Appearance
Vite 打包 Vue3 生产项目体积优化完整指南
更新: 6/28/2026 字数: 0 字 时长: 0 分钟

体积优化的收益排序很明确:先砍掉根本不该打进来的大依赖,再做按需加载切分首屏,最后压榨压缩和细节。 下面按收益从高到低排列,每项给出配置、原理、适用场景和坑。所有配置基于 Vite 5/6 + Vue 3 正式版,构建器为 Rollup。
预期压缩比例是经验区间,实际收益取决于项目现状——重依赖、未做分包的项目收益偏上限,已优化过的项目收益偏下限。
优先级一:依赖瘦身(预期减 30%~60%,收益最高)
体积问题八成出在依赖上。先解决这块,性价比远高于抠配置。
1.1 按需引入组件库与工具库
配置代码(以 Element Plus + lodash 为例):
ts
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
AutoImport({ resolvers: [ElementPlusResolver()] }),
Components({ resolvers: [ElementPlusResolver()] }),
],
})lodash 改用按方法引入或换 lodash-es:
ts
// ❌ 全量引入,整包 70KB+
import _ from 'lodash'
// ✅ 按需,只打进用到的方法
import debounce from 'lodash-es/debounce'生效原理:组件库全量引入会把所有组件和样式打进 bundle,按需引入让 Tree-shaking 只保留实际用到的部分。lodash-es 是 ESM 版本,支持 Tree-shaking,而 CommonJS 版 lodash 无法摇树。
适用场景:任何用了 Element Plus / Ant Design Vue / lodash / moment 这类大库的项目,几乎必做。
注意事项:moment 体积巨大且无法摇树,建议直接换成 day.js(约 2KB),收益立竿见影。
1.2 用更轻的替代品
排查 package.json 里的重量级依赖,能换则换:
moment→dayjsecharts全量 →echarts/core+ 按需引入图表和组件- 完整
axios在简单场景可考虑原生fetch
生效原理:从源头减少打进来的代码量,比任何后置压缩都有效。
注意事项:替换涉及 API 改动,评估改造成本,做好回归测试。
优先级二:代码分割与懒加载(预期首屏减 20%~40%)

这类优化不一定减小总体积,但显著降低首屏加载体积,对用户感知最直接。
2.1 路由懒加载
配置代码:
ts
const routes = [
// ✅ 动态 import,每个路由独立 chunk,按需加载
{ path: '/dashboard', component: () => import('@/views/Dashboard.vue') },
{ path: '/settings', component: () => import('@/views/Settings.vue') },
]生效原理:动态 import() 是 Vite/Rollup 的代码分割触发点,每个被动态引入的模块会被打成独立 chunk,只在访问对应路由时才加载。
适用场景:所有多路由 SPA,是性价比最高的首屏优化。
2.2 大组件 / 重依赖异步化
ts
import { defineAsyncComponent } from 'vue'
// 富文本编辑器、图表、地图等重组件按需加载
const HeavyEditor = defineAsyncComponent(() => import('@/components/HeavyEditor.vue'))适用场景:编辑器、图表、PDF 预览等使用频率低但体积大的组件。
2.3 手动分包 manualChunks
配置代码:
ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vue: ['vue', 'vue-router', 'pinia'],
echarts: ['echarts'],
},
},
},
},
})生效原理:把稳定的第三方依赖拆成独立 chunk,与业务代码分离。业务代码频繁变更,依赖很少变——分开后用户只需重新下载变动的业务 chunk,依赖 chunk 命中长期缓存。
注意事项:分包不是越碎越好。过度拆分会增加 HTTP 请求数和 chunk 间公共代码重复。优先按"变更频率"和"体积"分组,别为拆而拆。
优先级三:Tree-shaking 与压缩(预期再减 15%~30%)

3.1 生产构建压缩(默认已开,确认配置)
Vite 生产构建默认用 esbuild 压缩,速度快。要更极致的体积可换 terser:
ts
export default defineConfig({
build: {
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // 移除 console
drop_debugger: true, // 移除 debugger
},
},
},
})生效原理:minify 做变量名压缩、空白删除、死代码消除。drop_console 在生产环境清掉调试日志,既减体积又避免信息泄露。
注意事项:terser 比 esbuild 压得更小但构建更慢,按需取舍。drop_console 会清掉所有 console,确认没有依赖 console 输出的逻辑。
3.2 Gzip / Brotli 预压缩
配置代码:
ts
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
viteCompression({ algorithm: 'gzip' }),
viteCompression({ algorithm: 'brotliCompress', ext: '.br' }),
],
})生效原理:构建时预生成 .gz/.br 文件,服务器直接下发压缩产物,省去运行时压缩开销。Brotli 压缩率通常比 Gzip 高 15%~20%。
适用场景:传输体积优化的关键一步。注意事项:需要 Nginx 等服务端配合开启对应支持(gzip_static on / Brotli 模块),否则预压缩文件不生效。
3.3 确保 Tree-shaking 生效
注意事项:Tree-shaking 依赖 ESM 静态结构。避免引入纯 CommonJS 库、避免有副作用的全量导入。第三方库的 package.json 里 sideEffects: false 标记能帮助摇树,自己的工具库也建议正确标注。
优先级四:静态资源优化(预期减 5%~20%)
4.1 图片压缩与格式转换
ts
import viteImagemin from 'vite-plugin-imagemin'
// 构建时压缩 png/jpg/svg;优先用 WebP/AVIF 格式小图片(< 4KB)Vite 默认转 base64 内联,减少请求;大图保持外链并压缩。
4.2 SVG 雪碧图 / 按需引入
图标用 vite-plugin-svg-icons 做雪碧图,避免每个图标一个请求或全量打包图标库。
4.3 控制资源内联阈值
ts
build: {
assetsInlineLimit: 4096, // 小于 4KB 的资源内联为 base64
}注意事项:内联阈值调太大反而会让 JS chunk 膨胀、丢失缓存优势,保持默认 4KB 附近即可。
优先级五:构建配置细节(预期减 0%~10%)
5.1 关闭生产环境 sourcemap
ts
build: { sourcemap: false } // 生产默认即 false,确认别误开sourcemap 文件很大,生产环境若不需要线上调试就关闭(或用 hidden 只上传错误监控平台)。
5.2 设置合理的浏览器目标
ts
build: { target: 'es2015' } // 目标越新,polyfill 越少,体积越小注意事项:target 要匹配实际用户的浏览器范围。定太新老浏览器报错,定太旧 polyfill 冗余,按用户画像权衡。
5.3 移除未使用的 CSS
配合 vite-plugin-purgecss 或 UnoCSS 的按需生成,清理未使用的样式。注意事项:PurgeCSS 容易误删动态拼接的类名,配好白名单并充分测试。
打包体积分析与结果验证

优化前先量化现状,优化后再对比验证,否则全凭感觉。
用 visualizer 看体积构成
ts
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
visualizer({ open: true, gzipSize: true, brotliSize: true }),
],
})构建后生成 treemap 可视化报告,方块大小直观反映每个依赖的体积占比。先看哪个方块最大,就先优化谁——这是定位问题的第一手段。
验证流程
- 优化前:跑一次
vite build,记录dist总体积、各 chunk 体积、gzip 后体积,并保存 visualizer 报告。 - 逐项优化:每做一项改动单独构建,对比体积变化,确认收益和没引入功能问题。
- 优化后:对比首屏加载的 chunk 总和(不是 dist 总和——懒加载会让 dist 总量不变但首屏变小)。
- 真实环境验证:用 Chrome DevTools 的 Network 面板,在生产构建下看首屏实际传输体积(Transferred,即 gzip/brotli 后的大小)和加载瀑布流,这才是用户真正下载的量。
关键提醒:体积优化要看首屏传输体积,而非 dist 目录总大小。代码分割让总量不降反升都有可能,但首屏体积明显下降,用户体验才是真改善了。
优化方案速览(按收益排序)
| 优先级 | 优化项 | 预期收益 | 关键手段 |
|---|---|---|---|
| 一 | 依赖瘦身 | 30%~60% | 按需引入、换轻量库、moment→dayjs |
| 二 | 代码分割懒加载 | 首屏 20%~40% | 路由懒加载、异步组件、manualChunks |
| 三 | Tree-shaking + 压缩 | 15%~30% | terser、Gzip/Brotli、ESM 摇树 |
| 四 | 静态资源优化 | 5%~20% | 图片压缩、WebP、SVG 雪碧图 |
| 五 | 构建配置细节 | 0%~10% | 关 sourcemap、target、清 CSS |
执行顺序建议:先 visualizer 量化现状 → 砍依赖 → 切分懒加载 → 配压缩 → 抠资源和细节 → 再次 visualizer 对比验证。