性能优化
本章涵盖 Vite 项目的性能优化策略:开发体验优化和生产构建优化。
开发性能
依赖预构建优化
确保 Vite 预构建了所有需要预构建的依赖:
export default defineConfig({
optimizeDeps: {
// 添加动态引入的依赖
include: [
'lodash-es',
'dayjs',
'echarts', // 大型库
'some-deep-import/deep/module',
],
// 排除已经预构建好的或纯 ESM 的库
exclude: [
'your-pure-esm-lib',
],
},
})开发服务器启动时间很大程度上取决于预构建速度。include 列表中的包越多,首次启动越慢,但运行时请求更少。
预热(Warmup)
Vite 5.3+ 支持启动时预热:
export default defineConfig({
server: {
warmup: {
clientFiles: [
'./src/App.vue',
'./src/views/Home.vue',
'./src/views/Dashboard.vue',
],
},
},
})预热让频繁访问的大文件在服务器启动时就编译好,而不是等到浏览器首次请求时才编译。
⚡ 性能提示:预热 3-5 个最常访问的入口文件即可。不要预热所有文件——反而会拖慢启动速度。
排除大文件监听
export default defineConfig({
server: {
watch: {
ignored: [
'**/node_modules/**',
'**/dist/**',
'**/.git/**',
'**/coverage/**',
],
},
},
})HMR 性能诊断
// vite.config.js 中启用 HMR 日志
export default defineConfig({
server: {
hmr: {
// 打印 HMR 更新详情
// 开发时在控制台看到每个模块的更新耗时
},
},
})
// 也可通过插件诊断
import inspect from 'vite-plugin-inspect'
export default defineConfig({
plugins: [inspect()], // 访问 localhost:5173/__inspect
})构建性能
选择合适的压缩器
export default defineConfig(({ mode }) => ({
build: {
// 默认 esbuild:速度快,体积合理
minify: 'esbuild',
// 生产极致体积优化用 terser
// minify: 'terser',
// terserOptions: {
// compress: {
// drop_console: true, // 移除 console
// drop_debugger: true, // 移除 debugger
// pure_funcs: ['console.log'], // 移除特定函数调用
// },
// },
},
}))CSS 压缩
export default defineConfig({
build: {
cssMinify: 'lightningcss', // 比 esbuild 更快,压缩率更好
// cssMinify: 'esbuild', // 默认,也很快
},
})安装:npm i -D lightningcss
代码分割策略
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
// 分包:React/Vue 相关单独打包
'react-vendor': ['react', 'react-dom'],
'ui-vendor': ['antd'],
'utils-vendor': ['lodash', 'dayjs', 'axios'],
},
},
},
},
})分包原则
| 策略 | 说明 | 何时使用 |
|---|---|---|
| 按框架 | React/Vue 单独 chunk | 框架变更频率低,可利用浏览器缓存 |
| 按库体积 | 大库单独 chunk | 超过 50KB 的库单独打包 |
| 按页面 | 页面级 lazy import | SPA 路由懒加载 |
| 按频率 | 稳定库 vs 频繁变更的库 | 稳定库长期缓存 |
⚡ 性能提示:不要过度拆分!HTTP/1.1 限制同域名约 6 个并发连接。总 chunk 数建议控制在 20-30 个以内。HTTP/2 无此限制,但每个 chunk 仍有下载开销。
产物体积优化
分析构建产物
npm i -D rollup-plugin-visualizerimport { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
filename: 'dist/stats.html',
}),
],
})Tree Shaking 前提条件
Tree Shaking 依赖 ES Module 的静态结构。确保:
- 使用 ESM 导入:
import { foo } from 'pkg' - 库提供
"sideEffects": false在 package.json 中 - 避免副作用导入:不用
import 'pkg/global.css'式的裸导入(必要的全局样式除外)
// package.json
{
"sideEffects": [
"*.css",
"*.scss"
]
}按需导入大型库
// ❌ 全部导入(体积大)
import _ from 'lodash'
_.debounce(fn, 300)
// ✅ 按需导入
import debounce from 'lodash/debounce'
debounce(fn, 300)
// ✅ 或直接使用 lodash-es(天然 Tree Shakable)
import { debounce } from 'lodash-es'// ❌ Moment.js(不可 Tree Shaking,体积大)
import moment from 'moment'
// ✅ dayjs / date-fns(天然轻量 + Tree Shaking)
import dayjs from 'dayjs'
import { format } from 'date-fns'减少 Polyfill 体积
export default defineConfig({
build: {
target: 'es2020', // 现代浏览器,减少 transpile 体积
// target: 'es2015', // 如需兼容老旧浏览器
},
})target: 'modules'(默认)要求浏览器支持原生 ESM(Chrome 87+, Firefox 78+),此设置下几乎不需要额外 Polyfill。
图片优化
npm i -D vite-plugin-imageminimport viteImagemin from 'vite-plugin-imagemin'
export default defineConfig({
plugins: [
viteImagemin({
gifsicle: { optimizationLevel: 3 },
mozjpeg: { quality: 80 },
pngquant: { quality: [0.7, 0.8] },
svgo: { plugins: [{ removeViewBox: false }] },
}),
],
})加载性能
资源预加载 / 预连接
// vite.config.js
export default defineConfig({
build: {
modulePreload: {
polyfill: true, // 为不支持 modulepreload 的浏览器注入 polyfill
resolveDependencies: (url, deps, context) => deps,
},
},
})在 HTML 中手动添加:
<!-- 预连接到关键来源 -->
<link rel="preconnect" href="https://api.example.com" />
<link rel="dns-prefetch" href="https://cdn.example.com" />
<!-- 预加载关键资源 -->
<link rel="modulepreload" href="/assets/vendor.hash.js" />CSS 加载优化
// 关键 CSS 内联
// 对于首屏渲染必需的 CSS,可以通过插件内联到 HTML 中
npm i -D vite-plugin-critical开启 gzip / brotli
npm i -D vite-plugin-compressionimport compression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
compression({
algorithm: 'brotliCompress', // 比 gzip 小 20% 左右
ext: '.br',
threshold: 10240, // 大于 10KB 才压缩
}),
compression({
algorithm: 'gzip',
ext: '.gz',
}),
],
})💡 最佳实践:Vite 构建时不压缩,而是在部署环节由 Nginx / CDN 自动压缩。前提是你的 Nginx/CDN 配置了 gzip/brotli。否则用
vite-plugin-compression提前生成压缩文件。
打包体积检查清单
| 检查项 | 操作 |
|---|---|
| 是否未使用按需导入 | 检查导入语句,用 import { specific } from 'pkg' 替代 import * |
| 是否有未使用的依赖 | 运行 npx depcheck 或使用 knip |
| Moment.js | 替换为 dayjs 或 date-fns |
| Lodash 全量导入 | 改为 lodash-es + Tree Shaking 或 lodash/functionName |
| 大图标库全量导入 | 使用按需导入 @ant-design/icons/es |
| CSS-in-JS 运行时体积 | 考虑零运行时方案(Tailwind / CSS Modules) |
| target 过低导致过多 polyfill | 指定合适的 build.target |
| 重复依赖(不同版本) | 运行 npx npm-dedupe |
| Source Map 开启在生产 | 确保 build.sourcemap: false(或 'hidden') |
开发体验优化
快速重启
# 强制重新进行依赖预构建
vite --force
# 清除缓存后启动
rm -rf node_modules/.vite && vite减少插件负担
开发时仅加载必要的插件:
export default defineConfig(({ command }) => ({
plugins: [
// 核心插件始终加载
react(),
// 仅在构建时加载的插件
...(command === 'build' ? [visualizer(), compression()] : []),
],
}))浏览器性能
Vite 开发服务器使用 304 协商缓存。如果发现开发时浏览器卡顿,可以打开 DevTools 的 “Disable cache” 确认是否是缓存问题。
⚡ 性能提示:大型项目(500+ 模块)的开发启动依然很快(< 2s 冷启动)。如果变慢,检查
optimizeDeps.include是否配置合理,以及是否有大量不必要监听的 node_modules 目录。