移动spa商城优化记(二)--- 减少70%的打包等待时间
背景
开始
公司这个项目的起手模板是vue-cli的webpack模板,项目完成大概有将30个页面,未经优化前打包时间如图:

接下来开始优化,优化主要分四方面:减少打包文件数量,减少不必要的功能开销,优化打包方式,升级打包工具。
1.减少打包文件数量
指导思想:要打包的东西少了速度自然就快了。
1.dll
webpack.DllPlugin + webpack.DllReferencePlugin这组插件应该是借鉴了dll的思想所以叫dllplugin这个名字,目的就是将vue,vue-router,react,jquery等等这些体积较大,项目中不常更新的第三方包抽离出来单独打包,然后告诉webpack这些包我之前已经打包过了,你每次打包直接用就行了,不用每次再去重新打包一次了。
使用方法:
- build文件夹下新建一个webpack.dll.conf.js,内容可以这样写:
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry:{
//这地方写你想抽离的包,可以参考你的package.json文件下的dependencies
vue:['vue','vue-router']
},
output:{
//这地方写你打包后生成文件的路径
path:path.join(__dirname,"../src/dll"),
filename:'[name].dll.js',
library:'[name]'
},
plugins:[
//这个插件是重点,用于打包上面entry里配置的包
new webpack.DllPlugin({
path:path.join(__dirname,"../src/dll",'[name]-manifest.json'),
name:'[name]',
}),
new webpack.optimize.UglifyJsPlugin()
]
}
- 执行
webpack --config build/webpack.dll.conf.js
打包生成抽离的公共包。 此时src下应该能看到dll目录及生成的公共包js及json。 - 正常webpack配置文件里配置DllReferencePlugin进行关联
plugins: [
new webpack.DllReferencePlugin({
//这里写上一步打包出的json路径
manifest:require('../src/dll/vue-manifest.json')
})
......
]
现在,再次打包就可以了,你提取出的第三方包越多,打包速度优化的越明显。如果想让打包出的html可以自动引入第二步打包出的dll.js文件,可以使用add-asset-html-webpack-plugin或者自己修改HtmlWebpackPlugin的配置实现打包出的html内自动引入dll.js文件。
关于HtmlWebpackPlugin详细配置可以看这篇文章: html-webpack-plugin用法全解 关于add-asset-html-webpack-plugin详细配置可以看这篇文章: add-asset-html-webpack-plugin配置
另外使用cdn引入包然后加 externals配置的方式也可以,思路和dll一致,都是抽离第三方包,只打包业务代码,只不过这种方式第三方包直接引用cdn上的。
2.减少不必要的resolve
- 看下webpack的每个rule下面include里面是不是有多余的resolve,或者看看有没有把node_modules文件夹exclude掉。
- 用到babel-loader的地方,记得设置cacheDirectory,以利用bable的缓存。
- resolve里面的extensions可以删除不必要的后缀名自动补全,减少webpack的查询时间,比如
extensions: ['.js', '.vue', '.json','.scss','.css'],
写这么多自动补全写代码的时候是省了后缀名了,但是这需要webpack打包时去自动查询后缀增加了时间开销。 - import时多使用完整路径而不是目录名,如
import './components/scroll/index.js'
而不是import './components/scroll
,减少webpack的路径查询。
2.去除不必要的功能开销
指导思想:减少打包过程中要做的额外的工作
我们的目的就是优化打包速度,那么与这个无关的不必要的功能可以先暂停掉,用到时再开。
关掉source map。
sourcemap有以下几个配置值:
eval: 生成代码 每个模块都被eval执行,并且存在@sourceURL
cheap-eval-source-map: 转换代码(行内) 每个模块被eval执行,并且sourcemap作为eval的一个dataurl
cheap-module-eval-source-map: 原始代码(只有行内) 同样道理,但是更高的质量和更低的性能
eval-source-map: 原始代码 同样道理,但是最高的质量和最低的性能
cheap-source-map: 转换代码(行内) 生成的sourcemap没有列映射,从loaders生成的sourcemap没有被使用
cheap-module-source-map: 原始代码(只有行内) 与上面一样除了每行特点的从loader中进行映射
source-map: 原始代码 最好的sourcemap质量有完整的结果,但是会很慢
当我们不需要调试时,可以关掉sourcemap或降低sourcemap的级别来加快打包的速度。
3.优化打包方式:并行
指导思想:并行打包速度当然快。
1.UglifyJSPlugin并行
这个比较好配置,UglifyJSPlugin插件下加一个属性parallel设为true即可。
new UglifyJSPlugin({
parallel: true
......
})
还可以设置打包缓存,具体见下面的配置

2.Happypack
Happypack通过多进程模型,来加速代码构建。 比如说以前使用vue-loader处理vue文件,以前是串行处理,现在利用happypack可以并行使用vue-loader处理vue文件。
- 首先安装HappyPack
npm install --save-dev happypack
- 修改webpack.base.config.js
const HappyPack = require('happypack');
const vueLoaderConfig = require('./vue-loader.conf')
exports.module = {
rules: [
{
test: /\.vue$/,
//vue-loader替换为happypack/loader,如果遇到vue文件就用happypack,id指定为vue
loader: 'happypack/loader?id=vue'
},
{
test: /\.js$/,
//babel-loader替换为happypack/loader,如果遇到js文件就用happypack,id指定为js
loader: 'happypack/loader?id=js'
}
......
]
};
exports.plugins = [
new HappyPack({
id:'vue',
//同时开多少线程进行打包,也可以用ThreadPool控制
threads: 4,
loaders: [{
//这是真实的处理loader,具体配置和rules里原本的一致,options也照搬过来就行
loader:'vue-loader',
options:vueLoaderConfig
}]
}),
new HappyPack({
id: 'js',
threads: 3,
loaders: [{
loader:'bable-loader',
}]
})
......
];
经过以上配置,我们就可以使用happypack愉快的进行打包了。
更多高级配置可以看文档:Happypack文档
4.升级打包工具
指导思想:鸟枪换大炮,升级打包工具。
- 升级node
- 升级webpack webpack4比3快,3比2快,推荐webpack至少升到3以上,4还不太稳定,强行升级坑较多。
- 升级各种loader
很多时候,大神们在冥冥之中已经帮我们在底层做了优化,我们根本不需要做什么配置,我们只需要升级工具即可,当然,升级的同时要保证项目的健壮性。
最后
一图胜千言,这是经过优化后的打包时间:

打包时间从原来的的120s减少到了现在的34s,优化率70%以上。再也不用每次npm run 一下就先去上个厕所了。。。
转载自:https://juejin.cn/post/6844903586443296781