[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)

情况说明:前端项目,技术框架是vue 2.x + element ui + highcharts,平台内容是基金股票相关(基金行情、基金产品详情、基金经理详情、尽调报告;股票行情;模拟组合,在售组合等)目前项目已经超过11万行代码,开发编译(本地)需要1min左右,生产编译(本地)平均需要17min左右。由于是docker容器化部署,每次上线都要跑流水线编译发布,线上编译的CPU可能不如本地,跑一次流水线的时间在60-90min不等,其中编译时间大多在40-60min,慢!!
这周抽空研究一下如何提高编译速度。
(同步更新到自己的语雀,文章、代码的样式更好看点
可以移步https://www.yuque.com/diracke...)
翻阅各类文章资料,看下来思路有三个:
1、loader多进程 2、压缩工具多进程 3、dllPlugin
在这里先说各条思路实践下来的结论
1、loader多进程 --失败,做无用功
(被讲的最多的是利用happypack开启多进程Loader转换,主要用来提升babel的速度)
vue/cli3 中 自带了 thread-loader ( == happypack ) 用于多进程处理,仅在生产环境开放。
2、使用webpack-parallel-uglify-plugin增强代码压缩 (uglify 多进程) --uglifyJs自带多进程,我都不知道这个webpack-parallel-uglify-plugin的作者在干啥,再加上提升有限,没探索
“自带的js压缩插件是单线程的,而该插件会开启多个子进程,将压缩工作分给多个子进程去完成,每个子进程还是通过uglifyjs去压缩代码,无非就是并行处理压缩,效率更高。”
上面这段话,我见了非常多,但调研发现,webpack官方的uglifyjs自身有多进程选项,且uglify在我的编译16min中仅占一分钟,所以没有往下走,这条思路是否正确意义不大,提升有限。
(调研时间2021年12月16日,npm上看,uglifyjs最后一个版本v2.2.0是两年前发布的,而webpack-parallel-uglify-plugin最后一个版本v2.0.0是一年前发布的)
3、dllPlugin 提取出我们常用的第三方模块,单独打成一个文件包,之后插入到我们的html页面中。这样我们以后每次打包,都不需要针对第三方模块进行处理,毕竟第三方模块动辄成千上万行。
第一次读到这句话的时候,我以为dll的编译会花很多时间,之后由于使用了dll的编译产物,所以每次编译的时候就节省了共用dll的编译时间。(首次完整编译的时候,分别编译出dll文件和项目文件。之后再编译的时候只需要编译项目文件,不需要编译dll文件,节省的是编译第三方库的时间,但是对docker这样的容器化部署,dll和cache都没有用,因为每次流水线都是重新编译的过程。因此还想到了走3的思路,把第三方库单独打包,且起一个服务,提供dll.js文件的思路)(同一份代码,两条流水线,两份编译产物)
实际上,dll文件的编译只需要1min左右,而插入dll之后,项目编译的时间变成了6min左右(也就是说整个编译时间变成了7min左右)。
dll的方式节省时间的原因是它减少了拆解第三方库再打包到各个chunk的时间。这是dll方式最大的意义所在。
通俗来讲,dll的方式就是在vue项目中,通过在App.vue中通过的方式引入打包的第三方库dll.js文件。



讲过程之前先说需要用到的量化、分析打包时间的工具
speed-measure-webpack-plugin (SMP)
这个包可以统计编译的总时间,以及测量各个插件和 loader 在编译过程中花费的时间。
安装过程参考这篇blog
《Vue-cli 中 Webpack 配置优化(一)》 注意区别vue cli2 vue cli 3
https://www.cnblogs.com/zhuro...
原本项目编译时间统计
[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)
文章图片

分析发现各种loader以及uglifyJs占用时间不多,16min里面的大头应该是把文件编译成chunk.js的过程。
加入dll之后 dll的编译时间在1min左右,项目打包时间变为了6min
[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)
文章图片

DLL使用过程
1、安装依赖项
webpack
clean-webpack-plugin (用于在构建之前清空构建文件夹)
add-asset-html-webpack-plugin (自动插入dll.js的引用链接)
2、在vue.config.js同级目录下新建webpack.dll.config.js文件
[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)
文章图片

3、在webpack.dll.config.js中,引入依赖项,写配置(写需要抽离的第三方库,打包成单独的js文件,注意看entry里面的配置,这个写法会打包出4个dll.js文件)
[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)
文章图片

4、在package.json写一个编译命令 "build:dll": "webpack --config webpack.dll.config.js"
[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)
文章图片

【[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)】5、运行编译命令npm run build:dll,得到dll文件
[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)
文章图片

展开/dll的目录,可以看到以vuebundle、vendor、ui、util开头的dll.js文件和以vuebundle、vendor、ui、util开头的manifest.json文件。
6、改写vue.config.js,使得npm run build的时候不编译已经进入dll.js的第三方库文件,同时在编译的时候自动插入引用dll的标签。
[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)
文章图片

dllNameArr数组里面的各项,要和webpack.dll.config.js里 entry的各项一一对应。
另外chainWebpack中,要增加配置项,在生产环境编译的时候开启dllReference。
[Vue] vue 2.x项目生产编译优化缩短编译时间 (基于vue/cli3 + webpack 4)
文章图片

在第6步的时候要注意,引用dll文件夹的路径是什么。
(如果报错,就要修改vue.config.js中publicPath,或者修改webpack.dll.config.js中output的path)
7、最后npm run build,大功告成。
容器化部署还需要去改流水线脚本,与本文无关,结束!
-- 附参考文章资料
2019年08月14日 21:19 《vue项目打包优化之happypack》
https://juejin.cn/post/684490...
这是个老式的webpack.base.conf.js配置方式
文章说HappyPack 对file-loader、url-loader 支持的不友好
文章说HappyPack 对less-loader、sass-loader、stylus-loader支持的不友好
2017-08-29 happypack compatibility list
https://github.com/amireh/hap...
这里 happypack 支持列表里 有sass-loader 和 css-loader 然而很不幸,vue-loader和sass-loader 以及 css-loader 不兼容
2021-01-06 16:47:12《利用webpack-chain配置happypack和DllReferencePlugin》
https://blog.csdn.net/qq_3467...
这个文章提到
需要用const hRule = config.module.rule('js')的方式显示定义,而不要直接链式调用。
const hRule = config.module.rule('js') 再进行过滤和匹配,如果直接在config.module.rule('js').test(/.js$/).include.add(resolve('src')) .end()是不对的,有可能是不报错又不生效的,有的是打包正式环境会报错。
2019-10-13 《基于vue-cli的webpack打包优化实践及探索》
https://segmentfault.com/a/11...
由于vue文件中会含有CSS,所以vue-loader会提取出其中的css,交给其他loader处理,vue-loader-plugin会通过在vue文件后面加上查询字符串来告诉其他loader,针对这个文件要做处理。意味着什么呢?我们的vue-loader在处理文件的时候,通知其他loader处理,但是此时的loader配置已经被我们改写成了happypack,而vue又与happypack不兼容,最终导致了报错。很遗憾的告诉大家,vue-cli接入happypack--失败。
2019-10-08 《vuecli3怎么使用happypack》
https://segmentfault.com/q/10...
回答1 从webpack4发表之后,happypack已经不维护了,退出历史舞台了,有新的thread-loader代替。另外,如果你只是单纯地想加快编译打包速度的话,不如上dllplugin,这个比thread-loader快。
回答2 vuecli3不需要使用happypack,vuecli3脚手架默认采用了thread-loader(与happypack作用相同)加快编译。(仅生产环境)
2020-03-31 《Vue-cli 中 Webpack 配置优化(一)》
https://www.cnblogs.com/zhuro...
量化、分析打包时间的插件SMP 区别vue cli2 vue cli 3
2018-09-03《[Vue CLI 3] 配置解析之 parallel》
https://segmentfault.com/a/11...
(这一篇有很多同名文章,也有一篇全英的文章找不到发表日期
https://titanwolf.org/Network...
不知道谁抄谁)
通过测试得出结论:
thread-loader的开启条件,开启后的作用和上文中的表述一样
(和下面这段代码的效果一样)
const useThreads = process.env.NODE_ENV === 'production' && options.parallel;
if (useThreads) {
jsRule
.use('thread-loader')
.loader('thread-loader')
}
但是我没有在vue项目 以及 @vue/cli中找到这段源码。
最类似的代码出自
https://gist.github.com/imanh...
vue-cli-apollo-webpack-config.js 这里的代码
如果有源码出处,请指教。
注: 不需要在vue.config.js中对 parallel进行手动配置
如果在某个项目里面看到 vue.config.js 配置了:
parallel: require('os').cpus().length > 1
删掉它。无用,多余。
2020-11-22 《初尝Vue3,通过DllPlugin 和 DllReferencePlugin优化打包》
https://blog.csdn.net/vipshop...

    推荐阅读