人人都会AI编程

23.3 打包体积分析:rollup-plugin-visualizer /webpack-bundle-analyzer

更新时间:2026-07-11

当你完成了功能开发,决定上线之前,需要问一个实在的问题:用户下载的 JS 文件到底有多大?里面塞了什么? 肉眼翻 dist 目录只能看到一堆哈希文件名,真正要定位体积瓶颈,必须借助打包体积分析工具

对于 Vue 项目,目前主流构建工具是 Vite(底层用 Rollup)Webpack,它们各有对应的可视化分析插件。

rollup-plugin-visualizer(Vite / Rollup 项目)

Vite 生产构建基于 Rollup,rollup-plugin-visualizer 可以将打包产物的模块组成生成一个可交互的 HTML 图表,帮你快速揪出哪些模块占了最大体积。

1. 安装与配置

npm install rollup-plugin-visualizer --save-dev

vite.config.js 中引入并启用,建议仅在需要分析时开启,避免拖慢常规构建:

import { defineConfig } from 'vite'
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    // 其他插件...
    visualizer({
      open: true,           // 构建完成后自动在浏览器打开报告
      filename: 'stats.html', // 报告输出的文件名
      gzipSize: true,       // 显示 gzip 压缩后的大小
      brotliSize: true,     // 显示 brotli 压缩后的大小
    })
  ]
})

运行 npm run build 后,项目根目录会生成 stats.html,浏览器打开后你看到类似这样的结构:

  • 三种视图模式:树状图(Treemap)、列表(List)、网络图(Network)。通常用树状图,它像磁盘占用图一样,用面积表示模块体积。
  • 颜色标识:不同颜色的方块对应不同的包,比如 node_modules 下的第三方库、你自己的 src 源码。
  • 交互操作:点击方块可以下钻查看该模块内部组成,快速定位具体是哪个文件/函数过大。

2. 从报告中锁定体积大户

打开报告后,最常见的问题是某个第三方库被打包进去了,且体积远超预期。例如:

  • 发现 moment.js 占了几百 KB,可以考虑换成 dayjs 或者使用 moment 的按需加载 locale 配置。
  • lodash 整个引入会导致几百 KB 增加,应改为 import { debounce } from 'lodash' 或直接使用 lodash-es 实现 Tree Shaking。
  • UI 组件库(如 Element Plus)若没有按需引入,会全量打入,可通过 unplugin-vue-components 实现自动按需引入。

3. 定位自己的业务代码膨胀

有时候体积大户不是 node_modules 而是你自己的代码。例如:

  • 一个 Vue 组件里 import 了一张未被压缩的 PNG,该图片被 inlined 成 Base64 打入 JS。
  • 某个 data.js 文件里硬编码了超大 JSON 数据(比如全国省市区列表)。
  • 重复打包:同一个模块被多个入口引用而未做代码分割。

当发现这些问题后,就可以针对性地优化:图片改用外链或压缩,数据拆分成懒加载 JSON,将公共模块提取为 chunk。

webpack-bundle-analyzer(Webpack 项目)

如果你的项目还在用 Webpack(如基于 Vue CLI 搭建),webpack-bundle-analyzer 是事实标准。它同样提供交互式可视化报告。

1. 安装与配置

npm install webpack-bundle-analyzer --save-dev

vue.config.js 中通过 chainWebpack 配置,或直接修改 webpack.config.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = {
  chainWebpack: config => {
    if (process.env.ANALYZE) {  // 通过环境变量按需启动
      config.plugin('webpack-bundle-analyzer')
        .use(BundleAnalyzerPlugin, [{ 
          analyzerMode: 'static',
          reportFilename: 'bundle-report.html' 
        }])
    }
  }
}

package.json 中添加脚本,方便调起:

"scripts": {
  "analyze": "cross-env ANALYZE=true npm run build"
}

运行后,报告会展示每个包的体积信息,而且支持查看经过代码压缩(minified)和 gzip 压缩后的大小,这更接近用户实际下载的尺寸。

2. 分析报告的关键动作

  • 筛出重复模块:当同一库的不同版本被打进不同 chunk 时,报告会以红色标记,提示存在重复。比如 core-js 的多个版本,或 moment 的 locale 资源被多次打包,需要统一版本或剔除非必要资源。
  • 查看代码分割结果:确认路由懒加载是否生效。如果所有路由组件都集中在一个巨大的 chunk 中,说明动态 import() 未正确配置,应立即修正。
  • 评估异步 chunk 大小:单个 chunk 太大(例如超过 500KB)影响加载时间,可考虑进一步拆分路由或组件。

3. 使用分析结果驱动优化

拿到报告后,优化路径非常清晰:

| 问题现象 | 常见解决方案 |
|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| 某第三方库全量引入 | 替换为更小替代品(如 dayjs 替代 moment),或配置 Tree Shaking,或使用按需引入插件 |
| 图片/字体被打包进 JS | 将较大的静态资源改为单独文件,并使用 CDN 或 S3 分发,不在 JS 中内联 |
| 多个 chunk 包含同样模块 | 在 Webpack 中配置 splitChunks.cacheGroups 提取公共依赖;在 Vite 中通过 build.rollupOptions.output.manualChunks 手工划分 |
| 首屏入口 chunk 过大 | 检查是否把所有组件都同步 import 了;使用异步组件(defineAsyncComponent)或路由懒加载,配合 Suspense |
| 源码中某个无用 import 被打包 | 结合 Tree Shaking 检查是否有副作用 (side effects);在 package.json 中声明 "sideEffects": false,确保无副作用文件可被安全删除 |

实际使用建议

  1. 纳入构建流程,但按需开启:分析插件会拖慢构建速度,平时开发时不要常驻。可以在 package.json 中增加 build:analyze 脚本,需要时跑一次。
  2. 关注 gzip 大小而非原始大小:用户下载的往往是 CDN 自动提供的 gzip 或 brotli 压缩文件,尽量将压缩后的大小作为判断标准。一般单文件 gzip 控制在 100KB 以内较为理想。
  3. 定期执行分析:项目迭代过程中,很容易不小心引入大依赖。建议在每个大版本发布前跑一次分析,尽早发现并解决体积膨胀。
  4. 结合懒加载与预加载:通过分析确认哪些 chunk 可以延迟加载后,还可以使用 <link rel="prefetch">preload 提示浏览器在空闲时预取可能需要的资源,进一步优化加载体验。

这两个工具是性能排查链的起点:能看见,才能优化。当你习惯在每次重大更新后看一眼打包报告,很多体积问题都会在萌芽阶段被解决,而不是等用户反馈“白屏太久了”才回过头去抓包。