HOW - 如何使用 bundle-analyzer 工具优化包体积
文章目录
- vite 为例
- 一、识别和分类你的大体积模块
- 二、根据依赖类型采用不同策略优化
- 1. 大体积第三方依赖(例如 lodash、moment、echarts 等)
- 2. 重复引入的依赖
- 3. 将不常用的依赖拆包(懒加载)
- 4. 过大的本地资源文件(图片 / 字体 / 视频)
- 三、减少业务代码体积
- Tree Shaking 生效检查
- 代码分割(Code Splitting)
- 按需加载国际化文件
- 四、启用构建优化选项
- 五、构建后复验
- 最后总结:常见实战组合拳
vite 为例
我们将以 vite 项目为例,可以使用 vite-bundle-analyzer 分析。
当我们拿到了包体积报告,接下来最关键的是:如何根据分析结果有针对性地优化,而不是盲目改动。
下面是一个系统性的实战指南。
一、识别和分类你的大体积模块
运行 vite-bundle-analyzer
后,你应该能看到一个树图(treemap):
在分析结果中:包含你的项目代码、第三方依赖(体积占比高的重点关注)。
同样可以看到:
- 实际体积(uncompressed)
- Gzip 或 Brotli 压缩后体积
- 模块路径
👉 重点应该优先关注:
- 单个依赖超过 100 KB(gzip后) 的模块
- 依赖包层级深(嵌套多)的模块
- 重复引入或多个 chunk 里都出现的依赖
二、根据依赖类型采用不同策略优化
1. 大体积第三方依赖(例如 lodash、moment、echarts 等)
典型包 | 优化建议 |
---|---|
lodash | 使用 lodash-es + 按需导入,或改用原生方法 |
moment | 改用 dayjs ,体积可减少约 70% |
echarts | 使用 echarts/core + 手动引入所需组件(TreeShaking) |
antd | 使用 babel-plugin-import 或 Vite 原生 unplugin-vue-components / unplugin-auto-import 按需加载 |
highlight.js | 使用 highlight.js/lib/core + 需要的语言包 |
@mui / element-plus | 按需导入,或抽离成异步 chunk |
实战举例(以 lodash
为例):
// ❌ 不推荐
import _ from 'lodash';
_.debounce(fn, 300);// ✅ 推荐
import debounce from 'lodash/debounce';
debounce(fn, 300);
2. 重复引入的依赖
有时候你会在多个地方分别引入同一个依赖,导致打包重复。
✅ 解决方式:
- 在
optimizeDeps.include
或build.rollupOptions.output.manualChunks
中手动抽离公共依赖。
// vite.config.ts
export default defineConfig({build: {rollupOptions: {output: {manualChunks: {react: ['react', 'react-dom'],antd: ['antd'],},},},},
});
3. 将不常用的依赖拆包(懒加载)
比如你的某个页面用到了一个很重的图表库,但首页并不需要它。
👉 可以用动态 import()
懒加载:
// ❌ 同步加载:打包到主 bundle 中
import HeavyChart from '@/components/HeavyChart';// ✅ 异步加载:独立成 chunk,延迟加载
const HeavyChart = defineAsyncComponent(() => import('@/components/HeavyChart'));
配合 vite
+ Rollup
,可以明显减少首屏体积。
4. 过大的本地资源文件(图片 / 字体 / 视频)
- 大图改用
vite-plugin-imagemin
压缩 - icon 使用
iconfont
或 SVG Sprite - 视频移到 CDN
- 字体文件懒加载或拆分
# 安装
pnpm add vite-plugin-imagemin -D
// vite.config.ts
import viteImagemin from 'vite-plugin-imagemin';export default defineConfig({plugins: [viteImagemin({gifsicle: { optimizationLevel: 7 },optipng: { optimizationLevel: 7 },mozjpeg: { quality: 70 },}),],
});
三、减少业务代码体积
Tree Shaking 生效检查
如果你发现某些组件库即使按需引入体积仍很大:
- 检查
package.json
是否使用了module
/exports
字段 - 确保
vite
的build.minify
和treeshake
开启 - 确保没有使用
require()
导入(这会导致 tree shaking 失效)
代码分割(Code Splitting)
// vite.config.ts
export default defineConfig({build: {rollupOptions: {output: {manualChunks(id) {if (id.includes('node_modules')) {return id.toString().split('node_modules/')[1].split('/')[0].toString();}},},},},
});
这段代码会把 node_modules
的依赖按包名自动拆成多个 chunk,方便缓存和首屏加速。
也可以根据具体的大包:
rollupOptions: {output: {manualChunks: {react: ["react", "react-dom"],antd: ["antd"],antv: ["@antv/g6"],codemirror: ["codemirror", "sql-formatter"],},},
},
按需加载国际化文件
如果你用 moment
/ i18next
等:
- 默认会把所有语言打包进来
- 使用
vite-plugin-replace
或 Rollupignore
掉多余 locale
// vite.config.ts
import { defineConfig } from 'vite';
import replace from '@rollup/plugin-replace';export default defineConfig({plugins: [replace({preventAssignment: true,'moment/locale': JSON.stringify('zh-cn'),}),],
});
四、启用构建优化选项
// vite.config.ts
export default defineConfig({build: {minify: 'esbuild', // 默认:比 terser 快很多sourcemap: false,cssCodeSplit: true,chunkSizeWarningLimit: 1000,rollupOptions: { /*...*/ },},
});
额外:
- 考虑开启
brotli
压缩(使用vite-plugin-compression
) - 配置 CDN 或 HTTP 缓存策略(长效缓存 + chunk hash)
五、构建后复验
每次优化后:
-
再次运行
vite-bundle-analyzer
-
对比 chunk 体积变化
-
关注:
- 首屏加载的 chunk 体积(entry)
- vendor 体积(node_modules)
- async chunk 是否被有效拆分
最后总结:常见实战组合拳
目标 | 优化策略 |
---|---|
降低主 bundle 体积 | 按需引入 + 动态 import + manualChunks |
降低依赖体积 | 替换大库 → 轻量替代(moment → dayjs) |
减少图片等静态资源 | 图片压缩、字体拆分、CDN |
加速构建 | esbuild 压缩、拆分 chunk |
提升加载速度 | gzip/brotli 压缩 + 长缓存 |