Appearance
Vite 最佳实践
本章总结了使用 Vite 进行项目开发的最佳实践,涵盖了配置优化、性能提升、开发工作流等多个方面。
项目结构
推荐的项目结构
my-vite-project/
├── index.html # 主 HTML 文件
├── package.json
├── vite.config.js # Vite 配置文件
├── .env* # 环境变量文件
├── public/ # 静态资源(不经过构建处理)
│ ├── favicon.ico
│ └── robots.txt
└── src/ # 源代码目录
├── assets/ # 静态资源(经过构建处理)
│ ├── images/
│ ├── icons/
│ └── styles/
├── components/ # 组件
├── composables/ # Vue 组合函数或 React Hooks
├── utils/ # 工具函数
├── composables/ # 可复用逻辑
├── views/ # 页面视图
├── router/ # 路由配置
├── store/ # 状态管理
├── styles/ # 全局样式
├── types/ # TypeScript 类型定义
├── main.js # 应用入口
└── App.vue # 根组件
配置优化
基础配置
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
// 基础路径(部署到子路径时使用)
base: './',
// 源码目录
root: '.',
// 构建配置
build: {
outDir: 'dist',
assetsDir: 'assets',
minify: 'esbuild',
sourcemap: false,
},
// 路径别名
resolve: {
alias: {
'@': resolve(__dirname, './src'),
'@assets': resolve(__dirname, './src/assets'),
'@components': resolve(__dirname, './src/components'),
'@utils': resolve(__dirname, './src/utils'),
}
},
// 插件
plugins: [vue()],
// 开发服务器配置
server: {
port: 3000,
open: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
环境特定配置
javascript
// vite.config.js
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig(({ mode }) => {
// 加载环境变量
const env = loadEnv(mode, process.cwd(), '')
return {
base: env.VITE_BASE_URL || './',
define: {
__APP_ENV__: env.APP_ENV
},
server: {
port: parseInt(env.VITE_PORT) || 3000,
proxy: {
'/api': {
target: env.VITE_API_URL || 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
}
})
性能优化
依赖预构建优化
javascript
// vite.config.js
export default {
optimizeDeps: {
include: [
'vue',
'vue-router',
'pinia',
'axios',
'lodash-es'
],
exclude: [
'heavy-server-lib' // 排除仅服务端使用的库
]
}
}
代码分割
javascript
// 动态导入实现代码分割
// 路由级代码分割
const routes = [
{
path: '/',
component: () => import('./views/Home.vue')
},
{
path: '/about',
component: () => import('./views/About.vue')
}
]
// 组件级代码分割
const LazyComponent = defineAsyncComponent(() =>
import('./components/HeavyComponent.vue')
)
// 库的代码分割
const loadChart = async () => {
const { Chart } = await import('chart.js')
return Chart
}
构建优化
javascript
// vite.config.js
export default {
build: {
rollupOptions: {
output: {
manualChunks: {
// 分离框架代码
'vue': ['vue', 'vue-router'],
// 分离工具库
'utils': ['lodash-es', 'axios'],
// 分离 UI 库
'ui': ['element-plus', '@vueuse/core']
},
// 自定义文件名
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
}
},
// 启用压缩
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
}
}
开发工作流
环境变量管理
text
# .env.development
VITE_API_URL=http://localhost:3000/api
VITE_APP_ENV=development
VITE_DEBUG=true
# .env.production
VITE_API_URL=https://api.myapp.com
VITE_APP_ENV=production
VITE_DEBUG=false
# .env.local (git 忽略)
VITE_API_URL=http://local-api:4000
VITE_CUSTOM_FEATURE=true
TypeScript 配置
json
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
/* 路径映射 */
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@assets/*": ["src/assets/*"],
"@components/*": ["src/components/*"]
}
},
"include": ["src"]
}
ESLint 和 Prettier 集成
javascript
// .eslintrc.cjs
module.exports = {
root: true,
env: {
node: true,
'vue/setup-compiler-macros': true
},
extends: [
'plugin:vue/vue3-essential',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier'
],
rules: {
// 自定义规则
}
}
json
// .prettierrc
{
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 80,
"trailingComma": "es5"
}
资源管理
静态资源处理
javascript
// 推荐的资源组织方式
// 图像资源 - 使用导入或 public 目录
import logo from '@/assets/logo.png' // 小图像,会被优化
const bgImage = '/images/background.jpg' // 大图像,放在 public
// SVG 图标处理
// 作为组件导入
import IconHome from '@/assets/icons/home.svg'
// 作为 URL 使用
import iconUrl from '@/assets/icons/menu.svg?url'
CSS 优化
css
/* 使用 CSS 变量便于主题切换 */
:root {
--color-primary: #007bff;
--color-secondary: #6c757d;
--border-radius: 4px;
}
/* 启用 CSS 代码分割 */
/* styles/global.css */
@import './variables.css';
@import './mixins.css';
/* 组件样式 */
/* components/Button.css */
.component-button {
border-radius: var(--border-radius);
background: var(--color-primary);
}
测试配置
单元测试配置
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig(({ mode }) => {
const isTest = mode === 'test'
return {
plugins: [vue()],
test: isTest ? {
environment: 'jsdom',
setupFiles: ['./tests/setup.js'],
include: ['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}']
} : {},
resolve: {
alias: isTest ? {
'@': resolve(__dirname, './src'),
... // 测试专用别名
} : {
'@': resolve(__dirname, './src')
}
}
}
})
部署优化
生产构建配置
javascript
// vite.config.js
export default {
build: {
// 启用子资源完整性
sourcemap: false, // 生产环境关闭 sourcemap
cssTarget: 'chrome61', // CSS 兼容目标
rollupOptions: {
output: {
// 预加载策略
format: 'es',
// 文件大小优化
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('vue')) {
return 'vendor-vue'
}
if (id.includes('chart') || id.includes('d3')) {
return 'charts'
}
return 'vendor'
}
}
}
}
},
// 静态资源优化
assetsInclude: [
// 根据需要包含额外的资源类型
]
}
预览服务器配置
javascript
// package.json
{
"scripts": {
"preview": "vite preview --port 4173",
"preview:debug": "vite preview --port 4173 --strict-port"
}
}
调试和监控
性能监控
javascript
// 性能监控插件示例
// plugins/performance.js
export default function performancePlugin() {
return {
name: 'performance',
configResolved(config) {
if (config.command === 'build') {
const start = Date.now()
this.load = () => {
console.log(`构建耗时: ${Date.now() - start}ms`)
}
}
}
}
}
错误处理
javascript
// 全局错误处理
// main.js
if (import.meta.env.DEV) {
// 开发环境错误处理
window.addEventListener('error', (e) => {
console.error('Runtime Error:', e.error)
})
window.addEventListener('unhandledrejection', (e) => {
console.error('Unhandled Promise Rejection:', e.reason)
})
}
常见陷阱和解决方案
1. 环境变量问题
javascript
// ❌ 错误 - 直接使用 process.env
const apiUrl = process.env.API_URL // 不会在客户端生效
// ✅ 正确 - 使用 import.meta.env
const apiUrl = import.meta.env.VITE_API_URL
2. 路径问题
javascript
// ❌ 错误 - 相对路径在不同页面可能失效
img.src = './assets/image.png'
// ✅ 正确 - 使用导入或绝对路径
import imgUrl from '@/assets/image.png'
img.src = imgUrl
3. 动态导入优化
javascript
// 避免过于动态的导入
// ❌ 这样无法进行预构建
const module = await import(userInput)
// ✅ 预先定义可能的导入
const modules = {
'chart': () => import('./charts/Chart.js'),
'table': () => import('./tables/Table.js')
}
const loadModule = async (type) => {
const factory = modules[type]
return factory ? factory() : null
}
项目维护
依赖管理
json
// package.json - 使用精确版本控制
{
"dependencies": {
"vue": "^3.3.0",
"vue-router": "^4.2.0"
},
"devDependencies": {
"vite": "^4.4.0",
"@vitejs/plugin-vue": "^4.2.0"
}
}
Git 配置
text
# .gitignore
node_modules/
dist/
.vite/
.env.local
coverage/
*.log
通过遵循这些最佳实践,您可以构建出高性能、可维护的 Vite 项目,同时享受快速的开发体验。