likes
comments
collection
share

Webpack 实践 - optimization.splitChunks

作者站长头像
站长
· 阅读数 12

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 3 天,点击查看活动详情

默认值

默认情况下,SplitChunksPlugin 只会影响到按需加载的 chunks

webpack 将根据以下条件自动拆分 chunks

  • 新的 chunk 可以被共享,或者模块来自于 node_modules 文件夹
  • 新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积)
  • 当按需加载 chunks 时,并行请求的最大数量小于或等于 30
  • 当加载初始化页面时,并发请求的最大数量小于或等于 30
module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000, // 分割代码应满足的最小体积
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
      maxInitialRequests: 30, // 入口点的最大并行请求数
      enforceSizeThreshold: 50000, // 设置强制执行拆分的体积阈值为 50000B,同时会忽略其他限制(minRemainingSize,maxAsyncRequests,maxInitialRequests)
      cacheGroups: {
        defaultVendors: {
          test: /[\/]node_modules[\/]/,
          priority: -10, // 拆分的权重
          reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

optimization.splitChunks

实践

实践过程中的拆包原则:

  • 将变动的与不易变动的资源进行分离 ---> 有效利用缓存;
    • 将 node_modules 中的资源拆分出来,如果 node_modules 中的资源不变,就可以有效利用缓存,避免受到业务代码频繁改动的影响;
  • 将大的拆分成若干个小的 chunk ---> 缩短单个资源下载时间;
  • 将公共模块抽离出来 ---> 避免资源被重复打包,这样也可以在一定程度上减小打包产物总体积;
    • 将被多个 chunk 引用的包拆分成单独的模块;

这里给出实践的 optimization.splitChunks 配置:

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          name: 'chunk-vendors',
          test: /[\\/]node_modules[\\/]/,
          priority: 10,
          chunks: 'initial'
        },
        echarts: {
          name: 'chunk-echarts',
          priority: 20,
          test: /[\\/]node_modules[\\/]_?echarts|zrender(.*)/
        },
        commons: {
          name: 'chunk-commons',
          minChunks: 3, // minimum common number
          priority: 5,
          reuseExistingChunk: true
        },
        lib: {
          test(module) {
            return (
              module.size() > 160000 &&
              /node_modules[/\\]/.test(module.nameForCondition() || '')
            )
          },
          name(module) {
            const packageNameArr = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/);
            const packageName = packageNameArr ? packageNameArr[1] : '';
            // npm package names are URL-safe, but some servers don't like @ symbols
            return `chunk-lib.${packageName.replace("@", "")}`;
          },
          priority: 15,
          minChunks: 1,
          reuseExistingChunk: true,
        },
      }
    },
  }
}

配置说明:

  • 先把大体积包拆分出来
    • 先大体积包 echarts 拆分出来;
    • 再把 node_modules 中体积大于 160000B 的依赖包拆出来(这里参考 next.js,将阈值设置为 160000B);
  • 再考虑将 node_modules 中的剩余项打成一个 chunk;
  • 将被引用次数大于等于 3 次的公共模块拆分出来;

注意优先级的配置

配置建议

  1. 可以先借助 webpack-bundle-analyzer 插件分析各模块的大小;
  2. 定位重复的模块;
  3. 参考优秀的开源项目;
    • next.js

补充:个人觉得 optimization.splitChunks 没有绝对的最佳配置,只有最佳实践,要根据项目情况灵活配置~

参考