大家好,我是前端架构师,关注微信公众号【程序员大卫】免费领取精品资料。
1. 背景
最近在优化一个项目的加载性能时,对 optimization.splitChunks.chunks 的三个可选值 async、initial 和 all 的具体效果产生了疑惑。为了彻底搞清楚它们的区别,我专门搭建了一个 Demo 进行对比研究。
2. 核心区别:async vs initial
chunks 属性决定了 Webpack 对哪些类型的代码块进行分割。其中 async 是默认配置。
经过测试发现:在单入口应用中,二者区别不明显;但在多入口应用中,差异非常显著。
2.1 测试环境配置 (webpack.config.js)
为了直观观察分包结果,我将 minSize 设置为 0,确保即使是很小的模块也会被强制分割。
1const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 2 3module.exports = { 4 mode: "production", 5 entry: { 6 entry1: "./src/entry1.js", 7 entry2: "./src/entry2.js", 8 }, 9 optimization: { 10 splitChunks: { 11 chunks: "async", // 实验变量:此处分别修改为 'async', 'initial', 'all' 12 minSize: 0 // 强制分割小模块 13 }, 14 }, 15 plugins: [ 16 new CleanWebpackPlugin() // 每次构建前清理 dist 目录 17 ], 18}; 19
2.2 代码结构
假设我们有两个入口文件,它们都引用了同步模块 shared.js,且 entry1 额外引用了一个异步模块 dynamic.js。
- entry1.js: 引用
shared+ 动态引用dynamic - entry2.js: 引用
shared
1// entry1.js 2import "./shared"; // 同步公共模块 3import("./dynamic"); // 异步动态导入 4console.log("entry1"); 5 6// entry2.js 7import "./shared"; // 同步公共模块 8console.log("entry2"); 9
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 | 所有模块 | 希望最大化代码分割效果 | 最全面的策略,通常能获得最佳的缓存利用率 |
源码地址: github.com/zm8/wechat-…
《一文搞懂 Webpack 分包:async、initial 与 all 的区别【附源码】》 是转载文章,点击查看原文。
