探秘 Webpack splitChunks:把代码切成小块的艺术

43 阅读4分钟

当你打开一个网站,结果首页白屏好几秒,开发者工具一看:
一个 5MB 的 bundle.js 正在慢吞吞下载

这时候,你可能会想:

“前端同学是不是把整个世界都打包进来了?”

别急,其实 Webpack 给我们准备了一把“解剖刀”—— splitChunks,它能把臃肿的 bundle.js 切成小块,让用户更快加载页面。


一、为什么需要 splitChunks?

如果你写过 React/Vue 项目,可能遇到这种情况:

  • 引入了 lodash,结果只用到一个函数;
  • 用了 UI 库(antd、element),结果只需要几个组件;
  • 多个页面用到了相同的库,但却在每个 bundle 里重复打包。

这些问题的最终表现就是:
👉 bundle 体积爆炸,加载速度直线下降。

splitChunks 就像一个聪明的打包师傅:

  • 看看哪些代码可以“公用”;
  • 把大的依赖拆出去做“vendor”;
  • 给用户按需送上“套餐”,而不是强塞一个大锅饭。

二、splitChunks 是怎么切的?

在 Webpack 4+ 中,splitChunks 内置在 optimization.splitChunks 配置里。一个最经典的配置如下:

// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',          // 对同步(initial)+异步(async)代码都生效
      minSize: 20000,         // 模块超过 20KB 才会被提取
      minChunks: 1,           // 模块至少被引用 1 次才会提取
      cacheGroups: {
        vendors: {            // 针对第三方库
          test: /[\/]node_modules[\/]/, // 匹配 node_modules 下的模块
          name: 'vendors',     // 生成文件名
          priority: -10        // 优先级,高于 default
        },
        default: {            // 针对自定义模块
          minChunks: 2,       // 至少被两个不同模块引用才会提取
          priority: -20,      // 优先级低于 vendors
          reuseExistingChunk: true // 如果已有 chunk 满足条件,就复用
        }
      }
    }
  }
}

参数详解

参数含义小贴士
chunks'all''async''initial''all' 最常用,能覆盖同步+异步模块。
minSize提取的最小字节数太小的模块不单独生成 chunk,避免文件太碎。
minChunks模块被引用次数default cacheGroup 很关键,保证重复使用的模块才提取。
cacheGroups缓存组配置可自定义 vendor/common/chunk 的策略。
priority优先级如果模块同时符合多个 cacheGroup,优先级高的会先抽离。
reuseExistingChunk是否复用已有 chunk避免重复生成相同模块 chunk,提高缓存利用率。

vendors 与 default

  • vendors

    • 针对第三方库(如 reactlodashantd
    • 优先级高于 default
    • 生成的文件通常命名为 vendors.jsvendors.[contenthash].js
  • default

    • 针对项目内部模块
    • minChunks: 2 保证至少被两个页面或模块引用
    • reuseExistingChunk: true 避免重复生成相同模块 chunk,提高缓存效率

🔹 总结:vendors 优先抽离第三方库,default 用于复用内部重复代码。


三、用个例子说明

假设我们有两个页面:pageApageB

// pageA.js
import _ from 'lodash';
import { Button } from 'antd';

// pageB.js
import _ from 'lodash';
import { Table } from 'antd';

如果不做优化,最后可能会打出两个大文件:

  • pageA.bundle.js (包含 lodash + antd + 业务代码)
  • pageB.bundle.js (又包含 lodash + antd + 业务代码)

开启 splitChunks 后:

  • lodash 和 antd 会被抽到 vendors.js
  • pageA.bundle.jspageB.bundle.js 只包含各自的业务逻辑
  • 浏览器会并行加载 vendors.js + 页面文件,提升速度 🚀

注意:如果 lodash、antd 被多个页面引用,开启 splitChunks 后只打包一次,浏览器缓存一次就好,其他页面复用,不再重复下载。


四、真实项目中的实践技巧

  1. 按需切割 UI 库

    • 使用 babel-plugin-importunplugin-vue-components,避免整库打包
    • splitChunks 再来一刀,效果更佳
  2. 合理设置缓存组 (cacheGroups)

    • 常用工具库(lodash、dayjs)可以单独抽成 common.js,避免混在 vendors 里
  3. 利用浏览器缓存

    • vendors 和 common 模块通常不常改动,可以长期缓存
    • 业务代码变动时,用户只需要更新小文件,加载更快
  4. chunk 命名策略

    • 生产环境建议使用 [name].[contenthash].js 命名,配合缓存策略

五、形象比喻:自助餐 vs 大锅饭

  • 没用 splitChunks:所有菜(代码)都放到一口大锅里,顾客(用户)只能端走一大碗
  • 用了 splitChunks:自助餐,用户只拿自己需要的盘子(页面代码),公共的调料区(vendors)大家共用

这样既省钱(带宽),又高效(加载速度快)。


六、总结

splitChunks 的核心价值就是:
👉 让代码更合理地切割和复用,避免重复打包,提升加载速度

  • Tree-Shaking = “减肥” → 去掉没用的代码
  • splitChunks = “分餐制” → 把代码合理分配

两者配合,让前端项目既精简又高效。


你在项目里用过 splitChunks 吗?踩过哪些坑?欢迎在评论区分享!