普通视图

发现新文章,点击刷新页面。
今天 — 2025年11月28日首页

一文搞懂 Webpack 分包:async、initial 与 all 的区别【附源码】

2025年11月28日 22:09

大家好,我是前端架构师,关注微信公众号【程序员大卫】免费领取精品资料。

1. 背景

最近在优化一个项目的加载性能时,对 optimization.splitChunks.chunks 的三个可选值 asyncinitialall 的具体效果产生了疑惑。为了彻底搞清楚它们的区别,我专门搭建了一个 Demo 进行对比研究。

2. 核心区别:async vs initial

chunks 属性决定了 Webpack 对哪些类型的代码块进行分割。其中 async 是默认配置。

经过测试发现:在单入口应用中,二者区别不明显;但在多入口应用中,差异非常显著。

2.1 测试环境配置 (webpack.config.js)

为了直观观察分包结果,我将 minSize 设置为 0,确保即使是很小的模块也会被强制分割。

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
// 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 所有模块 希望最大化代码分割效果 最全面的策略,通常能获得最佳的缓存利用率

源码地址: github.com/zm8/wechat-…

❌
❌