大家好,我是前端架构师 ,关注微信公众号【程序员大卫】免费领取精品资料。
1. 背景
最近在优化一个项目的加载性能时,对 optimization.splitChunks.chunks 的三个可选值 async、initial 和 all 的具体效果产生了疑惑。为了彻底搞清楚它们的区别,我专门搭建了一个 Demo 进行对比研究。
2. 核心区别:async vs initial
chunks 属性决定了 Webpack 对哪些类型的代码块进行分割。其中 async 是默认配置。
经过测试发现:在单入口应用中,二者区别不明显;但在多入口应用中,差异非常显著。
2.1 测试环境配置 (webpack.config.js)
为了直观观察分包结果,我将 minSize 设置为 0,确保即使是很小的模块也会被强制分割。
javascript
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "production",
entry: {
entry1: "./src/entry1.js",
entry2: "./src/entry2.js",
},
optimization: {
splitChunks: {
chunks: "async", // 实验变量:此处分别修改为 'async', 'initial', 'all'
minSize: 0 // 强制分割小模块
},
},
plugins: [
new CleanWebpackPlugin() // 每次构建前清理 dist 目录
],
};
2.2 代码结构
假设我们有两个入口文件,它们都引用了同步模块 shared.js,且 entry1 额外引用了一个异步模块 dynamic.js。
- entry1.js : 引用
shared+ 动态引用dynamic - entry2.js : 引用
shared
javascript
// entry1.js
import "./shared"; // 同步公共模块
import("./dynamic"); // 异步动态导入
console.log("entry1");
// entry2.js
import "./shared"; // 同步公共模块
console.log("entry2");
2.3 打包结果对比
在上述场景下,切换配置会产生完全不同的结果:
-
设置
chunks: 'async'(默认)- 结果 :
dynamic.js被单独打包,但shared.js没有被分离。 - 原因 :
async只关注异步加载(动态导入)的模块。尽管shared.js被多个入口引用,但因为它是同步导入的,所以被忽略,直接打入了各自的入口包中。
- 结果 :
-
设置
chunks: 'initial'- 结果 :
dynamic.js被单独打包,同时shared.js也可以被剥离出来成为独立文件。 - 原因 :
initial关注初始加载(同步导入)的模块。Webpack 发现shared.js在初始化时就被多个入口共享,因此将其分离。
- 结果 :
3. 关于 all
当设置为 all 时,Webpack 会采用一种混合策略:无论同步还是异步,只要满足分割条件(如大小、引用次数),都会进行代码分割。
这是目前最推荐的配置,因为它能最大限度地复用代码,减小包体积。
4. 总结
三种模式的核心差异对比:
| 模式 | 作用范围 | 适用场景 | 特点 |
|---|---|---|---|
| async (默认) | 仅异步模块 | 针对 import() 动态导入的模块 |
确保首屏加载的 bundle 纯净,不影响初始包大小 |
| initial | 仅同步模块 | 针对入口文件直接 import 的公共模块 |
优化多页应用的公共代码提取,减少重复打包 |
| all | 所有模块 | 希望最大化代码分割效果 | 最全面的策略,通常能获得最佳的缓存利用率 |