Webpack 4 SplitChunksPlugin 配置详解与实战
本文详解 Webpack 4 中 SplitChunksPlugin 的配置与工作原理。涵盖默认分割条件、chunks 参数(initial/async/all)的区别,以及利用 cacheGroups 自定义缓存组、提取第三方库和禁用默认组的具体操作。通过实例演示如何优化打包体积与加载性能。
Webpack 4 代码分割概述
提及前端构建工具,Webpack 无疑是首选。尽管前端技术迭代迅速,Parcel 和 Rollup 等工具不断涌现,但各类构建工具在竞争中相互借鉴优势,共同推动了前端工程化的发展。
Webpack 4 引入了零配置特性,并对模块打包进行了优化。原有的 CommonsChunkPlugin 已被移除,转而采用 optimization.splitChunks 进行代码分割配置。
接下来将详细介绍 SplitChunks 的具体内容。
默认分割条件与行为
默认配置行为
在默认设置下,Webpack 会依据以下条件自动执行代码分割:
- 新生成的代码块被多个模块共享引用,或者这些模块源自 node_modules 目录。
- 新代码块的体积在压缩前大于 30KB(未进行 min 和 gzip 处理)。
- 对于按需加载的代码块,其并行请求的最大数量需小于或等于 5。
- 对于初始加载的代码块,其并行请求的最大数量需小于或等于 3。
默认情况下,代码分割仅作用于按需加载的模块。若对初始块也进行优化,会增加 HTML 中 script 标签的数量,从而提升请求数。
通过以下示例可帮助理解默认配置下的打包行为。
模块全部采用同步引入
// indexA.js
import React from 'react'
import ReactDOM from 'react-dom'
import _ from 'lodash'
console.log(_.join(['a', 'b'], '~'))
ReactDOM.render(
<div>SplitChunk</div>,
document.getElementById('root')
)

由于默认配置仅影响按需加载模块,因此所有同步引入的内容均被打包在一起。
包含动态导入的模块
此处使用符合 ECMAScript 提案的 import() 语法进行动态导入。
// indexA.js
import React from 'react'
import ReactDOM from 'react-dom'
import _ from 'lodash'
import(/* webpackChunkName: "async-jquery" */ 'jquery').then(component => {
console.log(component)
})
console.log(_.join(['a', 'b'], '~'))
ReactDOM.render(
<div>SplitChunk</div>,
document.getElementById('root')
)

当 jquery 采用动态导入时,打包结果中 jquery 会被单独打包成一个文件。
React 按需加载示例
同样地,我们尝试对 react 进行按需加载,利用 react-router 提供的方案实现。
AsyncModule 模块按照上述方案异步加载 Dashboard 组件。
import React from 'react'
import ReactDOM from 'react-dom'
import {BrowserRouter, Route} from 'react-router-dom'
import AsyncModule from './AsyncModule.jsx'
import _ from 'lodash'
import $ from 'jquery'
console.log(_.join(['a', 'b'], '~'))
ReactDOM.render(
<div>
<BrowserRouter>
<Route path='/' component={AsyncModule} />
</BrowserRouter>
</div>,
document.getElementById('root')
)

从打包结果可见,按需加载的模块被打包至 0.js 文件中。
了解了 Webpack 默认情况下的打包优化后,接下来探讨 splitChunks 的配置项。
SplitChunks 配置参数详解
配置参数说明
相关配置项如下:
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {}
}
}
}
- chunks:指定需要优化的代码块类型,可选值为 initial(初始块)、async(按需加载块)和 all(全部块),默认为 async。
- minSize:压缩前的最小模块体积阈值,默认为 30000 字节。
- minChunks:模块被引用的最小次数,默认为 1。
- maxAsyncRequests:按需加载时允许的最大并行请求数,默认为 5。
- maxInitialRequests:单个入口允许的最大并行请求数,默认为 3。
- automaticNameDelimiter:生成块名时使用的连接符。
- name:拆分后块的名称,默认由块名和 hash 值自动生成。
- cacheGroups:缓存组。除上述属性外,缓存组还包含 test、priority 和 reuseExistingChunk 属性。
- test:用于匹配哪些模块应被该缓存组处理。
- priority:缓存组打包的优先级顺序。
- reuseExistingChunk:若当前代码块已包含所需模块,则不生成新代码块。
上述为基本配置项,重点在于 chunks 和 cacheGroups 的配置。
chunks 参数:initial 与 all 的区别
chunks 参数详解
chunks 可选值为 initial、async 和 all。默认值为 async,前文已介绍其表现,此处分析其他两个值的效果。
当设置为 initial 或 all 时,所有来自 node_modules 的模块会被分配至名为 vendors 的缓存组;所有被引用至少两次的代码会被分配至 default 缓存组。
// indexA.js
import './Dashboard.jsx'
// indexB.js
import './Dashboard.jsx'
// Dashboard.jsx
import React from 'react'
// webpack.config.js
splitChunks: {
chunks: 'initial'
}

打包结果符合预期,生成了 vendors 和 default 两个代码块。
可通过配置 optimization.splitChunks.cacheGroups.default: false 来禁用 default 缓存组。
// webpack.config.js
splitChunks: {
chunks: 'initial',
cacheGroups: {
default: false
}
}

关于 all 和 initial 的区别,可参考文章《Webpack 4 — Mysterious SplitChunks Plugin》(需科学上网)。
文中指出,initial 模式会分别优化异步和非异步模块,而 all 模式则对两者同时进行优化。例如,若 moduleA 在 indexA 中异步引入,在 indexB 中同步引入,在 initial 模式下 moduleA 会出现在两个打包块中,而在 all 模式下仅出现一个。
cacheGroups 自定义缓存组
cacheGroups 缓存组配置
使用 cacheGroups 可自定义打包块的行为。
// indexA.js
import React from 'react'
import ReactDOM from 'react-dom'
import _ from 'lodash'
import $ from 'jquery'
// indexB.js
import React from 'react'
import ReactDOM from 'react-dom'
import('lodash')
import $ from 'jquery'
// webpack.config.js
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2
}
}
}
}

根据前文介绍的 Webpack 分割条件,部分公共模块被打包进 commons。自定义打包块的优先级默认为 0,因此公共模块会被打包进 commons,而非前文提到的默认打包块 vendors(其优先级为负值)。
为何 lodash 未被打包在一起?回顾 initial 和 all 的区别,接下来实验 all 的效果。
// indexA, indexB同上
// webpack.config.js
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
chunks: 'all',
minChunks: 2
}
}
}
}

结果符合预期,lodash 被成功打包在一起。
提取第三方库与 Runtime 配置
提取第三方库
最后回顾 CommonsChunkPlugin 常用的分离第三方库功能。思考如何实现这一操作。
前文提到设置 chunks: initial || all 即可提取第三方库,但这会提取所有第三方库。若仅需提取 react 和 react-dom,需自定义 cacheGroup。
// indexA.js
import React from 'react'
import ReactDOM from 'react-dom'
import _ from 'lodash'
import $ from 'jquery'
// webpack.config.js
entry: {
indexA: path.join(__dirname, 'src/indexA.js')
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /react/,
name: 'vendors'
}
}
}
}

通过重写 vendors 打包块,仅打包匹配 react 的模块,从而实现了此前 CommonsChunkPlugin 的功能。
或者采用以下方式:
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
// webpack.config.js
entry: {
indexA: path.join(__dirname, 'src/indexA.js'),
vendor: ["react", "react-dom"]
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
name: "vendor",
chunks: "initial"
}
}
}
}

optimization.runtimeChunk 配置
最后提及 runtimeChunk,通过 optimization.runtimeChunk: true 选项,Webpack 会在每个入口添加一个仅包含运行时(runtime)的额外代码块。(注:需根据场景使用,这会导致每个入口加载一份额外的运行时代码。)
总结
Webpack 4 的 SplitChunks 功能强大,但建议优先使用默认模式,或仅针对第三方库进行提取优化。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
JS压缩后代码报错怎么调试?Source Map使用详解
2026-11-05 09:05:04
JS压缩会破坏代码逻辑吗?兼容性风险与测试建议
2026-11-03 17:13:03
Next.js 与 Vite、Create React App 的优缺点对比
2026-11-03 15:27:33
js文件加载失败或404错误的常见原因与排查
2026-11-03 10:38:55
前端项目打包生成 JS 文件的核心步骤完整记录
2026-10-31 21:04:46
