打包产物分析与体积优化
场景
项目打包后体积过大(如 JS 超过 1MB),需要分析产物组成并优化。
分析思路
第一步:可视化分析产物
Webpack
npx webpack-bundle-analyzer stats.json
# 生成 stats.json
npx webpack --profile --json > stats.json
Vite(rollup-plugin-visualizer)
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
visualizer({
open: true,
gzipSize: true,
}),
],
});
第二步:常见体积问题与优化
| 问题 | 排查方式 | 优化手段 |
|---|---|---|
| 整个 lodash 被打包 | Analyzer 中看 lodash 大小 | lodash-es + Tree Shaking 或按路径导入 |
| moment.js locale 全量 | 看 locale 文件夹大小 | 替换为 dayjs 或 IgnorePlugin |
| 大型 UI 库全量引入 | 看 antd/element 大小 | 按需导入 + babel-plugin-import |
| 未使用的代码 | Coverage 面板 | 代码分割 + 懒加载 |
| 重复依赖 | Analyzer 中出现多次 | pnpm dedupe / resolutions |
| 未压缩 | 看 gzip 和原始大小差异 | 开启 gzip/brotli 压缩 |
| Source Map 泄露 | 生产包含 .map 文件 | 生产环境不上传 source map |
按需导入示例
// ❌ 全量 — 打包整个 antd
import { Button, Table } from 'antd';
// ✅ 使用 Tree Shaking 友好的 ESM 版本
// antd v5 默认支持 Tree Shaking,确认 sideEffects 配置正确
替换重量级库
// ❌ moment.js: ~300KB
import moment from 'moment';
// ✅ dayjs: ~2KB
import dayjs from 'dayjs';
体积预算
CI 中检查包大小
// bundlesize 配置
// package.json
{
"bundlesize": [
{ "path": "dist/js/main.*.js", "maxSize": "150 kB" },
{ "path": "dist/js/vendor.*.js", "maxSize": "300 kB" }
]
}
常见面试问题
Q1: 你一般怎么分析打包产物?
答案:
- 使用
webpack-bundle-analyzer或rollup-plugin-visualizer可视化查看 - 关注最大的几个模块,检查是否有全量引入、重复依赖
- 用
source-map-explorer查看具体文件占比 - 在 CI 中设置体积预算,超出自动告警
Q2: Tree Shaking 失效的常见原因?
答案:
- 使用了 CommonJS(
require)而非 ESM(import) package.json的sideEffects配置不当- 动态导入路径(
import(variable))无法静态分析 - 代码中有副作用(如顶层 IIFE、全局变量赋值)
- Babel 把 ESM 转成了 CommonJS(检查 Babel 配置
modules: false)