Files

86 lines
3.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: frontend.webpack.scenario.build-speed
title: 大型项目构建慢、包体积大:度量、优化和防退化
type: scenario
domain: frontend
stack: [webpack, fe-testing-perf, cicd]
tags: [构建速度, 包体积, splitChunks, 持久化缓存, 体积预算, CI]
level: intermediate
prerequisites: [frontend.webpack.build-optimization]
est_hours: 2
related: [frontend.webpack.interview, frontend.vite.scenario.webpack-to-vite]
week: [7]
---
# 大型项目构建慢、包体积大:度量、优化和防退化
## 业务背景与问题
一个中台项目(webpack 5,几百个页面):CI 构建要十几分钟,发版排队;首页 JS 有几 MB,弱网用户首屏很慢;优化过一次,几个月后又变回去了。
## 约束
- 短期内不能换构建工具(有大量自定义 loader 和插件)。
- 优化要可量化,并且防止退化。
## 方案设计
1. **先度量**:
- 构建速度:统计各 loader / plugin 耗时(速度分析插件或 `--profile`);
- 体积:生成产物分析报告(`webpack --json` + 可视化工具),找出最大的依赖和重复依赖。
2. **构建提速**:
- 开启 `cache: { type: "filesystem" }`,CI 中缓存缓存目录;
- babel-loader 换成 swc 类 loader,并用 `include` 只处理源码;
- 生产构建关闭不需要的 source map 或使用更快的类型;
- 类型检查与构建并行(单独的 `tsc --noEmit` 任务)。
3. **体积优化**:
- 路由级懒加载;
- 大依赖按需引入(图表库、组件库、日期库)或替换为更小的库;
- `splitChunks` 按变化频率拆分第三方库;
- 检查 `sideEffects` 让 tree shaking 生效。
4. **防退化**:在 CI 中设置体积预算(`performance.maxEntrypointSize` 或脚本对比上次的产物大小),超出就失败并提示。
## 关键代码
```js
// webpack.config.js 片段
export default {
cache: { type: "filesystem", buildDependencies: { config: [import.meta.filename] } }, // 配置变化时缓存失效
module: {
rules: [{ test: /\.[jt]sx?$/, include: path.resolve("src"), use: "swc-loader" }],
},
optimization: {
runtimeChunk: "single",
splitChunks: {
chunks: "all",
cacheGroups: {
framework: { test: /[\\/]node_modules[\\/](vue|vue-router|pinia)[\\/]/, name: "framework", priority: 20 },
vendors: { test: /[\\/]node_modules[\\/]/, name: "vendors", priority: 10 },
},
},
},
performance: { hints: "error", maxEntrypointSize: 500 * 1024, maxAssetSize: 300 * 1024 }, // 超预算直接构建失败
};
```
可运行的基础配置:[examples/webpack-config](../examples/webpack-config/)。
## 取舍
| 选择 | 优点 | 缺点 |
| --- | --- | --- |
| **在 webpack 内优化(本方案)** | 风险小,见效快 | 上限受 webpack 限制 |
| 迁移到 Rspack | 配置大体兼容,速度提升大 | 部分插件需要验证 |
| 迁移到 Vite | 开发体验最好 | 迁移成本高,见[迁移场景](../../vite/scenarios/webpack-to-vite.md) |
## 易错点
- 没有度量就开始优化,改了很多却不知道哪项有效。
- 持久化缓存没有配置 `buildDependencies`,改了配置却用了旧缓存。
- 把所有第三方库打成一个巨大的 vendor,任何依赖升级都让整个文件缓存失效。
- 只优化一次,没有预算和 CI 检查,很快退化。
## 面试怎么讲
> “先度量:用速度分析和产物分析找到瓶颈,主要是 babel 处理了 node_modules 和一个整包引入的图表库。然后开启持久化缓存并在 CI 中缓存、换成 swc 类 loader、类型检查并行;体积上做路由懒加载、图表库按需引入、按变化频率拆包。最后在 CI 加体积预算防止退化。数据以实际测量为准,我会给出优化前后的对比。”