1. Vite 基础概念
Vite 是一个现代化的前端构建工具,主要特点:
-
开发环境下使用原生 ES 模块导入
-
生产环境使用 Rollup 打包
-
快速的冷启动和热更新
-
开箱即用的各种优化
2. 项目创建和基础配置
# 创建项目
npm create vite@latest my-vue-app -- --template vue-ts
# 或者使用 yarn
yarn create vite my-vue-app --template vue-ts
# 支持的模板
# vanilla, vanilla-ts, vue, vue-ts, react, react-ts, preact, preact-ts, lit, lit-ts, svelte, svelte-ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
// 插件
plugins: [vue()],
// 解析配置
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'~': path.resolve(__dirname, 'node_modules')
},
extensions: ['.js', '.ts', '.jsx', '.tsx', '.json']
},
// 服务器配置
server: {
host: '0.0.0.0',
port: 3000,
open: true,
https: false,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
// 构建配置
build: {
target: 'es2015',
outDir: 'dist',
assetsDir: 'assets',
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
manualChunks: {
'vendor': ['vue', 'vue-router', 'pinia'],
'lodash': ['lodash-es']
}
}
}
}
})
3. 环境变量配置
# .env
VITE_APP_TITLE=My App
VITE_API_URL=http://api.example.com
# .env.development
VITE_APP_TITLE=Dev App
VITE_API_URL=http://dev-api.example.com
# .env.production
VITE_APP_TITLE=Prod App
VITE_API_URL=http://prod-api.example.com
// vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
readonly VITE_API_URL: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
4. 插件配置
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import legacy from '@vitejs/plugin-legacy'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
export default defineConfig({
plugins: [
vue(),
vueJsx(),
// 浏览器兼容性
legacy({
targets: ['ie >= 11'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime']
}),
// 自动导入
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
dts: 'src/auto-imports.d.ts',
resolvers: [ElementPlusResolver()]
}),
// 组件自动注册
Components({
dirs: ['src/components'],
extensions: ['vue'],
dts: 'src/components.d.ts',
resolvers: [
ElementPlusResolver(),
IconsResolver({
enabledCollections: ['ep']
})
]
}),
// 图标
Icons({
autoInstall: true
})
]
})
5. CSS 配置
// vite.config.ts
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `
@import "@/styles/variables.scss";
@import "@/styles/mixins.scss";
`
}
},
modules: {
localsConvention: 'camelCaseOnly',
scopeBehaviour: 'local',
generateScopedName: '[name]_[local]_[hash:base64:5]'
},
postcss: {
plugins: [
autoprefixer(),
postcssPresetEnv()
]
}
}
})
6. 优化配置
// vite.config.ts
export default defineConfig({
optimizeDeps: {
include: ['lodash-es', '@vueuse/core'],
exclude: ['vue-demi']
},
build: {
// 分块策略
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
}
}
},
// 压缩配置
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
// 文件大小警告限制
chunkSizeWarningLimit: 1500,
// 静态资源处理
assetsInlineLimit: 4096
}
})
7. 开发调试配置
// vite.config.ts
export default defineConfig({
server: {
host: true,
port: 3000,
open: true,
cors: true,
// 代理配置
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
},
// HMR 配置
hmr: {
overlay: true
}
}
})
8. 生产部署配置
// vite.config.ts
export default defineConfig({
base: process.env.NODE_ENV === 'production' ? '/my-app/' : '/',
build: {
// 生成静态资源的存放目录
assetsDir: 'static',
// 小于此阈值的导入或引用资源将内联为 base64 编码
assetsInlineLimit: 4096,
// 启用/禁用 CSS 代码拆分
cssCodeSplit: true,
// 构建后是否生成 source map 文件
sourcemap: false,
// 自定义底层的 Rollup 打包配置
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
nested: path.resolve(__dirname, 'nested/index.html')
},
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
}
}
}
})
9. 常见问题和解决方案
- 路径别名问题
// vite.config.ts
import path from 'path'
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
})
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
- 类型声明问题
// src/shims-vue.d.ts
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// src/shims-svg.d.ts
declare module '*.svg' {
const content: any
export default content
}
- HMR 问题
// vite.config.ts
export default defineConfig({
server: {
hmr: {
overlay: false,
timeout: 30000
}
}
})
10. 性能优化建议
- 依赖预构建
// vite.config.ts
export default defineConfig({
optimizeDeps: {
include: [
'vue',
'vue-router',
'pinia',
'@vueuse/core',
'lodash-es'
]
}
})
- 代码分割
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor': ['vue', 'vue-router', 'pinia'],
'utils': ['lodash-es', '@vueuse/core']
}
}
}
}
})
3. **资源压缩**
```typescript
// vite.config.ts
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz'
})
]
})
1. 高级插件配置
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import viteImagemin from 'vite-plugin-imagemin' // 图片压缩插件
import { visualizer } from 'rollup-plugin-visualizer' // 打包分析插件
import viteEslint from 'vite-plugin-eslint' // ESLint 插件
import viteMockServe from 'vite-plugin-mock' // Mock 数据插件
export default defineConfig({
plugins: [
vue(), // Vue 插件,处理 .vue 文件
// 图片压缩配置
viteImagemin({
// GIF 图片压缩配置
gifsicle: {
optimizationLevel: 7, // 压缩级别 1-7,7 压缩率最高
interlaced: false // 是否隔行扫描
},
// PNG 图片压缩配置
optipng: {
optimizationLevel: 7 // 压缩级别 0-7,7 压缩率最高
},
// JPEG 图片压缩配置
mozjpeg: {
quality: 70 // 压缩质量 0-100,值越小压缩率越高
},
// PNG 图片压缩配置(另一个压缩器)
pngquant: {
quality: [0.8, 0.9], // 压缩质量范围
speed: 4 // 压缩速度 1-11,1 最慢但压缩率最高
},
// SVG 图片压缩配置
svgo: {
plugins: [
{
name: 'removeViewBox' // 移除 viewBox 属性
},
{
name: 'removeEmptyAttrs', // 移除空属性
active: false // 禁用此插件
}
]
}
}),
// 打包分析配置
visualizer({
filename: './stats.html', // 分析报告输出路径
open: true, // 自动打开报告
gzipSize: true // 显示 gzip 后的大小
}),
// ESLint 配置
viteEslint({
// 指定需要检查的文件
include: ['src/**/*.ts', 'src/**/*.vue', 'src/*.ts', 'src/*.vue']
}),
// Mock 服务配置
viteMockServe({
mockPath: 'mock', // mock 文件目录
supportTs: true, // 支持 TypeScript
watchFiles: true, // 监听文件变化
localEnabled: command === 'serve', // 开发环境启用
prodEnabled: command === 'build' // 生产环境启用
})
]
})
2. 高级构建配置
// vite.config.ts
export default defineConfig({
build: {
// 库模式构建配置
lib: {
entry: path.resolve(__dirname, 'src/index.ts'), // 入口文件
name: 'MyLib', // 库的全局变量名
fileName: (format) => `my-lib.${format}.js`, // 输出文件名
formats: ['es', 'umd'] // 输出格式
},
// Rollup 构建配置
rollupOptions: {
external: ['vue'], // 外部依赖
output: {
globals: {
vue: 'Vue' // 外部依赖的全局变量名
},
// 自定义代码分割策略
manualChunks: (id) => {
// 处理 node_modules 中的模块
if (id.includes('node_modules')) {
if (id.includes('lodash')) {
return 'lodash' // lodash 单独打包
}
if (id.includes('@vueuse')) {
return 'vueuse' // vueuse 单独打包
}
return 'vendor' // 其他第三方库打包到 vendor
}
// 处理源码模块
if (id.includes('src/components')) {
return 'components' // 组件单独打包
}
if (id.includes('src/utils')) {
return 'utils' // 工具函数单独打包
}
}
}
},
target: ['es2015', 'chrome87'], // 目标环境
cssCodeSplit: true, // 启用 CSS 代码分割
sourcemap: true, // 生成 source map
emptyOutDir: true, // 构建前清空输出目录
brotliSize: true // 启用 brotli 压缩并显示大小
}
})
3. 高级开发配置
// vite.config.ts
export default defineConfig({
server: {
// HTTPS 配置
https: {
key: fs.readFileSync('path/to/server.key'), // SSL 私钥
cert: fs.readFileSync('path/to/server.crt') // SSL 证书
},
// 代理配置
proxy: {
'/api': {
target: 'http://localhost:8080', // 目标服务器
changeOrigin: true, // 修改请求头中的 Origin
rewrite: (path) => path.replace(/^\/api/, ''), // 重写请求路径
configure: (proxy, options) => {
// 自定义代理配置
proxy.on('proxyReq', (proxyReq, req, res) => {
// 添加自定义请求头
proxyReq.setHeader('x-custom-header', 'custom-value')
})
}
}
},
// 文件监听配置
watch: {
// 排除不需要监听的文件
ignored: ['**/node_modules/**', '**/.git/**']
},
// 中间件配置
middlewares: [
(req, res, next) => {
// 自定义请求处理
if (req.url?.startsWith('/custom')) {
res.end('Custom response')
} else {
next() // 继续下一个中间件
}
}
]
}
})
4. 自定义插件开发
// plugins/vite-plugin-custom.ts
import type { Plugin } from 'vite'
export default function customPlugin(options = {}): Plugin {
let config // 存储 Vite 配置
return {
name: 'vite-plugin-custom', // 插件名称
// 配置解析完成后的钩子
configResolved(resolvedConfig) {
config = resolvedConfig
},
// 代码转换钩子
transform(code, id) {
if (id.endsWith('.vue')) {
// 处理 Vue 文件的代码
return {
code: transformedCode, // 转换后的代码
map: null // source map
}
}
},
// 开发服务器配置钩子
configureServer(server) {
server.middlewares.use((req, res, next) => {
// 添加自定义中间件逻辑
next()
})
},
// 构建开始钩子
buildStart() {
// 构建开始时的初始化工作
},
// 构建结束钩子
buildEnd() {
// 构建结束时的清理工作
}
}
}
5. 性能优化进阶
// vite.config.ts
export default defineConfig({
// 依赖预构建配置
optimizeDeps: {
// 强制预构建的依赖
include: [
'vue',
'vue-router',
'pinia',
'@vueuse/core',
'lodash-es'
],
exclude: ['your-local-package'], // 排除预构建的依赖
esbuildOptions: {
target: 'es2015' // esbuild 目标环境
}
},
// 构建配置
build: {
// 多页面应用入口配置
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
nested: resolve(__dirname, 'nested/index.html')
},
output: {
// 自定义代码分割策略
manualChunks(id) {
if (id.includes('node_modules')) {
const packageName = id
.toString()
.split('node_modules/')[1]
.split('/')[0]
// 根据包大小决定是否单独分割
if (largePackages.includes(packageName)) {
return `vendor-${packageName}` // 大型包单独分割
}
return 'vendor' // 其他第三方库打包到 vendor
}
}
}
},
target: 'es2015', // 构建目标环境
minify: 'terser', // 使用 terser 压缩
terserOptions: {
compress: {
drop_console: true, // 移除 console
drop_debugger: true // 移除 debugger
}
},
cssCodeSplit: true, // CSS 代码分割
cssMinify: true // CSS 压缩
}
})