Vue打包优化

最近在用 Vue3 + Vite 开发后台项目,打包后 dist 包体积很大,首屏白屏时间长。 打开浏览器 Network,发现几个大的 chunk 文件拖慢加载速度。网上很多优化文章零散,很多方案在实际业务里踩坑。

一、先定位:怎么看打包后的文件大小

优化不能瞎调,第一步先分析包构成。

Vite 插件 rollup-plugin-visualizer

安装:

sql 复制代码
npm install rollup-plugin-visualizer -D

vite.config.ts 配置

arduino 复制代码
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
  plugins: [
    visualizer({
      open: true, // 打包完成自动打开分析页面
      filename: 'dist/stats.html'
    })
  ]
})

打包执行 npm run build,自动弹出可视化图表,可以直观看到:哪个依赖体积最大,比如 moment、大图标库、第三方 SDK。

✅ 重点:优先优化体积占比最大的依赖,收益最高。

二、优化方案(按收益从高到低排序)

1. 依赖按需引入(收益最高)

场景:项目引入 Vant / Element Plus 等组件库,很多人直接全量引入,体积爆炸。 以 Vant4 举例: ❌ 不好写法(全量引入)

javascript 复制代码
import Vant from 'vant'
app.use(Vant)

✅ 按需引入 + 自动导入插件

arduino 复制代码
npm install unplugin-vue-components unplugin-auto-import -D

vite.config.ts

javascript 复制代码
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'
plugins: [
  AutoImport({ imports: ['vue'] }),
  Components({
    resolvers: [VantResolver()]
  })
]

好处:代码里直接使用 <van-button>,不用手动 import,打包只打包用到的组件。

2. 替换重型依赖,剔除无用库

常见坑:

  • moment 体积大,推荐替换成 dayjs(API 基本一致,体积小很多)
  • 大型图标库,不要一次性引入全部图标,按需引入图标
  • 一些只在开发环境使用的包,放到 devDependencies,避免打入生产包

3. 静态资源压缩 + 图片处理

  1. 图片优先使用 webp 格式;
  2. 大图片放到 CDN,不要打包进项目;
  3. vite 配置资源打包限制:小于阈值图片转为 base64,减少 http 请求
yaml 复制代码
build: {
  assetsInlineLimit: 4 * 1024 // 4kb以下图片转base64
}

4. 代码分割(分包策略)

Vite/Rollup 默认分包,但是第三方大依赖可以手动拆分,避免全部打包到单个 chunk。

css 复制代码
build: {
  rollupOptions: {
    output: {
      manualChunks: {
        vue: ['vue'],
        vant: ['vant']
      }
    }
  }
}

作用:vue、vant 单独拆成独立 js,浏览器缓存,后续版本更新不会重复加载这部分代码。

5. 开启 Gzip 压缩(服务器端,非常有效)

打包生成 .gz 文件,nginx 开启 gzip_static。 安装插件 vite-plugin-compression

复制代码
npm install vite-plugin-compression -D
css 复制代码
import { createCompression } from 'vite-plugin-compression'
plugins: [
  createCompression({
    threshold: 1024 * 10 // 大于10kb的文件才生成gz
  })
]

⚠️ 注意:光前端打包 gz 没用,后端 /nginx 必须配置开启 gzip 才能生效。

6. 移除 console、debugger(生产环境)

vite 生产打包默认移除,但保险起见可以显式配置

yaml 复制代码
build: {
  minify: 'terser',
  terserOptions: {
    compress: {
      drop_console: true,
      drop_debugger: true
    }
  }
}

三、优化前后对比示例

优化前:dist 总大小 2.6MB,首屏加载 3.2s 优化后:dist 总大小 900KB,首屏加载 800ms (你的项目数据会不同,建议贴自己项目截图)

四、容易踩的坑

  1. 开启 manualChunks 后,可能出现 chunk 数量过多,不要过度分包;
  2. gzip 压缩只是传输体积变小,本地文件大小不变;
  3. unplugin 自动导入插件,开发环境正常,打包偶尔出现组件丢失,记得测试打包产物;
  4. 不要盲目引入一大堆优化插件,插件本身会增加打包耗时。

五、总结

  1. 先用 rollup-plugin-visualizer 分析包,找到体积大户;
  2. 优先:组件库按需引入 > 替换重型依赖 > 分包 > gzip;
  3. 性能优化讲究收益,优先做投入小、效果明显的优化;
  4. 优化完成一定要打包验证,不要只看开发环境。

结尾互动:你的 Vue3 项目打包最大的包是哪个依赖?欢迎评论区交流踩坑经验。


如果你需要,我还可以帮你:

  1. 精简摘要(掘金简介)
  2. 准备配图说明(stats.html 截图、network 首屏对比图)
  3. 调整文章语气,更口语化 / 更硬核

这个内容可以打磨成适合掘金发布的完整稿件,工作任务模式还能帮你完善摘要、配图文案、排版细节,要不要用它继续?

今天 17:05

3

好,那我把这篇文章调整成更口语化、更有掘金味儿的版本 ------ 去掉生硬的 "教科书感",加点实战吐槽和个人踩坑体感,读起来更像一个老前端在跟你唠嗑。


Vue3 项目打包优化实战:把 2.6MB 压到 900KB,首屏从 3s 干到 800ms

开篇

说真的,之前一直觉得打包优化是大佬才需要操心的事。

直到上次上线后老板在群里发了一张截图: "咱们这个后台怎么白屏这么久?" 旁边还配了个问号表情。我当场社死。

打开 Network 一看,好家伙,光一个 js chunk 就干了快 1.5MB,首屏加载 3 秒多。那一瞬间我意识到:这活逃不掉了。

这篇就记录一下我是怎么从 "啥也不懂" 一步步优化过来的,全是踩过的坑,你照着做基本能解决大部分问题。


一、别瞎优化,先看看包到底大在哪

很多人一上来就抄别人的 vite.config 配置,结果优化了半天,体积没降多少,打包还变慢了。

正确姿势:先分析,再动手。

装个 rollup-plugin-visualizer,打包完直接给你一张可视化的 "饼图",谁大谁小一目了然:

sql 复制代码
npm install rollup-plugin-visualizer -D
arduino 复制代码
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    visualizer({
      open: true, // 打包完自动打开
      filename: 'dist/stats.html'
    })
  ]
})

跑一下 npm run build,浏览器自动弹出一张图,你会看到类似这样的东西:

  • 哦原来 moment.js 占了这么大一块?
  • 我就用了个按钮组件,怎么把整个组件库都打进来了?
  • 这个图标库怎么全打进来了?

找到体积大户,再针对性优化,这才是聪明的做法。


二、优化手段(按效果从大到小排)

1. 组件库按需引入 ------ 这步省的最多

我之前图省事,直接全量引入 Vant:

javascript 复制代码
// 这样写体积直接爆炸
import Vant from 'vant'
app.use(Vant)

后来才知道,用 unplugin-vue-components 可以自动按需引入,你代码里写了什么组件,它就打什么组件,一个多余的都不会带。

arduino 复制代码
npm install unplugin-vue-components unplugin-auto-import -D
javascript 复制代码
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    AutoImport({ imports: ['vue'] }),
    Components({
      resolvers: [VantResolver()]
    })
  ]
})

配置完之后,你在业务代码里直接用 <van-button> 就行,连 import 都不用写,爽得很。

⚠️ 坑提醒:自动导入虽然爽,但有时候打包完会出现 "组件找不到" 的问题,大概率是某个组件没有走 resolver,这时候手动 import 一下就行。


2. 把 "胖子" 依赖换掉

分析完包你会发现,有些依赖体积大得离谱,而且功能还重复。

典型例子:moment → dayjs

moment 整个库 200KB+,而 dayjs 只有 2KB,API 几乎一模一样,迁移成本极低。

复制代码
npm install dayjs

把 import moment from 'moment' 换成 import dayjs from 'dayjs',90% 的场景都能直接用。

还有图标库,别一次性把所有图标都 import 进来,用到哪个引哪个,或者用 SVG Sprite 方案。


3. 静态资源该扔 CDN 就扔 CDN

图片、字体文件这些静态资源,千万别打包进项目里。

  • 大图片传 CDN,项目里直接引用 URL
  • 小图片(<4KB)转 base64,省一个 HTTP 请求:
yaml 复制代码
// vite.config.ts
build: {
  assetsInlineLimit: 4 * 1024 // 4kb 以下转 base64
}

图片能压缩就压缩,能转 webp 就转 webp,一张图省个几十 KB 很正常。


4. 分包策略:把不常变的东西单独拆出来

Vite 默认会自动分包,但你可以手动把大依赖单独拆出来,利用浏览器缓存。

比如 vue、vant 这些东西,你几个月都不会更新一次,单独打个 chunk,用户浏览器缓存住,下次打开直接用。

css 复制代码
build: {
  rollupOptions: {
    output: {
      manualChunks: {
        vue: ['vue'],
        vant: ['vant']
      }
    }
  }
}

⚠️ 注意:分包不是越多越好。chunk 太多了反而会增加 HTTP 请求数量,适得其反。我一般就拆 3~5 个大 chunk 就够了。


5. Gzip 压缩 ------ 传输体积直接砍 70%

这一步是服务器层面的优化,但效果立竿见影。

前端先装个插件,打包的时候自动生成 .gz 压缩文件:

复制代码
npm install vite-plugin-compression -D
css 复制代码
import { createCompression } from 'vite-plugin-compression'

plugins: [
  createCompression({
    threshold: 1024 * 10 // 大于 10KB 的文件才压缩
  })
]

然后重点来了:光前端打包 gz 文件没用,必须让后端 /nginx 配置开启 gzip 传输,否则浏览器根本不会用这个压缩文件。

nginx 配置大概长这样:

bash 复制代码
gzip on;
gzip_static on;
gzip_types text/css application/javascript application/json;

我当时就是忘了配 nginx,折腾了半天以为没生效,差点没把键盘砸了。


6. 生产环境干掉 console 和 debugger

这个简单,Vite 生产构建默认会帮你干掉,但保险起见可以显式配一下:

yaml 复制代码
build: {
  minify: 'terser',
  terserOptions: {
    compress: {
      drop_console: true,
      drop_debugger: true
    }
  }
}

三、优化完的效果

我项目优化前的数据:

表格

指标 优化前 优化后
dist 总体积 2.6MB ~900KB
首屏加载 3.2s ~800ms
最大单 chunk 1.5MB ~300KB

数据是我自己项目的,你的项目可能不一样,但整体优化幅度差不多。


四、几个血泪教训

最后说几个我踩过的坑,你别再踩了:

  1. 别上来就抄配置,先分析自己的包到底大在哪
  2. 分包不要过度,chunk 太多反而变慢
  3. gzip 一定要让后端配 nginx,前端自己打包没用
  4. 自动导入插件偶尔会掉链子,打包完一定要跑一遍线上验证
  5. 优化完一定要实测,别光看构建工具的提示
相关推荐
卸任11 小时前
Vibe coding工具使用心得
前端·ai编程
brien912 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance12 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M12 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写12 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李12 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易12 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马12 小时前
前沿视界
前端
kyriewen13 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易13 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员