项目越写越大,打包一次喝杯咖啡回来还没好?产出的bundle.js比电影还大?今天我们就来一场Webpack“减肥+提速”双修课。不用焦虑,6招下来,你的打包速度会像换了跑车引擎,产物体积瘦成一道闪电。
前言
Webpack就像个勤劳的搬运工,但如果你不告诉它“哪些不用搬”、“怎么抄近道”,它会把你整个项目连同node_modules一起扛上,慢得像蜗牛。今天我们就来调教这个搬运工,让打包速度飞起,让产物体积减半。
本文分两大块:速度优化(开发时等你)和体积优化(上线时快人一步)。
一、速度优化:别让Webpack摸鱼
1. 减少Loader和Plugin的工作范围
Webpack默认会遍历node_modules,但这里面的代码通常已经编译好了。用exclude告诉它:别管node_modules。
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // 跳过node_modules
use: 'babel-loader'
}
]
}
同理,Plugin里如果不需要在某个环境下执行,可以动态添加。
2. 使用缓存:第二次打包快如闪电
- babel-loader缓存:
cacheDirectory: true
use: {
loader: 'babel-loader',
options: { cacheDirectory: true }
}
- cache-loader(Webpack5之前):把结果缓存到硬盘。
- Webpack5内置缓存:直接开启
module.exports = {
cache: {
type: 'filesystem', // 硬盘缓存
}
};
第一次打包正常,第二次秒开。
3. 多线程/多进程构建
- thread-loader:把耗时Loader扔到子进程。
use: [
{ loader: 'thread-loader', options: { workers: 3 } },
'babel-loader'
]
- HappyPack(不维护了,慎用)。Webpack5里用thread-loader就够了。
4. 使用DLLPlugin(或Webpack5的持久化缓存)
老项目中DLLPlugin可以把第三方库预先打包成动态链接库,现在Webpack5的cache.type: 'filesystem'已够用。如果还想更极致,可以用splitChunks把vendor拆出去。
二、体积优化:让bundle瘦成闪电
1. 代码分割(SplitChunks)
把公共代码抽出来,防止重复打包。Webpack4+内置optimization.splitChunks,默认配置已经很智能:
optimization: {
splitChunks: {
chunks: 'all', // 对所有模块生效
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
}
}
}
}
这样会生成一个vendors.js,里面是第三方库,单独缓存。
2. 动态导入(按需加载)
不要一次性加载所有路由的组件。React里用React.lazy + Suspense,Vue里用动态import。
// 之前
import Dashboard from './Dashboard';
// 之后
const Dashboard = React.lazy(() => import('./Dashboard'));
Webpack会自动把Dashboard单独打包成一个chunk,只有访问时才加载。
3. Tree Shaking:摇掉死代码
Tree Shaking依赖ES6模块静态结构。确保:
- 使用
import/export,不要用require。 sideEffects: false或 指定有副作用的文件。
// package.json
{
"sideEffects": false // 告诉Webpack所有文件都没有副作用,可以安全摇掉未引用代码
}
如果你的项目里有import './global.css'这种,需要把CSS文件排除:
"sideEffects": ["*.css", "*.scss"]
4. 压缩代码
- TerserPlugin(JS压缩):Webpack5自带,无需安装。可以开启并行压缩。
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true, // 多线程压缩
terserOptions: {
compress: { drop_console: true } // 去除console
}
})
]
}
- CssMinimizerPlugin(CSS压缩):压缩抽离的CSS文件。
5. 图片压缩与优化
- image-webpack-loader:无损压缩图片。
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: { bypassOnDebug: true, disable: process.env.NODE_ENV === 'development' }
}
]
}
- url-loader:小图片转base64,减少请求数。
6. 分析打包结果
不知道哪里胖?用工具照个X光。
- webpack-bundle-analyzer:生成交互式饼图。
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins: [new BundleAnalyzerPlugin()]
一看便知哪个库占最大,然后决定替换或按需引入(比如lodash换成lodash-es)。
三、实战:一个优化前后的对比
假设项目原始打包时间30秒,体积2.5MB。
| 优化措施 | 时间效果 | 体积效果 |
|---|---|---|
| exclude + 缓存 | 30s → 10s | - |
| thread-loader | 10s → 6s | - |
| splitChunks | - | 2.5MB → 主包1MB,vendors 1.2MB |
| 动态导入 | - | 首屏只加载主包1MB |
| 压缩+tree shaking | - | 主包700KB,vendors 900KB |
| 图片压缩 | - | 再减200KB |
最终打包时间6秒,首屏加载1.2MB(原来2.5MB),体验大幅提升。
四、总结:优化口诀
- 速度:缩小范围、开启缓存、多线程。
- 体积:代码分割、动态导入、摇树、压缩、图片瘦身。
- 工具:用
webpack-bundle-analyzer看胖在哪,用speed-measure-webpack-plugin测谁慢。
优化不是一次性的事,项目每增加一个依赖,都要留心。但掌握了这6招,你已经能解决90%的性能问题。
如果你觉得今天的“减肥+提速”课够干,点个赞让更多人看到。明天我们将进入Vite原理——比Webpack更快的下一代构建工具。我们明天见!