Vite 配置与优化进阶指南
Vite 深度配置、性能优化与最佳实践 | 更新时间:2026-05
目录
核心配置
1. 基础配置
typescript
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
// 项目根目录
root: process.cwd(),
// 开发服务器配置
server: {
host: '0.0.0.0', // 监听所有地址
port: 3000,
open: true, // 自动打开浏览器
cors: true, // 允许跨域
// 代理配置
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
},
// HMR 配置
hmr: {
overlay: true // 错误覆盖层
}
},
// 预览服务器配置
preview: {
port: 4173,
host: '0.0.0.0'
},
// 路径别名
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@assets': path.resolve(__dirname, 'src/assets')
},
// 导入时想要省略的扩展名列表
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
// CSS 配置
css: {
// CSS 预处理器配置
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
},
less: {
modifyVars: {
'primary-color': '#1890ff'
},
javascriptEnabled: true
}
},
// CSS Modules 配置
modules: {
localsConvention: 'camelCase',
scopeBehaviour: 'local',
generateScopedName: '[name]__[local]___[hash:base64:5]'
},
// PostCSS 配置
postcss: {
plugins: [
require('autoprefixer'),
require('postcss-preset-env')({
stage: 3,
features: {
'nesting-rules': true
}
})
]
}
},
// 插件配置
plugins: [
vue()
],
// 构建配置
build: {
target: 'es2015',
outDir: 'dist',
assetsDir: 'assets',
rollupOptions: {
output: {
assetFileNames: '[ext]/[name]-[hash].[ext]'
}
},
// 压缩配置(推荐 esbuild,比 terser 快 20-40 倍,输出仅大 1-2%)
minify: 'esbuild', // 如需更高压缩率可使用 'terser',但构建速度会显著下降
// 分块大小警告限制
chunkSizeWarningLimit: 1000
},
// 依赖优化
optimizeDeps: {
include: ['vue', 'vue-router', 'pinia'],
exclude: ['your-local-package']
}
})2. 环境变量配置
bash
# .env
VITE_APP_TITLE=My App
# .env.development
VITE_API_BASE_URL=http://localhost:8080
VITE_APP_ENV=development
# .env.production
VITE_API_BASE_URL=https://api.example.com
VITE_APP_ENV=productiontypescript
// 使用环境变量
console.log(import.meta.env.VITE_API_BASE_URL)
console.log(import.meta.env.MODE) // 'development' | 'production'
console.log(import.meta.env.DEV) // boolean
console.log(import.meta.env.PROD) // boolean
// 类型声明
// env.d.ts
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string
readonly VITE_APP_TITLE: string
readonly VITE_APP_ENV: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}性能优化
1. 依赖预构建优化
typescript
// vite.config.ts
export default defineConfig({
optimizeDeps: {
// 强制预构建
include: [
'vue',
'vue-router',
'pinia',
'axios',
'lodash-es'
],
// 排除预构建
exclude: [
'your-local-package'
],
// 自定义 esbuild 配置
esbuildOptions: {
target: 'es2020',
supported: {
'top-level-await': true
}
}
}
})2. 代码分割优化
typescript
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// 将 node_modules 中的代码单独打包
if (id.includes('node_modules')) {
// 提取大型库
if (id.includes('element-plus')) {
return 'element-plus'
}
if (id.includes('echarts')) {
return 'echarts'
}
if (id.includes('@vue')) {
return 'vue-vendor'
}
// 其他 node_modules 代码
return 'vendor'
}
// 按路由分割
if (id.includes('src/views')) {
const match = /src\/views\/(.+)\//.exec(id)
if (match) {
return `view-${match[1]}`
}
}
}
}
}
}
})3. 图片优化
typescript
// 推荐:使用 unplugin-imagemin 替代已停维的 vite-plugin-imagemin
import imagemin from 'unplugin-imagemin/vite'
export default defineConfig({
plugins: [
imagemin({
// 默认使用 sharp,无需安装系统依赖
// 支持 WebP、AVIF 等现代格式自动转换
})
]
})4. Gzip 压缩
typescript
// vite.config.ts
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
viteCompression({
verbose: true,
disable: false,
threshold: 10240, // 大于 10KB 才压缩
algorithm: 'gzip',
ext: '.gz',
deleteOriginFile: false
})
]
})5. CDN 加速
typescript
// vite.config.ts
import { Plugin as importToCDN } from 'vite-plugin-cdn-import'
export default defineConfig({
plugins: [
importToCDN({
modules: [
{
name: 'vue',
var: 'Vue',
path: 'https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js'
},
{
name: 'vue-router',
var: 'VueRouter',
path: 'https://cdn.jsdelivr.net/npm/vue-router@4.2.4/dist/vue-router.global.prod.js'
}
]
})
]
})6. 构建分析
typescript
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
filename: 'dist/stats.html'
})
]
})插件开发
1. 基础插件结构
typescript
// my-plugin.ts
import { Plugin } from 'vite'
export default function myPlugin(): Plugin {
return {
name: 'my-plugin',
// 应用模式
apply: 'build', // 'serve' | 'build' | (config, env) => boolean
// 配置解析前调用
config(config, env) {
return {
// 返回部分配置(会与现有配置合并)
}
},
// 配置解析后调用
configResolved(resolvedConfig) {
// 存储最终解析的配置
},
// 配置开发服务器
configureServer(server) {
server.middlewares.use((req, res, next) => {
// 自定义中间件
next()
})
},
// 转换 index.html
transformIndexHtml(html) {
return html.replace(
/<title>(.*?)<\/title>/,
`<title>My App</title>`
)
},
// 自定义模块解析
resolveId(source) {
if (source === 'virtual-module') {
return source
}
},
// 加载自定义模块
load(id) {
if (id === 'virtual-module') {
return 'export default "This is virtual!"'
}
},
// 转换模块代码
transform(code, id) {
if (id.endsWith('.vue')) {
// 转换 Vue 文件
return {
code: transformedCode,
map: null
}
}
},
// 构建结束时调用
buildEnd() {
// 清理工作
}
}
}2. 实战:自动导入插件
typescript
// auto-import-plugin.ts
import { Plugin } from 'vite'
import MagicString from 'magic-string'
export default function autoImportPlugin(): Plugin {
const imports = new Map([
['ref', 'vue'],
['reactive', 'vue'],
['computed', 'vue'],
['watch', 'vue']
])
return {
name: 'auto-import',
transform(code, id) {
if (!id.endsWith('.vue') && !id.endsWith('.ts')) {
return null
}
const s = new MagicString(code)
const usedImports = new Set<string>()
// 检测使用的 API
imports.forEach((source, name) => {
const regex = new RegExp(`\\b${name}\\b`, 'g')
if (regex.test(code)) {
usedImports.add(name)
}
})
// 生成导入语句
if (usedImports.size > 0) {
const importStatement = `import { ${Array.from(usedImports).join(', ')} } from 'vue';\n`
s.prepend(importStatement)
}
return {
code: s.toString(),
map: s.generateMap({ hires: true })
}
}
}
}3. 实战:Markdown 插件
typescript
// markdown-plugin.ts
import { Plugin } from 'vite'
import MarkdownIt from 'markdown-it'
export default function markdownPlugin(): Plugin {
const md = new MarkdownIt()
return {
name: 'markdown',
// 处理 .md 文件
transform(code, id) {
if (!id.endsWith('.md')) {
return null
}
const html = md.render(code)
return {
code: `export default ${JSON.stringify(html)}`,
map: null
}
}
}
}
// 使用
import content from './README.md'
console.log(content) // HTML 字符串生产构建优化
1. 完整的生产配置
typescript
// vite.config.prod.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import viteCompression from 'vite-plugin-compression'
import { visualizer } from 'rollup-plugin-visualizer'
// ⚠️ vite-plugin-imagemin 已停止维护,推荐使用 unplugin-imagemin
// import imagemin from 'unplugin-imagemin/vite'
export default defineConfig({
mode: 'production',
build: {
target: 'es2015',
outDir: 'dist',
assetsDir: 'assets',
assetsInlineLimit: 4096,
cssCodeSplit: true,
sourcemap: false,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'ui-vendor': ['element-plus'],
'utils': ['lodash-es', 'dayjs', 'axios']
},
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.')
let extType = info[info.length - 1]
if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/i.test(assetInfo.name)) {
extType = 'media'
} else if (/\.(png|jpe?g|gif|svg|ico|webp)(\?.*)?$/i.test(assetInfo.name)) {
extType = 'img'
} else if (/\.(woff2?|eot|ttf|otf)(\?.*)?$/i.test(assetInfo.name)) {
extType = 'fonts'
}
return `${extType}/[name]-[hash].[ext]`
}
}
},
minify: 'esbuild', // 推荐 esbuild(默认值),比 terser 快 20-40 倍
// 如需更高压缩率,可切换为 terser(但构建速度会显著下降)
// minify: 'terser',
// terserOptions: {
// compress: {
// drop_console: true,
// drop_debugger: true,
// pure_funcs: ['console.log']
// },
// format: {
// comments: false
// }
// },
chunkSizeWarningLimit: 1000,
reportCompressedSize: false // 禁用 gzip 压缩大小报告
},
plugins: [
vue(),
// Gzip 压缩
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz'
}),
// Brotli 压缩
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'brotliCompress',
ext: '.br'
}),
// 图片压缩(已改用 unplugin-imagemin)
// imagemin({
// // 默认使用 sharp,无需安装系统依赖
// }),
// 构建分析
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
filename: 'dist/stats.html'
})
]
})2. 多页面应用配置
typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
admin: resolve(__dirname, 'admin/index.html'),
mobile: resolve(__dirname, 'mobile/index.html')
}
}
}
})3. Library 模式
typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'MyLib',
fileName: (format) => `my-lib.${format}.js`,
formats: ['es', 'cjs', 'umd']
},
rollupOptions: {
// 确保外部化处理那些你不想打包进库的依赖
external: ['vue'],
output: {
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
globals: {
vue: 'Vue'
}
}
}
}
})常见问题
1. 解决 CommonJS 依赖问题
typescript
// vite.config.ts
export default defineConfig({
optimizeDeps: {
include: ['problematic-package']
},
build: {
commonjsOptions: {
include: [/problematic-package/, /node_modules/]
}
}
})2. 解决路径别名问题
typescript
// vite.config.ts
import { defineConfig } from 'vite'
import path from 'path'
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'~': path.resolve(__dirname, 'node_modules')
}
}
})
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"~/*": ["node_modules/*"]
}
}
}3. 解决动态导入问题
typescript
// 使用 import.meta.glob
const modules = import.meta.glob('./modules/*.ts')
// 懒加载
const modules = import.meta.glob('./modules/*.ts', { eager: false })
// 直接导入
const modules = import.meta.glob('./modules/*.ts', { eager: true })
// 自定义导入
const modules = import.meta.glob('./modules/*.ts', {
import: 'setup',
eager: true
})4. 解决环境变量类型问题
typescript
// env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_BASE_URL: string
readonly VITE_APP_TITLE: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}5. 解决 HMR 问题
typescript
// 接受自身更新
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// 更新逻辑
})
}
// 接受依赖更新
if (import.meta.hot) {
import.meta.hot.accept('./dep.js', (newDep) => {
// 更新逻辑
})
}
// 处理更新失败
if (import.meta.hot) {
import.meta.hot.dispose(() => {
// 清理副作用
})
}最佳实践
1. 开发环境优化
typescript
// vite.config.ts
export default defineConfig({
server: {
// 预热常用文件
warmup: {
clientFiles: [
'./src/components/**/*.vue',
'./src/utils/**/*.ts'
]
}
},
optimizeDeps: {
// 强制预构建
include: ['vue', 'vue-router', 'pinia']
}
})2. 生产环境优化
typescript
// vite.config.ts
export default defineConfig({
build: {
// 禁用 CSS 代码分割(如果 CSS 很小)
cssCodeSplit: false,
// 启用 CSS 压缩
cssMinify: true,
// 禁用 brotli 压缩大小报告(加快构建)
reportCompressedSize: false
}
})3. 性能监控
typescript
// vite.config.ts
export default defineConfig({
plugins: [
{
name: 'performance-monitor',
buildStart() {
this.startTime = Date.now()
},
buildEnd() {
console.log(`Build time: ${Date.now() - this.startTime}ms`)
}
}
]
})参考资料
最新知识补充(2024-2026)
1. Vite 6 Environment API
Vite 6(2024 年 11 月发布)引入了 Environment API,允许在单个 Vite Dev Server 中配置多个运行时环境(如客户端 + SSR),实现更灵活的模块处理。
typescript
// vite.config.ts - Environment API 示例
import { defineConfig } from 'vite'
export default defineConfig({
environments: {
client: {
// 客户端环境配置
build: {
outDir: 'dist/client',
},
},
ssr: {
// SSR 环境配置
build: {
outDir: 'dist/ssr',
},
},
},
})2. Rolldown:Vite 8 的统一打包器
Rolldown(基于 Rust 开发)已在 Vite 8(2026.03)中正式成为默认打包器,替代了原来的 esbuild(开发)+ Rollup(生产)双引擎架构:
- 与 Rollup API 兼容,大多数插件无需修改
- 开发和生产共享同一打包器,消除行为差异
- 构建速度比 Rollup 快 10-30 倍
typescript
// Vite 8 直接升级即可,现有 rollupOptions 配置兼容 Rolldown
// 插件中可检测是否运行在 Rolldown 模式:
export default defineConfig({
build: {
rollupOptions: { /* 现有配置无需修改 */ },
},
})
// 插件中检测 Rolldown
function myPlugin() {
return {
name: 'my-plugin',
buildStart() {
if (this.meta.rolldownVersion) {
// 运行在 Rolldown 模式(Vite 8+)
}
}
}
}3. Lightning CSS 替代 PostCSS
Vite 5.4+ 支持 css.lightningcss 选项,使用 Rust 编写的 Lightning CSS 替代 PostCSS 进行 CSS 转换,性能大幅提升:
typescript
// vite.config.ts
import lightningcss from 'lightningcss'
export default defineConfig({
css: {
transformer: 'lightningcss',
lightningcss: {
// CSS 目标浏览器
targets: lightningcss.browserslistToTargets(['> 0.2%', 'not dead']),
},
},
build: {
cssMinify: 'lightningcss', // 使用 Lightning CSS 压缩
},
})4. 压缩工具对比
| 工具 | 构建速度 | 输出大小 | 说明 |
|---|---|---|---|
| esbuild | 极快(基准) | 较大 1-2% | Vite 默认,推荐大多数场景 |
| terser | 慢 20-40 倍 | 最小 | 需极致压缩时使用 |
| Lightning CSS | 极快 | 与 esbuild 相当 | 仅 CSS 压缩,Vite 5.4+ |
5. vite-plugin-imagemin 已停止维护
vite-plugin-imagemin 依赖系统级工具(gifsicle、optipng 等),安装时常出错且已停止维护。
推荐替代:
- unplugin-imagemin:基于 sharp,无需系统依赖,跨平台兼容
- vite-plugin-static-copy + 外部压缩:CI 中单独处理图片
6. Vite 7 过渡版本(2025 年 6 月 - 2026 年 1 月)
Vite 7 是 Vite 6 到 Vite 8 之间的过渡版本,主要变化:
- Node.js 20+ 为最低要求
- Environment API 进一步完善
- 为 Rolldown 集成做准备
- 生命周期较短,已被 Vite 8 替代
7. Vite 8 — Rolldown 统一打包器(2026 年 3 月)
Vite 8 是自 Vite 2 以来最重大的架构变更。
Vite 8(2026 年 3 月发布)将 Rolldown 作为唯一的统一打包器,替代了此前 esbuild(开发)+ Rollup(生产)的双打包器架构:
核心变化:
- 统一打包管线:开发和生产共享同一个 Rust 打包器,消除了长期存在的行为差异
- 极快的构建速度:比 Rollup 快 10-30 倍,与 esbuild 性能持平
- 插件兼容:Rolldown 支持 Rollup/Vite 插件 API,大多数现有插件无需修改即可使用
- 兼容层:Vite 8 内置兼容层,自动转换
esbuild和rollupOptions配置 - Node.js 20.19+ / 22.12+ 为最低要求
typescript
// 检测是否运行在 Rolldown 模式(Vite 8+)
function versionCheckPlugin(): Plugin {
return {
name: 'version-check',
buildStart() {
if (this.meta.rolldownVersion) {
// Rolldown 模式下的特定逻辑
} else {
// Rollup 模式下的逻辑
}
},
}
}迁移建议:
- 大多数项目可直接升级,Vite 8 内置兼容层自动处理配置转换
- 大型/复杂项目建议先在 Vite 7 上使用
rolldown-vite包测试,再升级到 Vite 8 - 这样可以更容易区分问题是来自 Vite 本身还是 Rolldown