webpack4 之 cacheGroups 分包【究极奥义】

简介: 近来遇项目打包之事,撰文记之。以期分享,皆有所获。

image.png



近来遇项目打包之事,撰文记之。以期分享,皆有所获。


前提



前提有两点,需要得到你的认同:


  1. 【后台管理系统】框架和 UI 组件库最强组合为 vue-element-admin + Element UI!(●'◡'●)
  2. webpack4 最核心的特性是 【splitChunks】,splitChunks 最核心的配置是 cacheGroups!


基于这个两个前提,我们再进行下一步。


分析工具



webpack 打包分析有它就够了:webpack-bundle-analyzer


  • 安装
npm install --save-dev webpack-bundle-analyzer


  • 配置:因为 vue-element-admin 基于 vueCli4,所以在 vue.config.js chainWebpack 中设置
config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin).tap(() => [
      {
        rel: 'BundleAnalyzerPlugin',
        analyzerMode: 'server', // 'server': 启动端口服务;'static': 生成 report.html;'disabled': 配合 generateStatsFile 使用;
        generateStatsFile: false, // 是否生成stats.json文件
        analyzerHost: '127.0.0.1',
        analyzerPort: '8877',
        reportFilename: 'report.html',
        defaultSizes: 'parsed',
        openAnalyzer: false,
        statsFilename: 'stats.json',
        statsOptions: null,
        excludeAssets: null
      }
复制代码


其中 analyzerMode 的设置比较重要。

  • 运行:
npm run dev 或 npm run build


  • 访问:
http://127.0.0.1:8877


现状问题



看一下咱们的打包分析图:

image.png


得出如上图的分包并不难,vue-element-admin 自带这些配置。


config.optimization.splitChunks({
        chunks: 'all',
        cacheGroups: {
          libs: {
            name: 'chunk-libs',
            test: /[\\/]node_modules[\\/]/,
            priority: 10,
            chunks: 'initial' // only package third parties that are initially dependent
          },
          elementUI: {
            name: 'chunk-elementUI', // split elementUI into a single package
            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
            test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
          },
          commons: {
            name: 'chunk-commons',
            test: resolve('src/components'), // can customize your rules
            minChunks: 3, //  minimum common number
            priority: 5,
            reuseExistingChunk: true
          }
        }
      })


如果你暂时还看不懂这些配置项,先别急,后面会一一陈述。

你只用先知道:它拆了初始化加载的第三方包、拆了 Element UI 库、拆了 src/components。


一切似乎好像还不错,但是我们并不满足。

实际上,咱们跑一下 npm run build:test 也会报警告。


image.png


那么还有哪些点可以继续优化?结合以上分析图和 test warning,很明显,我们需要思考:

  1. Echarts 的体积大小不能忽视,如何处理它?是首页加载还是异步加载?要按需引入吗?
  2. vue.js 等库还能不能再拆?
  3. 首页 Entrypoints 所依赖的包还能不能再优化?
  4. 包的体积应控制在什么范围?包太大,加载会太慢!包太小,会消耗 HTTP 请求连接!更多:合并 HTTP 请求是否真的有意义?
  5. 更多......


淦!打包什么的,多打几遍就完事了。十遍不行就一百遍,一百遍不行就一千遍,一千遍不行就......


优化的结果



淦完后得出如下打包分析图:

本瓜成功的将打包大小从 3.1MB 变成了 2.36MB,文件数从 68个 打包到了 43个!!!,既实现了拆包(拆公共库),也实现了并包(合并极小的包)。

虽然这不会是最终的结果,但本瓜可以先下一个结论:


配置 cacheGroups,权衡拆包与并包二者,便是 webpack 分包的究极奥义!

image.png


以下是 cacheGroups 配置:


config.optimization.splitChunks({
        chunks: 'all',
         cacheGroups: {
            vue: {
              name: 'chunk-vuejs',
              test: /[\\/]node_modules[\\/]_?vue(.*)/,
              priority: 20
            },
            elementUI: {
              name: 'chunk-elementUI', // split elementUI into a single package
              priority: 30, // the weight needs to be larger than libs and app or it will be packaged into libs or app
              test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
            },
            commons: { // split async commons chunk
              name: 'chunk-async-commons',
              minChunks: 2,
              priority: 40,
              chunks: 'async'
            },
            echarts: { // split echarts libs
              name: 'chunk-echarts',
              test: /[\\/]node_modules[\\/]_?echarts(.*)/,
              priority: 50,
              chunks: 'async'
            },
            zrender: { // split zrender libs
              name: 'chunk-zrender',
              test: /[\\/]node_modules[\\/]_?zrender(.*)/,
              priority: 55,
              chunks: 'async'
            },
            'manage-sendMsg': { // resolve src
              name: 'chunk-manage-sendMsg',
              test: resolve('src/views/manage/sendMsg'),
              priority: 80,
              chunks: 'async'
            },
            'manage-packageLink': { // resolve src
              name: 'chunk-manage-packageLink',
              test: resolve('src/views/manage/packageLink'),
              priority: 80,
              chunks: 'async'
            },
            ......
      })


其实咱单独从配置上去做优化,可操作的空间并不大。我们还应该从打包分析结果去回看我们的代码细节,调整业务代码来优化打包结果,或许是最直接有效的优化思路之一。包括:如何整合或解耦业务?如何做组件化?组件怎么引?插件怎么引?引多少?......每个点都能再操作操作!


  • 尤其注意
CommonJs(require) ES6(import)
输出的是一个值的拷贝 输出的是值的引用
运行时加载 编译时输出接口

cacheGroups



下面我们再具体看看 cacheGroups 最关键的配置:


【重要】

  • name chunk 的文件名
  • test 过滤 modules,默认为所有的 modules,可匹配模块路径或 chunk 名字,当匹配到某个 chunk 的名字时,这个 chunk 里面引入的所有 module 都会选中;
  • priority 权重,数字越大表示优先级越高。一个 module 可能会满足多个 cacheGroups 的正则匹配,到底将哪个缓存组应用于这个 module,取决于优先级;
  • chunks(非常非常非常重要) 有三个值:all、async、initial。


这里是一段示例代码,来看看设置不同的 chunks,它们有什么样的打包区别:

//app.js
import "my-statis-module";
if(some_condition_is_true){
  import ("my-dynamic-module")
}
console.log("My app is running")


asyn : (default)

会生成两个打包文件:

  1. bundle.js (包含 app.js + my-statis-module)
  2. chunk.js (只包含 my-dynamic-module)


initial :

会生成三个打包文件:

  1. app.js (只包含 app.js)
  2. bundle.js (只包含 my-static-module)
  3. chunk.js (只包含 my-dynamic-module)

all :

会生成两个打包文件:

  1. app.js (只包含 app.js)
  2. bundle.js (包含 my-static-module + my-dynamic-module)


设置 "all" 大小将最小,区别使用这三者,是核心中的核心。


【了解】

  • minSize 表示被拆分出的 bundle 在拆分之前的体积的最小数值,只有 >= minSize 的 bundle 会被拆分出来;
  • maxSize


表示被拆分出的 bundle 在拆分之前的体积的最大数值,默认值为 0,表示 bundle 在拆分前的体积没有上限;maxSize 如果为非 0 值时,不能小于 minSize;


  • minChunks 表示在分割前,可被多少个chunk分享的最小值
  • reuseExistingChunk 表示是否使用已有的 chunk,true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的,即几个 chunk 复用被拆分出去的一个 module;


意外收获



代码层面:这样写,user.png 会被单独打成一个包。打包出来 148B ,属实没必要!

<img v-show="imageUrl" :src="imageUrl" class="sort-img">
<img v-show="!imageUrl" src="~@/assets/user.png" class="sort-img">

image.pngimage.png


如果改成这样,则不会再被单独打包了。

<img :src="imageUrl?imageUrl:'~@/assets/user.png'" class="sort-img">
复制代码


回看其它代码,本瓜发现所有在条件判断里面引入的文件都会被单独打包。然而它们其中有些是可以调整写法的,真没必要将几 KB 的文件单独打包成一个几 B 的包文件。

从打包的结果去检验代码,也是一种不错的优化手段!


策略小结



基于本次分包,本瓜简单梳理一下策略:


  1. 公共的库是一定要尽量拆的。
  2. 公共的库尽量做到按需加载,这也是优化首屏加载需要注意的。
  3. 分包不能太细,0KB 至 10 KB 的包是极小的包,应当考虑合并。10 KB 至 100 KB 的包是小包,比较合适;100 KB 至 200 KB 的包只能是比较核心重要的包,需要重点关注,大于 200KB 的包就需要考虑拆包了。当然,也不排除一些特殊情况。


包大小 策略
0 KB 至 10 KB 合并包
10 KB 至 100 KB 大小合适
100 KB 至 200 KB 核心包,重点关注
大于 200 KB 考虑拆包
特殊情况 特殊处理


本次就先到这,打包无止境,愿这个世上没有打包攻城狮。


关注公众号【掘金安东尼】,你的三连,我的动力!!!

image.png


相关文章
|
前端开发 JavaScript CDN
webpack优化篇(四十五):进一步分包:预编译资源模块
webpack优化篇(四十五):进一步分包:预编译资源模块
194 0
webpack优化篇(四十五):进一步分包:预编译资源模块
|
5月前
|
JavaScript 前端开发
webpack成长指北第9章---webpack如何对icon字体进行打包
webpack成长指北第9章---webpack如何对icon字体进行打包
107 1
|
5月前
|
前端开发 JavaScript
webpack成长指北第7章---webpack的css\less\scss样式打包
webpack成长指北第7章---webpack的css\less\scss样式打包
85 0
|
5月前
|
前端开发 JavaScript
webpack成长指北第8章---webpack的CSS Modules打包
webpack成长指北第8章---webpack的CSS Modules打包
55 0
|
23天前
|
JavaScript
webpack打包TS
webpack打包TS
|
7天前
|
JavaScript 测试技术 Windows
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
本文介绍了如何使用vue-cli和webpack为Vue项目配置不同的生产和测试环境,包括修改`package.json`脚本、使用`cross-env`处理环境变量、创建不同环境的`.env`文件,并在`webpack.prod.conf.js`中使用`DefinePlugin`来应用这些环境变量。
23 2
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
|
8天前
|
缓存
webpack 打包多页面应用
webpack 打包多页面应用
|
20天前
webpack 打包多页面应用
webpack 打包多页面应用
|
1月前
|
前端开发 开发者
在前端开发中,webpack 作为一个强大的模块打包工具,为我们提供了丰富的功能和扩展性
【9月更文挑战第1天】在前端开发中,Webpack 作为强大的模块打包工具,提供了丰富的功能和扩展性。本文重点介绍 DefinePlugin 插件,详细探讨其原理、功能及实际应用。DefinePlugin 可在编译过程中动态定义全局变量,适用于环境变量配置、动态加载资源、接口地址配置等场景,有助于提升代码质量和开发效率。通过具体配置示例和注意事项,帮助开发者更好地利用此插件优化项目。
65 13
|
6天前
|
JavaScript 前端开发
手写一个简易bundler打包工具带你了解Webpack原理
该文章通过手写一个简易的打包工具bundler,帮助读者理解Webpack的工作原理,包括模块解析、依赖关系构建、转换源代码以及生成最终输出文件的整个流程。
下一篇
无影云桌面