概述
本文档提供了 webpack 打包构建速度优化的完整方案,明确区分开发环境和生产环境的优化策略。
快速参考
| 优化方案 | 开发环境 | 生产环境 | 效果 | 难度 |
|---|---|---|---|---|
| 启用缓存 | ✅ | ✅ | ⭐⭐⭐⭐⭐ | 简单 |
| 优化 Source Map | ✅ | ❌ | ⭐⭐⭐⭐⭐ | 简单 |
| 禁用代码压缩 | ✅ | ❌ | ⭐⭐⭐⭐⭐ | 简单 |
| 使用 thread-loader | ✅ | ✅ | ⭐⭐⭐⭐ | 简单 |
| 优化 resolve 配置 | ✅ | ✅ | ⭐⭐⭐⭐ | 简单 |
| 禁用代码分割 | ✅ | ❌ | ⭐⭐⭐ | 简单 |
| 使用 esbuild-loader | ✅ | ✅ | ⭐⭐⭐ | 中等 |
| 使用 DllPlugin | ✅ | ✅ | ⭐⭐⭐ | 复杂 |
| 优化 Terser 配置 | ❌ | ✅ | ⭐⭐⭐⭐ | 简单 |
| 代码分割 | ❌ | ✅ | ⭐⭐⭐⭐ | 简单 |
| Tree Shaking | ❌ | ✅ | ⭐⭐⭐⭐ | 简单(自动) |
优化方案分类
- 🟢 通用优化: 开发和生产环境都适用
- 🔵 开发环境优化: 主要针对本地开发构建速度
- 🟠 生产环境优化: 主要针对生产构建速度和产物优化
🟢 通用优化方案(开发和生产都适用)
1. 启用缓存(最重要,效果最明显)
webpack 5 内置了文件系统缓存,可以显著提升二次构建速度。
javascript
// webpack.config.js
module.exports = {
cache: {
type: 'filesystem', // 使用文件系统缓存
buildDependencies: {
config: [__filename], // 配置文件变化时重新构建缓存
},
cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'), // 缓存目录
},
};
效果 : 二次构建速度提升 60-80%
适用: ✅ 开发环境 ✅ 生产环境
2. 使用多线程/并行处理
使用 thread-loader 将耗时的 loader 放在独立线程中处理。
javascript
const os = require('os');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: os.cpus().length - 1, // 使用 CPU 核心数 - 1
poolTimeout: 2000, // 线程池超时时间
},
},
'babel-loader',
],
},
],
},
};
安装 : npm install --save-dev thread-loader
效果 : 构建速度提升 30-50%
适用: ✅ 开发环境 ✅ 生产环境
3. 优化 resolve 配置
减少模块解析时间,明确指定查找路径。
javascript
module.exports = {
resolve: {
// 明确指定扩展名,减少文件查找
extensions: ['.js', '.vue', '.json', '.ts'],
// 使用别名,避免相对路径解析
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
},
// 明确指定 node_modules 位置
modules: [
path.resolve(__dirname, 'node_modules'),
'node_modules',
],
// 避免解析符号链接
symlinks: false,
// 避免解析不必要的模块
mainFields: ['browser', 'module', 'main'],
},
};
效果 : 模块解析速度提升 20-30%
适用: ✅ 开发环境 ✅ 生产环境
4. 减少文件搜索范围
明确指定需要处理的文件范围,排除不必要的目录。
javascript
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
// 只处理 src 目录
include: path.resolve(__dirname, 'src'),
// 排除 node_modules
exclude: /node_modules/,
},
],
},
};
效果 : 减少不必要的文件处理
适用: ✅ 开发环境 ✅ 生产环境
5. 使用更快的 Loader 替代方案
使用 esbuild-loader 替代 babel-loader,速度提升 10-100 倍。
javascript
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: 'esbuild-loader',
options: {
loader: 'jsx',
target: 'es2015',
},
},
{
test: /\.ts$/,
loader: 'esbuild-loader',
options: {
loader: 'ts',
target: 'es2015',
},
},
],
},
};
安装 : npm install --save-dev esbuild-loader
效果 : 构建速度提升 5-10 倍(适合大型项目)
适用 : ✅ 开发环境 ✅ 生产环境
注意: 需要确保 esbuild-loader 支持你的语法特性
6. 使用 DllPlugin(适合大型项目)
预构建第三方库,避免每次都重新编译。
javascript
// webpack.dll.config.js - 预构建第三方库
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendor: ['vue', 'vue-router', 'axios', 'lodash'],
},
output: {
path: path.resolve(__dirname, 'dll'),
filename: '[name].dll.js',
library: '[name]_library',
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, 'dll', '[name]-manifest.json'),
name: '[name]_library',
}),
],
};
// webpack.config.js - 主配置
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: require('./dll/vendor-manifest.json'),
}),
],
};
效果 : 首次构建后,后续构建速度提升 50-80%
适用 : ✅ 开发环境 ✅ 生产环境
注意: 配置相对复杂,适合大型项目
🔵 开发环境优化方案(主要针对本地开发)
7. 优化 Source Map(开发环境)
开发环境使用更快的 source map 类型,生产环境使用完整 source map。
javascript
module.exports = {
// 开发环境使用最快的 source map
devtool: process.env.NODE_ENV === 'production'
? 'source-map' // 生产环境:完整 source map
: 'eval-cheap-module-source-map', // 开发环境:最快速度
};
Source Map 类型对比:
eval-cheap-module-source-map: ⚡ 最快,适合开发环境cheap-module-source-map: 较快,适合开发环境source-map: 最慢但最完整,适合生产环境
效果 : 开发环境构建速度提升 50-70%
适用: 🔵 开发环境(生产环境使用完整 source map)
8. 开发环境禁用代码压缩
开发环境不需要压缩代码,可以显著提升构建速度。
javascript
module.exports = {
optimization: {
minimize: process.env.NODE_ENV === 'production', // 只在生产环境压缩
},
};
效果 : 开发环境构建速度提升 40-60%
适用: 🔵 开发环境
9. 开发环境禁用代码分割
开发环境可以禁用代码分割,减少构建时间。
javascript
module.exports = {
optimization: {
splitChunks: process.env.NODE_ENV === 'production' ? {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
},
},
} : false,
},
};
效果 : 开发环境构建速度提升 20-30%
适用: 🔵 开发环境
10. 开发环境使用 watch 模式优化
javascript
module.exports = {
watchOptions: {
// 忽略 node_modules 变化
ignored: /node_modules/,
// 聚合延迟
aggregateTimeout: 300,
// 轮询间隔
poll: 1000,
},
};
效果 : 文件变化监听更高效
适用: 🔵 开发环境
🟠 生产环境优化方案(主要针对构建速度和产物优化)
11. 优化 Terser 配置
并行压缩,启用缓存。
javascript
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
parallel: true, // 并行压缩
cache: true, // 启用缓存(webpack 5 已废弃,使用文件系统缓存)
terserOptions: {
compress: {
drop_console: true, // 生产环境移除 console
drop_debugger: true,
},
},
}),
],
},
};
效果 : 压缩速度提升 30-50%
适用: 🟠 生产环境
12. 代码分割和懒加载
合理分割代码,优化产物体积和加载速度。
javascript
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
reuseExistingChunk: true,
},
common: {
name: 'common',
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
},
},
},
};
效果 : 优化产物体积,提升加载速度
适用: 🟠 生产环境
13. 生产环境使用完整 Source Map
生产环境需要完整的 source map 用于错误追踪。
javascript
module.exports = {
devtool: process.env.NODE_ENV === 'production'
? 'source-map' // 生产环境:完整 source map
: 'eval-cheap-module-source-map',
};
适用: 🟠 生产环境
14. 生产环境启用 Tree Shaking
javascript
module.exports = {
mode: 'production', // production 模式自动启用 tree shaking
optimization: {
usedExports: true, // 标记未使用的导出
sideEffects: false, // 标记无副作用的模块
},
};
效果 : 减少打包体积
适用: 🟠 生产环境
15. 使用 HardSourceWebpackPlugin(webpack 4)
webpack 4 可以使用 HardSourceWebpackPlugin 实现缓存。
javascript
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
plugins: [
new HardSourceWebpackPlugin({
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
configHash: function(webpackConfig) {
return require('node-object-hash')({sort: false}).hash(webpackConfig);
},
}),
],
};
注意 : webpack 5 已内置缓存,不需要此插件
适用: 🟠 webpack 4 项目
1. 启用缓存(最重要,效果最明显)
webpack 5 内置了文件系统缓存,可以显著提升二次构建速度。
javascript
// webpack.config.js
module.exports = {
cache: {
type: 'filesystem', // 使用文件系统缓存
buildDependencies: {
config: [__filename], // 配置文件变化时重新构建缓存
},
cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'), // 缓存目录
},
};
效果: 二次构建速度提升 60-80%
2. 使用多线程/并行处理
使用 thread-loader 将耗时的 loader 放在独立线程中处理。
javascript
const os = require('os');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: os.cpus().length - 1, // 使用 CPU 核心数 - 1
poolTimeout: 2000, // 线程池超时时间
},
},
'babel-loader',
],
},
],
},
};
安装 : npm install --save-dev thread-loader
效果: 构建速度提升 30-50%
3. 优化 resolve 配置
减少模块解析时间,明确指定查找路径。
javascript
module.exports = {
resolve: {
// 明确指定扩展名,减少文件查找
extensions: ['.js', '.vue', '.json', '.ts'],
// 使用别名,避免相对路径解析
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
},
// 明确指定 node_modules 位置
modules: [
path.resolve(__dirname, 'node_modules'),
'node_modules',
],
// 避免解析符号链接
symlinks: false,
// 避免解析不必要的模块
mainFields: ['browser', 'module', 'main'],
},
};
效果: 模块解析速度提升 20-30%
4. 减少文件搜索范围
明确指定需要处理的文件范围,排除不必要的目录。
javascript
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
// 只处理 src 目录
include: path.resolve(__dirname, 'src'),
// 排除 node_modules
exclude: /node_modules/,
},
],
},
};
效果: 减少不必要的文件处理
5. 使用更快的 Loader 替代方案
使用 esbuild-loader 替代 babel-loader,速度提升 10-100 倍。
javascript
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: 'esbuild-loader',
options: {
loader: 'jsx',
target: 'es2015',
},
},
{
test: /\.ts$/,
loader: 'esbuild-loader',
options: {
loader: 'ts',
target: 'es2015',
},
},
],
},
};
安装 : npm install --save-dev esbuild-loader
效果: 构建速度提升 5-10 倍(适合大型项目)
6. 优化 Source Map
开发环境使用更快的 source map 类型。
javascript
module.exports = {
// 开发环境使用最快的 source map
devtool: process.env.NODE_ENV === 'production'
? 'source-map' // 生产环境:完整 source map
: 'eval-cheap-module-source-map', // 开发环境:最快速度
};
Source Map 类型对比:
eval-cheap-module-source-map: 最快,适合开发环境cheap-module-source-map: 较快,适合开发环境source-map: 最慢但最完整,适合生产环境
效果: 开发环境构建速度提升 50-70%
7. 使用 DllPlugin(适合大型项目)
预构建第三方库,避免每次都重新编译。
javascript
// webpack.dll.config.js - 预构建第三方库
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendor: ['vue', 'vue-router', 'axios', 'lodash'],
},
output: {
path: path.resolve(__dirname, 'dll'),
filename: '[name].dll.js',
library: '[name]_library',
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, 'dll', '[name]-manifest.json'),
name: '[name]_library',
}),
],
};
// webpack.config.js - 主配置
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: require('./dll/vendor-manifest.json'),
}),
],
};
效果: 首次构建后,后续构建速度提升 50-80%
8. 代码分割和懒加载
合理分割代码,减少单次构建的文件量。
javascript
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
reuseExistingChunk: true,
},
common: {
name: 'common',
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
},
},
},
};
效果: 增量构建速度提升
9. 减少插件使用
生产环境禁用不必要的插件,使用 webpack 的 mode 自动优化。
javascript
module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
plugins: [
// 只在生产环境使用
...(process.env.NODE_ENV === 'production'
? [new SomeProductionPlugin()]
: []),
],
};
10. 优化 Terser 配置
并行压缩,启用缓存。
javascript
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
parallel: true, // 并行压缩
cache: true, // 启用缓存
terserOptions: {
compress: {
drop_console: true, // 生产环境移除 console
drop_debugger: true,
},
},
}),
],
},
};
效果: 压缩速度提升 30-50%
11. 使用 HardSourceWebpackPlugin(webpack 4)
webpack 4 可以使用 HardSourceWebpackPlugin 实现缓存。
javascript
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
plugins: [
new HardSourceWebpackPlugin({
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
configHash: function(webpackConfig) {
return require('node-object-hash')({sort: false}).hash(webpackConfig);
},
}),
],
};
注意: webpack 5 已内置缓存,不需要此插件
完整优化配置示例
开发环境配置
javascript
const path = require('path');
const os = require('os');
module.exports = {
mode: 'development',
// 1. 启用缓存(通用)
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
},
// 2. 优化 resolve(通用)
resolve: {
extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
'@': path.resolve(__dirname, 'src'),
},
modules: [path.resolve(__dirname, 'node_modules')],
symlinks: false,
},
// 3. 开发环境:使用最快的 source map
devtool: 'eval-cheap-module-source-map',
// 4. 模块规则(通用)
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: os.cpus().length - 1,
},
},
'babel-loader',
],
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
},
],
},
// 5. 开发环境:禁用压缩和代码分割
optimization: {
minimize: false, // 不压缩
splitChunks: false, // 不分割代码
},
// 6. 开发环境:watch 模式优化
watchOptions: {
ignored: /node_modules/,
aggregateTimeout: 300,
poll: 1000,
},
};
生产环境配置
javascript
const path = require('path');
const os = require('os');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
// 1. 启用缓存(通用)
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
},
// 2. 优化 resolve(通用)
resolve: {
extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
'@': path.resolve(__dirname, 'src'),
},
modules: [path.resolve(__dirname, 'node_modules')],
symlinks: false,
},
// 3. 生产环境:使用完整 source map
devtool: 'source-map',
// 4. 模块规则(通用)
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: os.cpus().length - 1,
},
},
'babel-loader',
],
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/,
},
],
},
// 5. 生产环境:启用压缩和代码分割
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
}),
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
reuseExistingChunk: true,
},
common: {
name: 'common',
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
},
},
usedExports: true, // Tree shaking
sideEffects: false,
},
};
性能分析工具
1. speed-measure-webpack-plugin
分析各个插件和 loader 的耗时。
javascript
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({
// webpack 配置
});
安装 : npm install --save-dev speed-measure-webpack-plugin
2. webpack-bundle-analyzer
分析打包体积,找出可以优化的地方。
javascript
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
}),
],
};
安装 : npm install --save-dev webpack-bundle-analyzer
优化优先级建议
🔵 开发环境优化优先级
按效果和实现难度排序:
-
启用缓存 ⭐⭐⭐⭐⭐
- 效果最明显,实现最简单
- 二次构建速度提升 60-80%
- ✅ 通用优化
-
优化 Source Map ⭐⭐⭐⭐⭐
- 开发环境效果显著
- 构建速度提升 50-70%
- 🔵 开发环境专用
-
禁用代码压缩 ⭐⭐⭐⭐⭐
- 开发环境不需要压缩
- 构建速度提升 40-60%
- 🔵 开发环境专用
-
使用 thread-loader ⭐⭐⭐⭐
- 多核 CPU 效果明显
- 构建速度提升 30-50%
- ✅ 通用优化
-
优化 resolve 配置 ⭐⭐⭐⭐
- 实现简单,效果稳定
- 模块解析速度提升 20-30%
- ✅ 通用优化
-
禁用代码分割 ⭐⭐⭐
- 开发环境不需要分割
- 构建速度提升 20-30%
- 🔵 开发环境专用
-
使用 esbuild-loader ⭐⭐⭐
- 适合大型项目
- 需要替换现有 loader
- ✅ 通用优化
-
使用 DllPlugin ⭐⭐⭐
- 适合大型项目
- 配置相对复杂
- ✅ 通用优化
🟠 生产环境优化优先级
-
启用缓存 ⭐⭐⭐⭐⭐
- 二次构建速度提升 60-80%
- ✅ 通用优化
-
优化 Terser 配置 ⭐⭐⭐⭐
- 压缩速度提升 30-50%
- 🟠 生产环境专用
-
代码分割 ⭐⭐⭐⭐
- 优化产物体积和加载速度
- 🟠 生产环境专用
-
使用 thread-loader ⭐⭐⭐⭐
- 构建速度提升 30-50%
- ✅ 通用优化
-
优化 resolve 配置 ⭐⭐⭐⭐
- 模块解析速度提升 20-30%
- ✅ 通用优化
-
Tree Shaking ⭐⭐⭐⭐
- 减少打包体积
- 🟠 生产环境专用(production 模式自动启用)
快速诊断
检查构建瓶颈
- 使用
speed-measure-webpack-plugin找出耗时最长的步骤 - 使用
webpack-bundle-analyzer分析打包体积 - 检查是否有大量小文件或重复打包
常见问题
-
构建很慢,但不知道哪里慢
- 使用
speed-measure-webpack-plugin分析
- 使用
-
二次构建还是很慢
- 检查是否启用了缓存
- 检查缓存目录是否有写入权限
-
内存占用过高
- 减少并行数量
- 使用
--max-old-space-size增加内存限制
参考资源
更新日志
- 2025-01-XX: 初始版本