Webpack SplitChunksPlugin 的配置技巧
Webpack SplitChunksPlugin 的基本概念
在前端开发中,随着项目规模的增长,打包后的文件体积也会逐渐变大。这不仅会导致页面加载时间变长,还会影响用户体验。Webpack 的 SplitChunksPlugin
就是为了解决这个问题而诞生的。它能够将公共代码从各个入口 chunk 中分离出来,形成单独的 chunk,这样在多个页面或模块中就可以共享这些代码,从而减少整体的文件体积。
SplitChunksPlugin
是 Webpack 4 开始内置的插件,无需额外安装。它基于一些配置规则来决定如何拆分代码块。默认情况下,Webpack 会对异步加载的模块进行代码分割,而对于同步加载的模块则不会自动分割。通过配置 SplitChunksPlugin
,我们可以对同步和异步模块都进行灵活的代码分割。
配置参数详解
chunks
这个参数用于指定哪些 chunk 应该被分割。它有三个取值:'initial'
、'async'
、'all'
。'async'
:默认值,表示只对异步加载的 chunk 进行分割。例如,在使用动态import()
语法引入模块时,这些异步加载的模块会根据配置进行代码分割。'initial'
:表示只对入口 chunk(即通过entry
配置的入口文件)进行分割。'all'
:表示对所有的 chunk,包括同步和异步加载的 chunk 都进行分割。
示例代码:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
minSize
这个参数定义了被分割出来的 chunk 的最小大小(以字节为单位)。如果一个模块或模块组的大小小于minSize
,则不会被分割成单独的 chunk。默认值是30000
(即 30KB)。 例如,我们将minSize
设为10000
(10KB),表示只要模块或模块组大小超过 10KB 就有可能被分割:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
minSize: 10000
}
}
};
maxSize
与minSize
相反,maxSize
用于限制分割后的 chunk 的最大大小。如果一个模块或模块组超过了maxSize
,Webpack 会尝试将其进一步分割,以确保每个 chunk 的大小不超过这个值。默认情况下没有设置maxSize
。 例如,我们设置maxSize
为20000
(20KB):
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
minSize: 10000,
maxSize: 20000
}
}
};
minChunks
minChunks
定义了一个模块至少需要被引用多少次才会被提取到公共 chunk 中。默认值是1
,表示只要被引用一次就可能被提取。如果设为2
,则表示该模块至少要被两个不同的 chunk 引用才会被提取出来。 示例:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
minChunks: 2
}
}
};
maxAsyncRequests
这个参数限制了在按需加载时,同时加载的最大请求数。默认值是6
。减少这个值可以避免在某些情况下一次性请求过多的文件,从而优化加载性能。 例如,我们将其设为4
:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
maxAsyncRequests: 4
}
}
};
maxInitialRequests
与maxAsyncRequests
类似,maxInitialRequests
限制了入口 chunk 的最大并行请求数。默认值是3
。在页面首次加载时,入口 chunk 的请求数过多可能会影响加载速度,通过设置这个值可以优化初始加载性能。 例如:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
maxInitialRequests: 2
}
}
};
cacheGroups
cacheGroups
是SplitChunksPlugin
中最重要的配置选项之一,它允许我们根据自定义的规则来创建多个缓存组。每个缓存组都有自己独立的配置,如test
、priority
等。test
:用于匹配模块路径或名称,只有匹配的模块才会被分到该缓存组。它可以是一个正则表达式、字符串或者函数。priority
:缓存组的优先级。当一个模块同时满足多个缓存组的条件时,会根据优先级决定被分到哪个缓存组。数值越大优先级越高。name
:缓存组生成的 chunk 的名称。如果不设置,Webpack 会根据模块的路径等信息自动生成名称。
示例:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name:'vendors',
priority: -10
},
commons: {
name: 'commons',
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
};
在上述示例中,vendor
缓存组用于匹配 node_modules
中的模块,并将其提取到名为 vendors
的 chunk 中。commons
缓存组用于提取至少被两个 chunk 引用的公共模块,名称为 commons
,并且 reuseExistingChunk
设置为 true
,表示如果该模块已经在其他 chunk 中存在,则不会重复提取。
实际应用场景
- 提取第三方库
在大多数项目中,都会使用大量的第三方库,如 React、Vue、lodash 等。这些库通常体积较大,并且在多个页面或模块中会被重复引用。通过
SplitChunksPlugin
,我们可以将这些第三方库提取到单独的 chunk 中,实现缓存和复用。 示例配置:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name:'vendors',
priority: -10
}
}
}
}
};
假设项目中使用了 React 和 lodash,打包后会将这两个库以及其他来自 node_modules
的模块都提取到 vendors.js
文件中。这样,在页面加载时,只要 vendors.js
被缓存,后续页面再次加载时就无需重复下载这些第三方库,大大提高了加载速度。
- 提取公共业务代码
除了第三方库,项目中往往还存在一些公共的业务代码,如工具函数、通用组件等。这些代码也可以通过
SplitChunksPlugin
提取出来,减少每个页面或模块的代码体积。 例如,项目中有一个utils
文件夹,里面存放了一些通用的工具函数,并且在多个页面中被引用。我们可以这样配置:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
commons: {
test: /[\\/]src[\\/]utils[\\/]/,
name: 'commons',
minChunks: 2
}
}
}
}
};
这样,src/utils
目录下被至少两个 chunk 引用的模块就会被提取到 commons.js
中。
- 按路由分割代码
在单页应用(SPA)中,通常会根据路由来加载不同的页面组件。通过
SplitChunksPlugin
,我们可以按照路由来分割代码,实现按需加载。 假设项目使用 React Router,页面结构如下:
src/
├── pages/
│ ├── Home/
│ │ ├── Home.js
│ │ └── Home.css
│ ├── About/
│ │ ├── About.js
│ │ └── About.css
│ └── Contact/
│ ├── Contact.js
│ └── Contact.css
├── App.js
└── index.js
配置如下:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
page: {
name: ({ module }) => {
const match = module.context.match(/[\\/]src[\\/]pages[\\/](.*?)([\\/]|$)/);
return match? `page-${match[1]}` : undefined;
},
chunks: 'initial',
minChunks: 1
}
}
}
}
};
在上述配置中,page
缓存组根据模块路径生成 chunk 名称,将每个页面的代码分割成单独的文件。例如,Home
页面的代码会被分割到 page - Home.js
中。当用户访问相应路由时,才会加载对应的页面代码,提高了应用的加载性能。
优化策略
- 合理设置
minSize
和maxSize
minSize
设置过小可能会导致生成过多的小 chunk,增加请求数量;设置过大则可能无法充分提取公共代码。maxSize
的设置也需要根据项目实际情况来调整。如果项目主要面向移动端,网络环境相对较差,那么可以适当减小maxSize
,以减少每个请求的大小。 例如,对于移动端项目,我们可以将minSize
设为5000
(5KB),maxSize
设为15000
(15KB):
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
minSize: 5000,
maxSize: 15000
}
}
};
- 调整
cacheGroups
的优先级 当多个缓存组的test
规则可能匹配到同一个模块时,优先级就显得尤为重要。确保重要的缓存组(如提取第三方库的缓存组)具有较高的优先级,这样可以避免模块被错误地分到其他缓存组。 例如,我们将vendor
缓存组的优先级设为10
,commons
缓存组的优先级设为5
:
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name:'vendors',
priority: 10
},
commons: {
name: 'commons',
minChunks: 2,
priority: 5
}
}
}
}
};
- 使用
reuseExistingChunk
将reuseExistingChunk
设置为true
可以避免重复提取已经存在于其他 chunk 中的模块。这在提取公共代码时非常有用,可以进一步减小打包后的文件体积。
module.exports = {
//...其他配置
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
commons: {
name: 'commons',
minChunks: 2,
reuseExistingChunk: true
}
}
}
}
};
- 分析打包结果
Webpack 提供了一些工具来分析打包结果,如
webpack - bundle - analyzer
。通过分析打包后的文件大小、模块依赖关系等信息,我们可以进一步优化SplitChunksPlugin
的配置。 安装webpack - bundle - analyzer
:
npm install --save - dev webpack - bundle - analyzer
在 webpack.config.js
中添加如下配置:
const BundleAnalyzerPlugin = require('webpack - bundle - analyzer').BundleAnalyzerPlugin;
module.exports = {
//...其他配置
plugins: [
new BundleAnalyzerPlugin()
]
};
运行打包命令后,会打开一个浏览器窗口,展示打包后的模块大小、依赖关系等详细信息。根据这些信息,我们可以调整 SplitChunksPlugin
的配置参数,如 minSize
、cacheGroups
的 test
规则等,以达到更好的代码分割效果。
注意事项
- 避免过度分割
虽然代码分割可以减小文件体积,但过度分割会导致请求数量过多,增加网络开销。在设置
minSize
、maxSize
等参数时,要综合考虑项目的实际情况和目标用户群体的网络环境。 - 模块依赖顺序 在提取公共模块时,要注意模块之间的依赖关系。如果一个模块 A 依赖于另一个模块 B,并且模块 B 被提取到公共 chunk 中,那么模块 A 也应该被正确地处理,以确保依赖关系的正确性。
- 缓存问题 当对代码进行分割后,要注意缓存的设置。对于提取出来的第三方库和公共代码 chunk,应该设置较长的缓存时间,以充分利用缓存提高加载速度。但在代码更新时,要确保缓存能够正确地失效,避免用户加载到旧的代码。
通过合理配置 SplitChunksPlugin
,我们可以有效地优化前端项目的打包结果,提高页面加载速度和用户体验。在实际项目中,需要根据项目的特点和需求,不断调整配置参数,以达到最佳的优化效果。同时,结合其他 Webpack 插件和工具,如 webpack - bundle - analyzer
,可以更好地分析和优化打包结果。希望本文介绍的内容能够帮助你在前端开发中熟练运用 SplitChunksPlugin
,打造高性能的前端应用。