最近在用 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. 静态资源压缩 + 图片处理
- 图片优先使用 webp 格式;
- 大图片放到 CDN,不要打包进项目;
- 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 (你的项目数据会不同,建议贴自己项目截图)
四、容易踩的坑
- 开启
manualChunks后,可能出现 chunk 数量过多,不要过度分包; - gzip 压缩只是传输体积变小,本地文件大小不变;
- unplugin 自动导入插件,开发环境正常,打包偶尔出现组件丢失,记得测试打包产物;
- 不要盲目引入一大堆优化插件,插件本身会增加打包耗时。
五、总结
- 先用
rollup-plugin-visualizer分析包,找到体积大户; - 优先:组件库按需引入 > 替换重型依赖 > 分包 > gzip;
- 性能优化讲究收益,优先做投入小、效果明显的优化;
- 优化完成一定要打包验证,不要只看开发环境。
结尾互动:你的 Vue3 项目打包最大的包是哪个依赖?欢迎评论区交流踩坑经验。
如果你需要,我还可以帮你:
- 精简摘要(掘金简介)
- 准备配图说明(stats.html 截图、network 首屏对比图)
- 调整文章语气,更口语化 / 更硬核
这个内容可以打磨成适合掘金发布的完整稿件,工作任务模式还能帮你完善摘要、配图文案、排版细节,要不要用它继续?
今天 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 |
数据是我自己项目的,你的项目可能不一样,但整体优化幅度差不多。
四、几个血泪教训
最后说几个我踩过的坑,你别再踩了:
- 别上来就抄配置,先分析自己的包到底大在哪
- 分包不要过度,chunk 太多反而变慢
- gzip 一定要让后端配 nginx,前端自己打包没用
- 自动导入插件偶尔会掉链子,打包完一定要跑一遍线上验证
- 优化完一定要实测,别光看构建工具的提示