webpack 默认分包策略
主要是关于 SplitChunksPlugin 的分包策略,SplitChunksPlugin 通过 module 被引用频率、chunk 大小、包请求数
三个维度决定是否执行分包操作,这些决策都可以通过 optimization.splitChunks 配置项调整定制,基于这些维度可以实现单独打包某些特定路径的内容
SplitChunksPlugin 内置了 default 与 defaultVendors 两个配置组,提供一些开箱即用的特性:
- node_modules 资源会命中 defaultVendors 规则,并被单独打包
- 只有包体超过 20kb 的 Chunk 才会被单独打包
- 加载 Async Chunk 所需请求数不得超过 30
- 加载 Initial Chunk 所需请求数不得超过 30
知识点:Webpack 内部包含三种类型的 Chunk:
- Initial Chunk:基于 Entry 配置项生成的 Chunk
- Async Chunk:异步模块引用,如 import(xxx) 语句对应的异步 Chunk
- Runtime Chunk:只包含运行时代码的 Chunk
根据 Module 使用频率
SplitChunksPlugin 支持按 Module 被 Chunk 引用的次数决定是否进行分包,开发者可通过 optimization.splitChunks.minChunks 设定最小引用次数
注意,这里“被 Chunk 引用次数”并不直接等价于被 import 的次数,而是取决于上游调用者是否被视作 Initial Chunk 或 Async Chunk 处理
根据 请求数量分包
在满足 minChunks 基础上,还可以通过 maxInitialRequest/maxAsyncRequests 配置项限定分包数量,配置项语义:
- maxInitialRequest:用于设置 Initial Chunk 最大并行请求数
- maxAsyncRequests:用于设置 Async Chunk 最大并行请求数
这里所说的“请求数”,是指加载一个 Chunk 时所需同步加载的分包数。 例如对于一个 Chunk A,如果根据分包规则(如模块引用次数、第三方包)分离出了 i 个子 Chunk, 那么请求 A 时,浏览器需要同时请求所有的子 Chunk,此时并行请求数等于 ¡ 个分包加 A 主包,即 ¡+1
并行请求数关键逻辑总结如下:
- Initial Chunk 本身算一个请求
- Async Chunk 不算并行请求
- 通过 runtimeChunk 拆分出的 runtime 不算并行请求
- 如果同时有两个 Chunk 满足拆分规则,但是 maxInitialRequests(或 maxAsyncRequest) 的值只能允许再拆分一个模块,那么体积更大的模块会被优先拆解
根据 体积分包
在满足 minChunks 与 maxInitialRequests 的基础上,SplitChunksPlugin 还会进一步判断 Chunk 包大小决定是否分包
minSize
:超过这个尺寸的 Chunk 才会正式被分包maxSize
:超过这个尺寸的 Chunk 会尝试继续做分包maxAsyncSize
:与 maxSize 功能类似,但只对异步引入的模块生效maxInitialSize
:与 maxSize 类似,但只对 entry 配置的入口模块生效enforceSizeThreshold
:超过这个尺寸的 Chunk 会被强制分包,忽略上述其它 size 限制
使用 cacheGroups
plitChunksPlugin 提供了 cacheGroups 配置项用于为不同文件组设置不同的规则
test
:接受正则表达式、函数及字符串,所有符合 test 判断的 Module 或 Chunk 都会被分到该组type
:接受正则表达式、函数及字符串,与 test 类似均用于筛选分组命中的模块,区别是它判断的依据是文件类型而不是文件名,例如 type = 'json' 会命中所有 JSON 文件idHint
:字符串型,用于设置 Chunk ID,它还会被追加到最终产物文件名中,例如 idHint = 'vendors' 时,输出产物文件名形如 vendors-xxx-xxx.jspriority
:数字型,用于设置该分组的优先级,若模块命中多个缓存组,则优先被分到 priority 更大的组
// 通过 cacheGroups 属性设置 vendors 缓存组,
// 所有命中 vendors.test 规则的模块都会被视作 vendors 分组,
// 优先应用该组下的 minChunks、minSize 等分包配置
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
minChunks: 1,
minSize: 0,
},
},
},
},
};