一. 改单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'); }