Webpack 是一個前端資源加載/打包工具。它將根據模塊的依賴關係進行靜態分析,而後將這些模塊按照指定的規則生成對應的靜態資源。javascript
它的異步加載原理是,事先將編譯好後的靜態文件,經過js對象映射,硬編碼進打包後的 manifest.xxxx.js 文件中,而後經過JSONP原理按需加載每一個chunk。php
每一個子模塊加載完畢以後,瀏覽器將會進行本地緩存,從而節省了網絡帶寬。css
Webpack編譯後的目錄結構以下:html
從結構目錄來看,整個項目的入口就是index.html,咱們來看看index.html的內容:前端
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <title>www.phpdragon.com</title> <script></script> <link href=/static/css/app.4a4f13cfbe19aa22b83c451c96f49338.css rel=stylesheet> </head> <body> <div id=app> <transition :name=transitionName> <router-view></router-view> </transition> </div> <script type=text/javascript src=/static/js/manifest.f726e03ee32bcdee633a.js></script> <script type=text/javascript src=/static/js/vendor.fa5ac3dc9fb740bb48c5.js></script> <script type=text/javascript src=/static/js/app.af822fb16a16ef70005b.js></script> </body> </html>
其中引入了3個js文件,和一個css樣式文件。vue
咱們看看manifest.f726e03ee32bcdee633a.js這個js加載器。java
找到這段代碼:webpack
是否是發現很熟悉!這一段jsonp代碼,這就是用來實現按需加載js資源文件的加載器。ios
講到了這,從上述代碼就引出了一個問題:git
當前端腳本從新編譯了之後,項目發佈採用的是刪除重置發佈,因爲靜態文件只加載一次的緣故,會致使按需加載模塊時報錯:Loading chunk " + e + " failed.
緣由是瀏覽器已經緩存了manifest.f726e03ee32bcdee633a.js這個加載器,而後訪問新的導航欄的時候,服務器端已經不存在舊版本的JS靜態資源文件了,從而致使系統異常。
解決方法:
方案一:每次都加載項目入口文件 index.html。也就是說服務器端設置index.html文件不緩存、或者經過URL後綴添加隨機字符串來解決。
這個方案適合入口URL可變動的系統。但對於ERP這種內部系統來講,可行性不是很好。
因爲入口只加載一次,致使點擊系統的其餘導航欄URL操做,沒法作到再次加載index.html文件,刷新瀏覽器緩存的JS。
第一種方案能夠放棄了!
方案二:給每一個導航欄路由URL添加隨機數。
這個也不行,並不會致使index.html被從新加載。具體緣由,請詳看源碼解析:vue-router源碼分析-總體流程
方案三: 系統內部經過ajax請求獲取版本信息從而提示更新。
這個可行,但對後端系統有侵入性,須要後端同窗配合。對與跨工種跨部門來講,這種方式屬於下策。
方案四:
方案二提到了路由,那麼vue的路由是否提供了鉤子機制,從而進行攔截呢?
官方是提供的,詳看官方文檔:vue導航鉤子。
經過以下這段代碼,咱們就能實現咱們想要的功能了。1、確保了檢測的頻率。同時也對系統內部的AJAX請求減小侵入性代碼。
router.beforeEach((to, from, next) => { // ... })
1.最終解決以下:在 main.js 中添加以下代碼:
router.beforeEach((to, from, next) => { axios.get('../static/version.json?_=' + Math.random()).then(response => { if (200 == response.status) { if (process.env.VERSION !== response.data.version) { var message = "系統版本有更新,點擊確認加載最新,或按【CTRL + F5】!" Vue.prototype.$alert(message, '系統提示', { confirmButtonText: '肯定', callback: function(){ window.location.reload(true); } }); return; } next(); } }).catch(err => { console.error(err); next(); }); });
2.添加版本變量:
3.給編譯環境添加env變量:
4.經過Webpack的編譯插件機制,引入 diy-plugin.js 自定義插件腳本,生成版本信息:
'use strict'; var FStream = require('fs'); var Archiver = require('archiver'); //npm install archiver /** * 版本信息生成插件 * @author phpdragon@qq.com * @param options * @constructor */ function DiyPlugin(options) { this.options = options || {}; this.options.outZipFile = this.options.path + '/front.zip'; !this.options.versionDirectory && (this.options.versionDirectory = 'static'); } //apply方法是必需要有的,由於當咱們使用一個插件時(new somePlugins({})),webpack會去尋找插件的apply方法並執行 DiyPlugin.prototype.apply = function (compiler) { var self = this; compiler.plugin("compile", function (params) { var dir_path = this.options.context + '/' + self.options.versionDirectory; var version_file = dir_path + '/version.json'; var content = '{"version":' + self.options.env.VERSION + '}'; FStream.exists(dir_path, function (exist) { if (exist) { writeVersion(self, version_file, content); return; } FStream.mkdir(dir_path, function (err) { if (err) throw err; console.log('\n建立目錄[' + dir_path + ']成功'); writeVersion(self, version_file, content); }); }); }); //編譯器'對'全部任務已經完成'這個事件的監聽 compiler.plugin("done", function (stats) { console.log("開始打包壓縮編譯文件..."); var output = FStream.createWriteStream(self.options.outZipFile); var archiveZip = Archiver('zip', {zlib: {level: 9}}); archiveZip.on('error', function (err) { throw err; }); archiveZip.pipe(output); archiveZip.directory(self.options.path + '/' + self.options.versionDirectory, self.options.versionDirectory); archiveZip.file(self.options.path + '/index.html', {name: 'index.html'}); //archive.glob(self.options.path + '/*.*'); archiveZip.finalize(); }); }; const writeVersion = (self, versionFile, content) => { console.log("\n當前版本號:" + self.options.env.VERSION); console.log("開始寫入版本信息..."); //寫入文件 FStream.writeFile(versionFile, content, function (err) { if (err) throw err; console.log("版本信息寫入成功!"); }); //刪除以前的壓縮包 FStream.exists(self.options.outZipFile, function (exists) { if (exists) { FStream.unlinkSync(self.options.outZipFile); } }); } module.exports = DiyPlugin;
5.在webpack配置文件中添加 diy-plugin.js 編譯鉤子:
6. ok,至此結束。 執行編譯:
npm run build
7. 訪問項目,再次編譯版本,打開以前的項目界面,點擊其餘導航菜單,效果以下:
以上,平常的一些開發點滴。
PS: