一. 改單dll為雙dll

因為上圖原因,使用CommonsChunkPlugin時,導致其打包出來的vendors.js內的模塊ID會因為其他文件引用模塊數量的變化而變化。
所以現利用DllPlugin打包原vendors.js打包的文件,命名依然為vendor,文件名:vendor.js。
二. 利用cache和多線程提高編譯速度:
| 時間(s) | 優化前 | 優化后 |
| webpack cach:true | 55 | 54 |
| babel-loader?cacheDirectory=true | 54 | 35 |
| webpack-parallel-uglify-plugin | 36.7 | 27.98 |
| happypack | 36 | 34.33 |
| uglifyjs-webpack-plugin | 39 | 21.20 |
三. 更換js壓縮插件為:uglifyjs-webpack-plugin
可以使用多線程加速,但有一個問題,目前使用版本是:1.1.8
此插件壓縮功能只支持如下配置:
output: { filename: 'js/[name].[chunkhash:8].js' } 或 output: { filename: 'js/[name].js' }
不支持:
output: { filename: 'js/[name].js?v=[chunkhash:8]' }
相關issue: https://github.com/webpack-contrib/uglifyjs-webpack-plugin/issues/220
基於以上原因,更改覆蓋式發布為非覆蓋式發布方式 js/[name].[chunkhash:8].js , 這時你可能會用到如下插件來動態插入css和js:
| 功能對比 | add-asset-html-webpack-plugin | html-webpack-include-assets-plugin | 備注 |
| hash | 根據具體文件內容計算哈希值 自動加在文件名后:xxx?as68d7 |
webpack編譯環境hash值,所有文件的hash值統一,且一旦編譯環境有改動,hash即變化 自動加在文件名后:xxx?as68d7 |
|
| 待插入文件 | filepath字段,支持glob | assets字段,支持glob | |
| 插入html的位置 | head或body最后,其他引用資源的前面,不可選擇位置 | 可選擇插入在其他引用資源的前面或后面 | 其他引用資源值htmlWebpackPlugin 插入的資源 |
| copy文件 | 會把filepath文件copy到publicPath下 | 不會copy文件 |
舉例如下:
new AddAssetHtmlPlugin([ { filepath: outDir + '/js/lib/dll.js', publicPath: outPublicDir + 'js/lib/', outputPath: './js/lib', hash: true, includeSourcemap: false }, { filepath: outDir + '/js/vendor.js', publicPath: outPublicDir + 'js/', outputPath: './js', hash: true, includeSourcemap: false }, { filepath: outDir + '/css/vendor.css', publicPath: outPublicDir + 'css/', outputPath: './css', hash: true, includeSourcemap: false, typeOfAsset:'css' } ])
new HtmlWebpackIncludeAssetsPlugin({ assets: [getLatestFile('js/lib/dll.js')], append: false }), new HtmlWebpackIncludeAssetsPlugin({ assets: [getLatestFile('js/vendor.js')], append: false }), new HtmlWebpackIncludeAssetsPlugin({ assets: [getLatestFile('css/vendor.css')], append: false })
對比后選擇:html-webpack-include-assets-plugin,動態順序插入dll.js, vendor.js, manifest.js和頁面功能js由htmlWebpackPlugin插入到最后。
再此基礎上,需要手動檢索最新的dll.xxx.js 和vendor.xxx.js文件:
getLatestFile('js/vendor.js')
function getLatestFile(path){
let new_path = path.replace(/\./g, '.**.');
let latest_file = '';
let latest_file_mtime = 0;
glob.sync(outDir + '/' + new_path).forEach(function(file){
let fileInfo = fs.statSync(file);
let file_mtime = +new Date(fileInfo.mtime);
latest_file = file_mtime > latest_file_mtime ? file : latest_file;
latest_file_mtime = file_mtime > latest_file_mtime ? file_mtime : latest_file_mtime;
})
return latest_file.replace(/^.*\/(js\/|css\/)/ig, "$1");
}
有個問題即,如果你是本地編譯后上傳發布編譯后的代碼,那么因為是非覆蓋式發布,manifest.js內的runtime一直變化導致所有引入manifest的html 都會變化。這個問題目前解決方案是把編譯部署這兩步移到服務器進行,我們只關注並提交源碼即可。比如可以利用gitlab+jenkins的方式。
附:nodejs一些常用方法簡介
glob:
基於javascript, 使用 minimatch 庫(各種正則)來進行匹配獲取文件路徑
var glob = require("glob") // options 是可選的 glob("**/*.js", options, function (er, files) { // files 是匹配到的文件的數組. // 如果 `nonull` 選項被設置為true, 而且沒有找到任何文件,那么files就是glob規則本身,而不是空數組 // er是當尋找的過程中遇的錯誤 })
glob.sync() 同步獲取
var files = glob.sync(pattern, [options])
fs:
Node.js內置的fs模塊就是文件系統模塊,負責讀寫文件。和所有其它JavaScript模塊不同的是,fs模塊同時提供了異步和同步的方法。
fs異步: 'use strict'; var fs = require('fs'); fs.readFile('sample.txt', 'utf-8', function (err, data) { if (err) { console.log(err); } else { console.log(data); } }); fs同步: try { var data = fs.readFileSync('sample.txt', 'utf-8'); console.log(data); } catch (err) { // 出錯了 }
path.resolve: 相對路徑轉絕對路徑
path.stat: 獲取文件屬性比如大小,時間等
附2:自己根據文件內容計算文件hash值方法:
const fs = require('fs');
const crypto = require('crypto');
function getFileHash(path){ let file = fs.readFileSync(path); let hash = crypto.createHash('md5'); hash.update(file); return hash.digest('hex'); }
