问题来源:在被问到如何进行打包优化时候,常常会大脑一时宕机,特地找到一些资料去了解一些打包的优化方式。
概要
Vue3 + Vite 打包优化核心要点:
- 体积优化:开启压缩 / 混淆、利用 Tree Shaking、移除无用代码;
- 拆包优化:第三方依赖分包 + 路由懒加载,减少首屏加载体积;
- 资源优化:图片压缩 / 格式转换、CSS 抽离,降低静态资源体积;
- 速度优化:禁用生产环境 sourcemap、优化依赖预构建,提升打包速度。
这些策略可根据项目规模灵活调整,小型项目只需基础优化(压缩、Tree Shaking),中大型项目需配合拆包、CDN 进一步提升性能。
一、基础体积优化(核心)
1. 开启压缩与混淆
Vite 内置了压缩能力,无需额外安装插件,直接在配置中开启即可减小打包体积。
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
// 开启代码混淆(生产环境默认开启,可显式配置)
minify: 'terser', // 替代默认的 esbuild,压缩效果更好
terserOptions: {
compress: {
drop_console: true, // 移除 console.log
drop_debugger: true // 移除 debugger
}
},
// 开启 gzip 压缩(需配合服务器开启 gzip)
reportCompressedSize: true
}
})
2. Tree Shaking 深度优化
Vite 天生支持 Tree Shaking:
前提条件:确保代码符合ESM 规范, 避免无效代码被打包**(基于编译型确认依赖关系)**
错误条件:CommonJS 是基于运行时确认依赖关系,不适合
-
优先使用 ESM 格式的依赖(如
lodash-es替代lodash):javascript// 推荐(只打包用到的 debounce 方法) import { debounce } from 'lodash-es' // 不推荐(打包整个 lodash) import _ from 'lodash' -
避免在
setup中定义未使用的变量 / 方法:javascript<script setup> // 未使用的变量会被 Tree Shaking 移除 const unusedVar = 123 // 打包时会被删除 const handleClick = () => { /* 业务逻辑 */ } // 用到则保留 </script>
3.vite-plugin-compression :给打包文件 "瘦身"(生成压缩包)
核心作用
这个插件的核心是在 Vite 打包时,自动为静态资源(JS/CSS/HTML)生成 Gzip/Brotli 压缩包,配合服务器端的压缩配置,让浏览器加载更小的文件,提升网络加载速度。
为什么需要它?
- 手动生成压缩包效率低,插件可自动化完成;
- Gzip/Brotli 压缩能让文件体积减少 60%-80%(比如 1MB 的 JS 文件压缩后可能只有 200KB);
- 服务器可直接返回压缩包,无需实时压缩(节省服务器资源)。
实战配置 & 使用步骤
1. 安装
bash
npm i vite-plugin-compression -D
# 或
yarn add vite-plugin-compression -D
2. 配置(vite.config.ts)
javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
vue(),
// 开启压缩
viteCompression({
verbose: true, // 打印压缩结果
disable: false, // 是否禁用
threshold: 10240, // 文件大于 10KB 才压缩(太小的文件压缩收益低)
algorithm: 'gzip', // 压缩算法:gzip/brotliCompress
ext: '.gz', // 压缩包后缀
// 可选:同时生成 Brotli 压缩包(比 Gzip 压缩率更高)
// algorithm: 'brotliCompress',
// ext: '.br'
})
]
})
3. 打包效果

执行 npm run build 后,dist 目录下会多出 .gz 后缀的压缩文件:

4. 服务器配合(关键)
生成压缩包后,需要配置 Nginx/Apache 让服务器优先返回压缩包:
# Nginx 配置示例
http {
gzip_static on; # 开启静态压缩包读取
gzip_types text/plain text/css application/javascript application/json;
}
适用场景
- 中大型项目(静态资源体积大,压缩收益明显);
- 追求极致加载速度的场景(如官网、电商首页);
- 服务器性能有限,不想实时压缩的场景。
打包结果:

4.rollup-plugin-visualizer:打包体积 "体检仪"(分析体积占比)
核心作用
这个插件的核心是生成可视化的打包体积分析报告,以图表(饼图 / 树形图)形式展示:
- 每个依赖 / 模块占总打包体积的比例;
- 哪些文件体积过大(比如某个第三方库占了 50% 体积);
- 有无冗余代码 / 重复依赖。
为什么需要它?
- 优化打包体积的前提是找到问题,这个插件能精准定位 "体积大头";
- 面试中可体现你 "有数据支撑的优化思路",而非盲目优化;
- 避免无用依赖 / 重复依赖占用体积(比如同时引入 lodash 和 lodash-es)。
实战配置 & 使用步骤
1. 安装
npm i rollup-plugin-visualizer -D
# 或
yarn add rollup-plugin-visualizer -D
2. 配置(vite.config.ts)
javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
vue(),
// 体积分析插件
visualizer({
open: true, // 打包后自动打开报告页面
filename: 'stats.html', // 报告文件名称(生成在 dist 目录)
gzipSize: true, // 显示 Gzip 压缩后的体积
brotliSize: true, // 显示 Brotli 压缩后的体积
})
]
})
3. 使用效果
执行 npm run build 后:
- 自动生成
dist/stats.html文件; - 自动打开浏览器,展示可视化报告(示例效果):
- 饼图:不同模块的体积占比(比如 element-plus 占 30%,vue 占 15%);
- 树形图:可展开查看每个文件的具体体积;
- 能看到哪些依赖是 "冗余" 的(比如重复引入的工具库)。
适用场景
- 打包体积过大,想定位问题时;
- 优化前后对比(比如优化后看体积是否下降);
- 排查 "为什么打包后有 2MB" 这类问题;
- 面试中展示 "数据驱动的优化思路"。
二、拆包优化(解决单文件体积过大)
1. 拆分第三方依赖(vendor 分包)
将 Vue、Element Plus 等第三方库单独打包,利用浏览器缓存:
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { splitVendorChunkPlugin } from 'vite'
export default defineConfig({
plugins: [
vue(),
// 自动拆分第三方依赖为独立 chunk
splitVendorChunkPlugin()
],
// 分包配置
build: {
rollupOptions: {
output: {
manualChunks: {
// 基础框架:Vue 全家桶
vue: ['vue', 'vue-router', 'pinia'],
// UI 组件库:Element Plus
ui: ['element-plus'],
// 时间工具:dayjs(单独拆,体积小但常用)
utils: ['dayjs'],
// 可视化:echarts(体积大,必须单独拆!)
echarts: ['echarts']
},
// 静态资源哈希配置(保留你的原有配置)
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
assetFileNames: '[ext]/[name]-[hash].[ext]'
}
}
}
})
2. 路由懒加载(页面级拆包)
目的:减少主包大小,只有在用到组件的时候再去加载,提升性能。
结合 Vue Router 实现路由懒加载,只加载当前页面的代码:
javascript
import type { RouteRecordRaw } from 'vue-router'
import Dashboard from '@/views/dashboard/index.vue'
import UserCenter from '@/views/user-center/index.vue'
import UserDetail from '@/views/user-center/UserDetail.vue'
// 路由规则
const routes: RouteRecordRaw[] = [
{
path: '/',
redirect: '/dashboard'
},
{
path: '/dashboard',
name: 'Dashboard',
// component: () => import('@/views/dashboard/index.vue'),
component: Dashboard,
meta: {
title: '仪表盘'
}
},
{
path: '/user-center',
name: 'UserCenter',
// component: () => import('@/views/user-center/index.vue'),
component: UserCenter,
meta: {
title: '用户中心'
},
children: [
{
path: 'detail/:id',
name: 'UserDetail',
// component: () => import('@/views/user-center/UserDetail.vue'),
component: UserDetail,
meta: {
title: '用户详情'
}
}
]
}
]
export default routes
2.2.1 不采用懒加载,查看打包体积

2.2.2 采用懒加载,缩小主包体积

三、资源优化(图片 / 字体 / 样式)
1. 图片压缩与格式转换
使用 vite-plugin-imagemin 压缩图片,自动转换为 WebP/AVIF 格式:
bash
bash
# 安装依赖
npm i vite-plugin-imagemin -D
javascript
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import viteImagemin from 'vite-plugin-imagemin'
export default defineConfig({
plugins: [
vue(),
viteImagemin({
// 图片压缩配置
gifsicle: { optimizationLevel: 3 },
optipng: { optimizationLevel: 7 },
mozjpeg: { quality: 80 },
pngquant: { quality: [0.8, 0.9] },
// 自动转换为 WebP
webp: { quality: 80 }
})
],
// 配置图片小于 4kb 时转为 base64
build: {
assetsInlineLimit: 4096
}
})
2. CSS 抽离与压缩
Vite 自动抽离 CSS,但可配置优化:
javascript
javascript
// vite.config.js
export default defineConfig({
build: {
// 禁用 CSS 内联(抽离为单独文件)
cssCodeSplit: true,
// CSS 压缩(默认开启)
minify: true
},
// 配置 CSS 预处理器(减少冗余)
css: {
preprocessorOptions: {
scss: {
// 全局引入变量,避免重复导入
additionalData: '@import "@/styles/variables.scss";'
}
}
}
})
四、预构建优化(提升开发 / 打包速度)
1. 优化依赖预构建
Vite 会预构建 CommonJS 依赖为 ESM,可配置排除 / 包含特定依赖:
javascript
// vite.config.js
export default defineConfig({
optimizeDeps: {
// 强制预构建指定依赖
include: ['lodash-es', 'element-plus'],
// 排除不需要预构建的依赖
exclude: ['vue']
}
})
2. 禁用 sourcemap(生产环境)
2.1 sourcemap 核心是什么?
sourcemap 本质是一个映射文件(.map 后缀),它记录了「打包 / 压缩后的代码」和「原始源代码」之间的对应关系。
举个通俗的例子:
你写的源代码是这样的(清晰易读):
javascript
// src/main.js(原始代码)
const sayHello = () => {
console.log('Hello Vue3')
error() // 故意写个错误
}
sayHello()
经过 Vite 打包压缩后,代码变成了这样(一行式、变量名被混淆):
javascript
// dist/assets/main.abc123.js(打包后代码)
const a=()=>{console.log("Hello Vue3"),error()};a();
如果运行时报错,浏览器会提示「错误在 main.abc123.js 的第 1 行第 30 列」------ 你根本不知道对应原始代码的哪一行。
但如果开启了 sourcemap,浏览器会读取 .map 文件,直接告诉你:错误在 src/main.js 的第 4 行第 3 列,这就是 sourcemap 的核心价值。
2.2 sourcemap 什么时候用?
| 场景 | 是否开启 sourcemap | 原因 |
|---|---|---|
| 开发环境(npm run dev) | ✅ 必须开 | 方便调试代码、定位错误 |
| 生产环境(npm run build) | ❌ 建议关 | 1. 生成的 .map 文件会增大打包体积;2. 防止源码泄露(安全性);3. 提升打包速度 |
2.3 Vite 中如何配置 sourcemap?
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
// 生产环境禁用 sourcemap(核心优化点)
sourcemap: false,
// 开发环境 Vite 会默认开启 sourcemap,无需额外配置
},
// 也可单独配置开发环境的 sourcemap
server: {
sourcemap: true
}
})
2.4 sourcemap 的优缺点
优点:
- 调试时能直接定位到原始源代码的行号,大幅提升调试效率;
- 即使代码被压缩 / 混淆,也能清晰看到代码逻辑。
缺点:
- 生成 .map 文件会增加打包体积(比如 1MB 的 JS 会多出 2-3MB 的 .map 文件);
- 生产环境暴露 .map 文件可能导致源码泄露(攻击者可通过 .map 还原你的源代码);
- 增加打包时间(生成 .map 文件需要额外计算)。
总结
- sourcemap 是 "代码映射文件":关联打包后代码和原始源码,方便调试定位错误;
- 开发环境必开,生产环境必关:开发时提升调试效率,生产时减少体积、避免源码泄露;
- Vite 中通过
build.sourcemap配置:生产环境设为 false 是核心打包优化点。
3. 去除console和debugger
一、为什么要移除?
- 减少代码体积 :大量
console.log会增加 JS 文件体积(尤其是循环 / 高频函数里的日志); - 避免敏感信息泄露 :比如
console.log(token)console.log(用户信息)可能泄露隐私 / 业务数据; - 提升执行效率 :
console本身是同步操作,高频执行会轻微阻塞主线程; - 规范生产环境代码 :
debugger会强制中断代码执行,若不小心提交到生产环境会导致页面卡死。
二、Vite 中移除的两种方式(推荐第二种)
方式 1:手动删除(不推荐)
开发时写了日志,打包前逐行删除 ------ 效率低,容易漏删,不适合团队协作。
方式 2:自动移除(推荐,打包时自动清理)
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
// 生产环境禁用 sourcemap(核心优化点)
sourcemap: false,
// 开发环境 Vite 会默认开启 sourcemap,无需额外配置
},
// 也可单独配置开发环境的 sourcemap
server: {
sourcemap: true
},
// 配置 esbuild 移除 console/debugger
esbuild: {
drop: ['console', 'debugger'] // 核心配置!
},
})
三、验证是否生效
- 执行
npm run build打包; - 打开
dist目录下的 JS 文件,搜索console.log/debugger; - 若完全找不到,说明配置生效。
五、进阶优化(可选)
1. 使用 CDN 引入大型依赖
将 Vue、Element Plus 等通过 CDN 引入,不打包进项目:
javascript
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
// 配置外部依赖(不打包)
resolve: {
alias: {
'@': '/src'
}
},
build: {
rollupOptions: {
external: ['vue', 'element-plus'], // 排除外部依赖
output: {
// 配置全局变量(对应 CDN 引入的全局对象)
globals: {
vue: 'Vue',
'element-plus': 'ElementPlus'
}
}
}
}
})
然后在 index.html 中引入 CDN:
html
html
<!-- index.html -->
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/element-plus/dist/index.full.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus/dist/index.min.css">
</head>
2. 分析打包体积
使用 rollup-plugin-visualizer 分析打包体积,定位大文件:
bash
bash
# 安装依赖
npm i rollup-plugin-visualizer -D
javascript
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
vue(),
// 打包后生成体积分析报告(dist/stats.html)
visualizer({
open: true, // 自动打开报告
filename: 'stats.html'
})
]
})