详解webpack4之splitchunksPlugin代码包分拆
本文详细解析webpack4中splitChunksPlugin的配置方法,通过多页面项目实例演示如何分离公共代码、异步组件及第三方库。重点讲解chunks、minSize、priority等参数对打包结果的影响,并通过优化echarts和d3等大体积库的加载策略,显著降低首屏资源体积,提升页面加载性能。
项目背景与框架介绍
本文介绍了一个多页面项目的构建过程,重点在于利用webpack4的splitChunks插件进行代码包的拆分与优化。
项目框架

该项目包含home和topic两个入口文件,主要组成部分如下:
- 项目基础框架由react、mobx和antd构成。
- echarts和d3是项目中部分页面使用的大型图表组件库。
- src目录下的业务组件和代码。
- 其他非公共代码。
两个入口文件均使用react-loadable实现了异步加载功能。
import Loadable from 'react-loadable';
...
const LoadableLogin = Loadable({
loader: () => import('../../common/components/login'),
loading: Loading,
});
...
splitChunks核心配置解析
webpack的相关配置如下所示:
module.exports = {
...
mode: 'production',
entry: { // 多入口
home: './src/home',
topic: './src/topic',
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
},
plugins: [
new HtmlWebpackPlugin({ // home页面
filename: 'home.html',
template: './template.html',
}),
new HtmlWebpackPlugin({ // topic页面
filename: 'topic.html',
template: './template.html',
inject: true,
}),
],
...
}
splitChunks
chunks配置选项
- all:无论文件是动态还是静态加载,统一进行分离。页面首次加载时会引入所有生成的包。
- async:仅分离异步加载的文件,首次加载通常不包含,仅在需要异步引入组件时才加载。
- initial:分离异步和非异步文件。如果一个文件既被异步引入又被非异步引入,它会被打包两次(注意与all的区别),主要用于分离页面首次加载所需的包。
minSize:文件最小打包体积,单位为byte,默认值为30000。
例如,若项目中有三个入口文件a.js、b.js和c.js,大小均为100byte,当minSize设置为301时,webpack会将它们合并为一个包,而不会拆分为多个包。
例如,若项目中有三个入口文件a.js、b.js和c.js,大小均为100byte,当minSize设置为301时,webpack会将它们合并为一个包,而不会拆分为多个包。
automaticNameDelimiter:用于生成文件名时的连接符。
假设生成了一个名为vendor的公共文件,a.js和b.js都依赖它,且连接符设置为"~",最终生成的文件名将是vendor~a~b.js。
maxInitialRequests:入口点处的最大并行请求数,默认值为3。
如果将其设置为1,每个入口文件将只打包成一个文件。
maxAsyncRequests:最大异步请求数量,默认值为5。
如果将其设置为1,每个入口文件将只打包成一个文件。
优先级关系
优先级顺序为:maxInitialRequests / maxAsyncRequests < maxSize < minSize。
cacheGroups:用于定制分割包的规则。
test可以配置正则表达式或函数作为打包规则。其他属性均可继承splitChunks的配置,这里需要特别说明priority,它用于设置包的打包优先级,非常重要(后续结合实践说明)。
minChunks
定义模块被引入的最少次数。
代码分包实践与优化
实践
我们从一个最简单的配置开始,尝试将公共代码打包出来。
splitChunks: {
chunks: 'all', // initial、async和all
minSize: 30000, // 形成一个新代码块最小的体积
maxAsyncRequests: 5, // 按需加载时候最大的并行请求数
maxInitialRequests: 3, // 最大初始化请求数
automaticNameDelimiter: '~', // 打包分割符
name: true,
cacheGroups: {
vendors: { // 打包两个页面的公共代码
minChunks: 2, // 引入两次及以上被打包
name: 'vendors', // 分离包的名字
chunks: 'all'
},
}
},
两个入口文件的公共代码被打包到vendor文件夹下,包括echarts、d3、amcharts等第三方包以及src下的公共代码。

这显然不是我们期望的结果,存在以下问题:
- 通常用户进入网站的第一步是访问登录页面,此时只需要项目的基本框架代码,如react、react-dom、antd等。我们可以使用all(或initial)将它们单独打包,作为首页必须加载的包。
- 在首次加载页面时,我们只希望加载同步代码,因此需要一个同步的Common包。
- 对于echarts、d3以及src下部分异步加载的包,可以利用async将它们打包成一个独立的异步加载包。
我们修改cacheGroups配置如下:
cacheGroups: {
vendors: { // 项目基本框架等
chunks: 'all',
test: /(react|react-dom|react-dom-router|babel-polyfill|mobx)/,
priority: 100,
name: 'vendors',
},
'async-commons': { // 异步加载公共包、组件等
chunks: 'async',
minChunks: 2,
name: 'async-commons',
priority: 90,
},
commons: { // 其他同步加载公共包
chunks: 'all',
minChunks: 2,
name: 'commons',
priority: 80,
},
}

此次webpack生成的包主要包括:
- async-common:两个入口文件都异步加载的三方包以及利用react-loader实现的懒加载代码,包含echarts、d3等。
- vendors:包括react、react-dom、antd等基础框架库。
- commons:引用超过两次的同步代码。
这里有两个需要注意的地方:
- 注意priority的设置,顺序为vendors > async-commons > commons。我们优先打包react、react-dom等库,然后再打包公共部分。如果将vendors的优先级设置低于两个Common包的优先级,react和react-dom将被打包到common包中,而不会生成独立的vendors包。
- 如果去掉commons的配置,将会生成一个名为topic~home的包。在配置了async-common提取异步加载公共包后,默认会将同步加载的公共包打包生成以automaticNameDelimiter连接符‘~'命名的‘topic~home'包,其内容与commons包完全相同。
按照我们的要求,这样首次页面加载只会引入vendors和commons包,而不会引入async-common包,效果不错!追求更精致的优化,我们继续思考是否还能做得更好?
到目前为止,我们的打包文件结构如下:

经过gzip压缩后,最大的async-common包体积为391kb。由于公司生产环境网速有时仅为20kb/s,导致页面加载缓慢,因此需要继续优化split配置。
分析如下:
- async-common中包含了自写的src组件和第三方组件。
- async-common中体积较大的是echarts、zrender(echarts引入)和d3。结合项目实际情况,只有部分页面需要echarts(d3同理),因此可以考虑将d3和echarts这两个大体积包单独提取出来,在特定页面需要时再异步加载,从而大幅减小async-common的体积。
修改配置如下:
cacheGroups: {
vendors: { // 基本框架
chunks: 'all',
test: /(react|react-dom|react-dom-router|babel-polyfill|mobx)/,
priority: 100,
name: 'vendors',
},
d3Venodr: { // 将体积较大的d3单独提取包,指定页面需要的时候再异步加载
test: /d3/,
priority: 100, // 设置高于async-commons,避免打包到async-common中
name: 'd3Venodr',
chunks: 'async'
},
echartsVenodr: { // 异步加载echarts包
test: /(echarts|zrender)/,
priority: 100, // 高于async-commons优先级
name: 'echartsVenodr',
chunks: 'async'
},
'async-commons': { // 其余异步加载包
chunks: 'async',
minChunks: 2,
name: 'async-commons',
priority: 90,
},
commons: { // 其余同步加载包
chunks: 'all',
minChunks: 2,
name: 'commons',
priority: 80,
},
}

每次修改后,需要在htmlWebpackPlugin中配置chunk所需的包。
plugins: [
new HtmlWebpackPlugin({ // home页面
filename: 'home.html',
template: './template.html',
chunks: ['vendors', 'commons', 'home'],
}),
new HtmlWebpackPlugin({ // topic页面
filename: 'topic.html',
template: './template.html',
chunks: ['vendors', 'commons', 'topic'],
}),
],
后期还进行了其他拆分和优化,大致将最大包体积保持在100k左右。当然,不建议拆分得过于细碎,因为浏览器HTTP/1.1协议可能一次性只支持6个文件下载,过多反而适得其反。大家可以根据自身项目情况采取不同的拆分策略,总之,目的是为了让项目在线上运行更完美,提供更好的用户体验。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
JS处理特殊字符时怎么安全生成JSON
2026-11-05 15:44:51
内部脚本与外部js文件的区别及优缺点对比
2026-11-05 14:42:19
JavaScript前端性能优化指南:提升页面加载速度与渲染效率
2026-11-05 13:48:26
主流JS反混淆工具对比:de4js、unminify与AST还原方案评测
2026-11-05 12:00:56
Nuxt.js 性能优化技巧:代码分割与组件懒加载
2026-11-03 23:32:56
