{singhi}
🏷 tech
Webpack 优化分包之 name
🌙 💬 📅

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