Webpack 打包优化:如何让构建速度快过泡茶?
泡一杯茶需要多久?三分钟?五分钟?如果你的 Webpack 构建速度比泡茶还慢,那可能是时候优化了。从配置调整到插件选择,再到代码拆分,每一步都可能成为构建性能的瓶颈。
分析构建瓶颈
优化前先定位问题。Webpack 提供了 speed-measure-webpack-plugin
,它能精确测量每个插件和 loader 的耗时:
javascript
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({
// 原有 Webpack 配置
});
运行构建后,你会看到类似这样的输出:
HappyPack[js]: 15.3s
Babel-loader: 12.1s
TerserPlugin: 8.7s
如果发现 babel-loader
耗时过长,可能是文件转译范围过大;如果 TerserPlugin
卡顿,可能需要调整压缩策略。
减少文件处理范围
通过 include
和 exclude
限制 loader 的作用范围,避免对 node_modules
等目录的无意义处理:
javascript
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
include: path.resolve(__dirname, "src"), // 只处理 src 目录
exclude: /node_modules/, // 排除 node_modules
},
],
},
多线程与缓存加速
HappyPack 或 thread-loader
将耗时的 loader(如 Babel)放到独立线程中运行:
javascript
rules: [
{
test: /\.js$/,
use: ["thread-loader", "babel-loader"], // thread-loader 需放在前面
},
],
缓存结果
babel-loader
和 eslint-loader
支持缓存:
javascript
rules: [
{
test: /\.js$/,
loader: "babel-loader",
options: {
cacheDirectory: true, // 启用 Babel 缓存
},
},
],
优化依赖与代码拆分
缩小打包范围
使用 externals
排除已知库(如 React):
javascript
externals: {
react: "React", // 通过 CDN 引入
},
动态导入与懒加载
通过动态导入拆分代码:
javascript
// 原写法
import HeavyComponent from "./HeavyComponent";
// 优化后
const HeavyComponent = React.lazy(() => import("./HeavyComponent"));
压缩与 Tree Shaking
选择更快的压缩工具
用 esbuild-webpack-plugin
替代 Terser:
javascript
const { ESBuildMinifyPlugin } = require("esbuild-webpack-plugin");
optimization: {
minimizer: [new ESBuildMinifyPlugin({ target: "es2015" })],
},
确保 Tree Shaking 生效
在 package.json
中标记副作用:
json
{
"sideEffects": ["*.css", "*.scss"]
}
开发环境特调
禁用生产级优化
开发环境下关闭代码压缩和完整 SourceMap:
javascript
devtool: "eval-cheap-module-source-map", // 快速 SourceMap
optimization: {
minimize: false, // 关闭压缩
},
使用 DLLPlugin 预编译依赖
将第三方库打包为单独文件:
javascript
// webpack.dll.config.js
module.exports = {
entry: { vendor: ["react", "lodash"] },
output: {
filename: "[name].dll.js",
path: path.resolve(__dirname, "dll"),
library: "[name]",
},
plugins: [
new webpack.DllPlugin({
name: "[name]",
path: path.join(__dirname, "dll/[name]-manifest.json"),
}),
],
};
监控与持续优化
集成 webpack-bundle-analyzer
分析产物体积:
javascript
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
plugins: [
new BundleAnalyzerPlugin(),
],
定期检查构建报告,重点关注:
- 重复依赖(如多个版本的 lodash)
- 意外打入的巨型文件(如未压缩的 JSON)
进阶:持久化缓存
Webpack 5 的 cache
配置可持久化缓存到文件系统:
javascript
cache: {
type: "filesystem",
buildDependencies: {
config: [__filename], // 配置文件变更时缓存失效
},
},
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn