知识速查表
CLI 命令
| 命令 | 说明 |
|---|---|
npm create vite@latest | 创建新项目(交互式) |
npm create vite@latest my-app -- --template vue | 使用模板创建项目 |
npx vite | 启动开发服务器 |
npx vite --port 3000 | 指定端口启动 |
npx vite --open | 启动并打开浏览器 |
npx vite --host | 允许外部访问 |
npx vite build | 生产构建 |
npx vite build --mode staging | 使用指定模式构建 |
npx vite preview | 预览生产构建 |
npx vite --config my-config.js | 使用指定配置文件 |
项目结构
my-project/
├── index.html # HTML 入口
├── package.json # 项目配置
├── vite.config.js # Vite 配置
├── public/ # 静态资源(原样复制)
│ ├── favicon.ico
│ └── robots.txt
└── src/
├── main.js # 入口文件
├── App.vue # 根组件
├── assets/ # 资源(会被处理)
└── components/ # 组件
配置文件模板
基础配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
server: {
port: 3000,
open: true,
},
})
完整配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig(({ mode }) => ({
root: process.cwd(),
base: '/',
publicDir: 'public',
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
'@components': resolve(__dirname, 'src/components'),
'@views': resolve(__dirname, 'src/views'),
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
},
server: {
port: 3000,
host: true,
open: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
build: {
outDir: 'dist',
sourcemap: mode === 'development',
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router'],
},
},
},
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/vars.scss" as *;`,
},
},
},
}))
环境变量
.env 文件
# .env # 所有环境
# .env.local # 本地(不提交 git)
# .env.[mode] # 特定模式
# .env.[mode].local # 特定模式本地
VITE_API_URL=https://api.example.com
VITE_APP_TITLE=My App
使用环境变量
// 访问环境变量
const apiUrl = import.meta.env.VITE_API_URL
const isDev = import.meta.env.DEV
const isProd = import.meta.env.PROD
const mode = import.meta.env.MODE
const baseUrl = import.meta.env.BASE_URL
TypeScript 类型
// vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string
readonly VITE_APP_TITLE: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
路径别名
配置
// vite.config.js
import { resolve } from 'path'
export default defineConfig({
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
'@components': resolve(__dirname, 'src/components'),
'@views': resolve(__dirname, 'src/views'),
'@utils': resolve(__dirname, 'src/utils'),
'@assets': resolve(__dirname, 'src/assets'),
},
},
})
使用
// 导入组件
import Button from '@components/Button.vue'
// 导入工具
import { formatDate } from '@utils/date'
// 导入资源
import logo from '@assets/logo.png'
CSS 处理
预处理器
npm install -D sass-embedded # 或 sass
npm install -D less
npm install -D stylus
CSS Modules
/* style.module.css */
.container { padding: 20px; }
.title { font-size: 24px; }
import classes from './style.module.css'
// 使用
<div className={classes.container}>
<h1 className={classes.title}>Title</h1>
</div>
Scoped CSS (Vue)
<style scoped>
/* 只作用于当前组件 */
.container { padding: 20px; }
</style>
静态资源
资源导入
// 导入图片
import imgUrl from './img.png'
// 作为 URL
import assetUrl from './asset.js?url'
// 作为原始字符串
import shaderCode from './shader.glsl?raw'
// 内联为 base64
import inlineSvg from './icon.svg?inline'
public 目录
public/
├── favicon.ico
├── robots.txt
└── images/
└── logo.png
<!-- 使用根路径引用 -->
<img src="/images/logo.png" />
代理配置
// vite.config.js
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/ws': {
target: 'ws://localhost:8080',
ws: true,
},
},
},
})
Glob 导入
// 懒加载
const modules = import.meta.glob('./dir/*.js')
// 立即加载
const modules = import.meta.glob('./dir/*.js', { eager: true })
// 具名导入
const modules = import.meta.glob('./dir/*.js', {
import: 'setup',
eager: true,
})
// 排除文件
const modules = import.meta.glob([
'./dir/*.js',
'!**/bar.js',
])
动态导入
// 路由懒加载
const User = () => import('./views/User.vue')
// 条件加载
if (condition) {
const module = await import('./heavy-module.js')
}
// 动态路径
const module = await import(`./locales/${lang}.js`)
Web Workers
// 构造函数方式
const worker = new Worker(
new URL('./worker.js', import.meta.url),
{ type: 'module' }
)
// 查询后缀方式
import MyWorker from './worker?worker'
const worker = new MyWorker()
// 内联 Worker
import InlineWorker from './worker?worker&inline'
常用插件
| 插件 | 安装 | 用途 |
|---|---|---|
| Vue | npm i -D @vitejs/plugin-vue | Vue 3 支持 |
| React | npm i -D @vitejs/plugin-react | React Fast Refresh |
| Legacy | npm i -D @vitejs/plugin-legacy | 旧浏览器支持 |
| PWA | npm i -D vite-plugin-pwa | PWA 支持 |
| SVG | npm i -D vite-plugin-svgr | SVG 作为组件 |
| 检查器 | npm i -D vite-plugin-checker | TypeScript/ESLint 检查 |
| 自动导入 | npm i -D unplugin-auto-import | API 自动导入 |
| 组件导入 | npm i -D unplugin-vue-components | 组件自动导入 |
构建配置
export default defineConfig({
build: {
outDir: 'dist', // 输出目录
assetsDir: 'assets', // 资源目录
sourcemap: false, // Source map
target: 'es2015', // 目标浏览器
minify: 'esbuild', // 压缩工具
cssCodeSplit: true, // CSS 分割
assetsInlineLimit: 4096, // 内联限制
chunkSizeWarningLimit: 500, // 警告阈值
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router'],
},
},
},
},
})
多页面应用
// vite.config.js
import { resolve } from 'path'
export default defineConfig({
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
about: resolve(__dirname, 'about/index.html'),
},
},
},
})
库模式
// vite.config.js
import { resolve } from 'path'
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'lib/main.js'),
name: 'MyLib',
fileName: 'my-lib',
formats: ['es', 'umd'],
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue',
},
},
},
},
})
HMR API
if (import.meta.hot) {
// 接受自身更新
import.meta.hot.accept()
// 接受依赖更新
import.meta.hot.accept('./dep.js', (newModule) => {
console.log('updated:', newModule)
})
// 监听事件
import.meta.hot.on('vite:beforeUpdate', (data) => {
console.log('before update:', data)
})
// 清理副作用
import.meta.hot.dispose(() => {
clearInterval(timer)
})
}
package.json 脚本
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"build:staging": "vite build --mode staging",
"type-check": "tsc --noEmit"
}
}
浏览器支持
开发环境
- Chrome/Edge >= 111
- Firefox >= 114
- Safari >= 16.4
最低支持(ESM)
- Chrome >= 64
- Firefox >= 67
- Safari >= 11.1
- Edge >= 79
旧浏览器支持
npm install -D @vitejs/plugin-legacy
import legacy from '@vitejs/plugin-legacy'
export default defineConfig({
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
}),
],
})
常见问题
端口被占用
npx vite --port 3000
清空输出目录
build: {
emptyOutDir: true
}
相对路径部署
export default defineConfig({
base: './',
})
禁用 HMR
server: {
hmr: false
}
设置全局变量
export default defineConfig({
define: {
__VERSION__: JSON.stringify('1.0.0'),
},
})