Webpack 优化分包之 name

Tue, Jan 21, 20

name 是包含 3 个变量的函数

虽然,name 的取值类型有truefalsestring,但最终都可以用 function 来替代。这个函数包含了 3 个变量,它们分别是:modulechunkscacheGroupKey。那么这个三个变量分别指的是什么意思呢?下面就一一详细加以分析。

module - 模块

module 是类型 Module 的实例。在进行优化分析的时候,webpack 要将它添加到符合纳入规则的缓存组(CacheGroup)中。module 上的一些属性(或方法)对我们定义的模块作出了描述,如 Module.identifier() 返回了 module 的唯一标识,一般是.js文件在磁盘中的绝对位置。

chunks - 一组代码块

这不是指全部的代码块,有两个范围限定:

  • 由 entry splitpoint 和 async splitpoint 拆分出来的
  • 依赖 module(就是函数 name 的第一个变量的值)

不考虑优化拆包,webpack 只在“入口分离点”与“异步依赖分离点”会分别产生代码块(称为:原始代码块,英文称为:Origin Chunk)。往昔的 CommonsChunkPlugin 插件和如今的 optimization.splitChunks 配置项都是对于这个基础来说的。

如果“异步依赖分离点”对应的代码块 A 是 B 的子代码块,且 A、B 均依赖 module,那么提供给函数 name 的 chunks 变量里只有 B。其中,A 是 B 的子代码块是指,B 中包含了 import(/* webpackChunkName: "A"*/ ...)

cacheGroupKey - 缓存组的键

也就是你在配置的时候,写下的那个 key,如以下配置的 common

{
  cacheGroups: {
    common: {
      // ...
    }
  }
}

意义为何

按说,将一个缓存组纳入的全部模块放到一个代码块里是没问题的,比如这样定义 name:

{
  name: "vendor" | () => "vendor"
}

第三个变量 cacheGroupKey 可以用于标识代码块。但是并不建议这样处理,原因就在于,这忽略了变量 chunks 的可能变化。什么意思呢?上述的做法仅仅考虑了 cacheGroupKey 的变化,它将所有符合缓存组规则的模块放到一个代码块中。

举个例子来说,模块 m1m2 均符合缓存组 CG007 的规则(minSize、maxSize、minChunks、chunks、maxAsyncRequests、maxInitialRequests、test、…);m1 来自原始代码块 OC1m2 来自原始代码块 OC2m1m2 合并为一个分离的代码块为 C1。这样的情况,当仅加载 OC1OC2 的时候,我们不加选择地将 m1m2 一并加载进来。显然,这是没有必要的。第二个变量 chunks 也就是用于处理这个问题。

一般我们会将 chunks 的名字部分连接起来,作为一个唯一标识。它标识的是,在此缓存组中,那些同时由这些原始代码块所依赖的模块的集合。

{
  name: (m, chunks, key) => {
    return `${key}_${chunks.map((item) => item.name).join('~')}`
  }
}

最后,要考虑 module 吗?一般是不必要的,那样的话就分得太细碎了,而网络请求数太多,对于只限 6 个并行 HTTP 会话的浏览器不是好事。

经典做法

It is recommended to set splitChunks.name to false for production builds so that it doesn’t change names unnecessarily.

这是官方的建议,这样大概不能对缓存组里的模块做分拣。或许,大多数情况是实用的。

而,name 的默认值是 truetrue 表示考虑了缓存组的键和原始代码块两大变量,所以你很多时候不需要配置 name


webpack 优化 分包