使用 SplitChunks
Webpack 默认会将尽可能多的模块代码打包在一起,优点是能够减少最终页面的HTTP请求数,但是也有明显的缺点:
- 页面初始代码包过大,影响首屏渲染性能
- 无法有效应用浏览器缓存,特别对于 NPM 包这类变动较少的代码,业务代码哪怕改了一行都会导致 NPM 包缓存失效
为此,Webpack 提供了 SplitChunksPlugin
插件,专门用于根据产物包的体积、引用次数等做分包优化,规避上述问题,特别适合生产环境使用
深入理解 Chunk
Chunk 是 Webpack 内部一个非常重要的底层设计,用于组织、管理、优化最终产物,在构建流程进入生成(Seal)阶段后:
- Webpack 首先根据
entry
配置创建若干 Chunk 对象 - 遍历构建(Make)阶段找到的所有 Module 对象,同一 Entry 下的模块分配到 Entry 对应的 Chunk 中
- 遇到异步模块则创建新的 Chunk 对象,并将异步模块放入该 Chunk
- 分配完毕后,根据
SplitChunksPlugin
的启发式算法进一步对这些 Chunk 执行裁剪、拆分、合并、代码调优,最终调整成运行性能(可能)更优的形态 - 最后,将这些 Chunk 一个个输出成最终的产物(Asset)文件,编译工作到此结束
Chunk 在构建流程中起着承上启下的关键作用 —— 一方面作为 Module 容器,根据一系列默认 分包策略 决定哪些模块应该合并在一起打包;另一方面根据 splitChunks
设定的 策略 优化分包,决定最终输出多少产物文件
Chunk 分包结果的好坏直接影响了最终应用性能
Webpack 默认会将以下三种模块做分包处理:
- Initial Chunk:
entry
模块及相应子模块打包成 Initial Chunk - Async Chunk:通过
import('./xx')
等语句导入的异步模块及相应子模块组成的 Async Chunk - Runtime Chunk:运行时代码抽离成 Runtime Chunk,可通过
entry.runtime
配置项实现
SplitChunksPlugin
SplitChunksPlugin
是 Webpack 4 之后内置实现的最新分包方案,与 Webpack3 时代的 CommonsChunkPlugin
相比,它能够基于一些更灵活、合理的启发式规则将 Module 编排进不同的 Chunk,最终构建出性能更佳,缓存更友好的应用产物
SplitChunksPlugin
的主要能力有:
SplitChunksPlugin
支持根据 Module 路径、Module 被引用次数、Chunk 大小、Chunk 请求数等决定是否对 Chunk 做进一步拆解,这些决策都可以通过optimization.splitChunks
相应配置项调整定制,基于这些能力我们可以实现:- 单独打包某些特定路径的内容,例如
node_modules
打包为vendors
- 单独打包使用频率较高的文件
- 单独打包某些特定路径的内容,例如
SplitChunksPlugin
还提供了optimization.splitChunks.cacheGroup
概念,用于对不同特点的资源做分组处理,并为这些分组设置更有针对性的分包规则SplitChunksPlugin
还内置了default
与defaultVendors
两个cacheGroup
,提供一些开箱即用的分包特性:node_modules
资源会命中defaultVendors
规则,并被单独打包- 只有包体超过 20kb 的 Chunk 才会被单独打包
- 加载 Async Chunk 所需请求数不得超过 30
- 加载 Initial Chunk 所需请求数不得超过 30
这里所说的请求数不能等价对标到 http 资源请求数
配置项与最佳实践
配置项
minChunks
:用于设置引用阈值,被引用次数超过该阈值的 Module 才会进行分包处理maxInitialRequest/maxAsyncRequests
:用于限制 Initial Chunk(或 Async Chunk) 最大并行请求数,本质上是在限制最终产生的分包数量minSize
: 超过这个尺寸的 Chunk 才会正式被分包maxSize
: 超过这个尺寸的 Chunk 会尝试继续做分包maxAsyncSize
: 与 maxSize 功能类似,但只对异步引入的模块生效maxInitialSize
: 与 maxSize 类似,但只对 entry 配置的入口模块生效enforceSizeThreshold
: 超过这个尺寸的 Chunk 会被强制分包,忽略上述其它 size 限制cacheGroups
:用于设置缓存组规则,为不同类型的资源设置更有针对性的分包策略
最佳分包策略
- 针对
node_modules
资源- 可以将
node_modules
模块打包成单独文件(通过cacheGroups
实现),防止业务代码的变更影响 NPM 包缓存,同时建议通过maxSize
设定阈值,防止 vendor 包体过大 - 更激进的,如果生产环境已经部署 HTTP2/3 一类高性能网络协议,甚至可以考虑将每一个 NPM 包都打包成单独文件
- 可以将
- 针对业务代码
- 设置
common
分组,通过minChunks
配置项将使用率较高的资源合并为 Common 资源 - 首屏用不上的代码,尽量以异步方式引入
- 设置
optimization.runtimeChunk
为true
,将运行时代码拆分为独立资源
- 设置