情况说明:前端项目,技术框架是vue 2.x + element ui + highcharts,平台内容是基金股票相关(基金行情、基金产品详情、基金经理详情、尽调报告;股票行情;模拟组合,在售组合等)目前项目已经超过11万行代码,开发编译(本地)需要1min左右,生产编译(本地)平均需要17min左右。由于是docker容器化部署,每次上线都要跑流水线编译发布,线上编译的CPU可能不如本地,跑一次流水线的时间在60-90min不等,其中编译时间大多在40-60min,慢!!

    这周抽空研究一下如何提高编译速度。

    翻阅各类文章资料,看下来思路有三个:
    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/zhurong/p/12603887.html

    原本项目编译时间统计
    image.png
    分析发现各种loader以及uglifyJs占用时间不多,16min里面的大头应该是把文件编译成chunk.js的过程。
    加入dll之后 dll的编译时间在1min左右,项目打包时间变为了6min
    image.png
    DLL使用过程

    1、安装依赖项
    webpack
    clean-webpack-plugin (用于在构建之前清空构建文件夹)
    add-asset-html-webpack-plugin (自动插入dll.js的引用链接)

    2、在vue.config.js同级目录下新建webpack.dll.config.js文件
    image.png

    3、在webpack.dll.config.js中,引入依赖项,写配置(写需要抽离的第三方库,打包成单独的js文件,注意看entry里面的配置,这个写法会打包出4个dll.js文件)
    image.png

    4、在package.json写一个编译命令 “build:dll”: “webpack —config webpack.dll.config.js”
    image.png

    5、运行编译命令npm run build:dll,得到dll文件
    image.png
    展开/dll的目录,可以看到以vuebundle、vendor、ui、util开头的dll.js文件和以vuebundle、vendor、ui、util开头的manifest.json文件。

    6、改写vue.config.js,使得npm run build的时候不编译已经进入dll.js的第三方库文件,同时在编译的时候自动插入引用dll的标签。
    image.png
    dllNameArr数组里面的各项,要和webpack.dll.config.js里 entry的各项一一对应。

    另外chainWebpack中,要增加配置项,在生产环境编译的时候开启dllReference。
    image.png

    在第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/6844903913292824589
    这是个老式的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/happypack/wiki/Loader-Compatibility-List
    这里 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_34672907/article/details/112259788
    这个文章提到
    需要用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/1190000020672528
    由于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/1010000020615738
    回答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/zhurong/p/12603887.html
    量化、分析打包时间的插件SMP 区别vue cli2 vue cli 3

    2018-09-03《[Vue CLI 3] 配置解析之 parallel》
    https://segmentfault.com/a/1190000016247395
    (这一篇有很多同名文章,也有一篇全英的文章找不到发表日期
    https://titanwolf.org/Network/Articles/Article?AID=102babc1-c37c-420f-a0ab-c3f969405ab0
    不知道谁抄谁)
    通过测试得出结论:
    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/imanhodjaev/005d53bb19823525838588834d4196eb
    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_fin_dev/article/details/109935042