🚀 Vite 开发指南
🌟 简介
Vite 是一个现代化的前端构建工具,由 Vue.js 作者尤雨溪开发,旨在提供极速的开发体验和优化的生产构建。Vite 利用浏览器的原生 ES 模块支持,在开发时实现了极速的热更新(HMR),同时通过 Rollup 进行生产构建,确保了优异的构建性能和产物质量。
1.1 Vite 的核心优势
- 极速开发服务器:利用原生 ES 模块,无需打包,启动速度极快
- 即时热模块替换:修改代码后立即看到效果,无需等待重新构建
- 优化的生产构建:使用 Rollup 进行生产构建,产物体积小、性能优
- 丰富的插件生态:支持各种前端框架和工具
- 内置 TypeScript 支持:无需额外配置即可使用 TypeScript
- 智能的路径别名:简化模块导入路径
- 环境变量管理:内置多环境配置支持
🚀 快速开始
2.1 创建项目
使用 Vite 5 创建新项目的命令如下:
# 使用 npm 6.x
npm create vite@latest my-project -- --template vue
# 使用 npm 7+
npm create vite@latest my-project --template vue
# 使用 yarn
yarn create vite my-project --template vue
# 使用 pnpm
pnpm create vite my-project --template vue
# 使用 bun
bun create vite my-project --template vue2.2 支持的模板
Vite 提供了多种官方模板,适用于不同的前端框架:
| 模板名称 | 命令 | 描述 |
|---|---|---|
| Vue | --template vue | Vue 3 + JavaScript |
| Vue + TypeScript | --template vue-ts | Vue 3 + TypeScript |
| React | --template react | React + JavaScript |
| React + TypeScript | --template react-ts | React + TypeScript |
| React + SWC | --template react-swc | React + SWC + JavaScript |
| React + SWC + TypeScript | --template react-swc-ts | React + SWC + TypeScript |
| Preact | --template preact | Preact + JavaScript |
| Preact + TypeScript | --template preact-ts | Preact + TypeScript |
| Lit | --template lit | Lit + JavaScript |
| Lit + TypeScript | --template lit-ts | Lit + TypeScript |
| Svelte | --template svelte | Svelte + JavaScript |
| Svelte + TypeScript | --template svelte-ts | Svelte + TypeScript |
| Vanilla | --template vanilla | 原生 JavaScript |
| Vanilla + TypeScript | --template vanilla-ts | 原生 TypeScript |
2.3 项目结构
创建项目后,Vite 会生成一个标准的项目结构:
my-project/
├── public/ # 静态资源目录,不会被打包
│ └── favicon.ico # 网站图标
├── src/ # 源代码目录
│ ├── assets/ # 资源文件(图片、字体等)
│ ├── components/ # 组件目录
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── index.html # HTML 入口文件
├── package.json # 项目配置文件
├── vite.config.js # Vite 配置文件
├── tsconfig.json # TypeScript 配置文件(仅 TypeScript 模板)
├── .eslintrc.cjs # ESLint 配置文件
├── .prettierrc.json # Prettier 配置文件
└── README.md # 项目说明文件2.4 安装依赖并启动开发服务器
# 进入项目目录
cd my-project
# 安装依赖
npm install
# 或 yarn
# yarn install
# 或 pnpm
# pnpm install
# 启动开发服务器
npm run dev
# 或 yarn dev
# 或 pnpm dev
# 构建生产版本
npm run build
# 或 yarn build
# 或 pnpm build
# 预览生产构建产物
npm run preview
# 或 yarn preview
# 或 pnpm preview✨ 核心特性
3.1 开发服务器
Vite 的开发服务器提供了极速的启动速度和热模块替换(HMR)功能,大大提升了开发体验:
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
// 服务器端口
port: 3000,
// 自动打开浏览器
open: true,
// 允许跨域
cors: true,
// 自定义主机名
host: '0.0.0.0',
// 热模块替换配置
hmr: {
// 禁用 HMR 覆盖层
overlay: false,
// HMR 协议
protocol: 'ws',
// HMR 主机
host: 'localhost'
},
// 代理配置
proxy: {
// 代理 API 请求
'/api': {
// 目标服务器
target: 'http://localhost:8080',
// 改变源
changeOrigin: true,
// 路径重写
rewrite: (path) => path.replace(/^\/api/, ''),
// 配置 WebSocket
ws: true
},
// 多个代理配置
'/auth': {
target: 'http://localhost:9000',
changeOrigin: true
}
}
### 3.2 构建优化
Vite 使用 Rollup 进行生产构建,提供了丰富的构建优化选项:
```javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
// 构建目标
target: 'es2015',
// 输出目录
outDir: 'dist',
// 静态资源目录
assetsDir: 'assets',
// 生成源映射
sourcemap: false,
// 代码压缩
minify: 'terser',
// Terser 配置
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
// chunk 大小警告阈值
chunkSizeWarningLimit: 1500,
// 启用 CSS 代码分割
cssCodeSplit: true,
// 生成 manifest.json
manifest: false,
// 库模式
// lib: {
// entry: './src/index.js',
// name: 'MyLibrary',
// fileName: 'my-library'
// },
// Rollup 配置
rollupOptions: {
// 输入
input: {
main: './index.html',
// 多页面应用
// admin: './admin.html'
},
// 输出
output: {
// 手动代码分割
manualChunks: {
// 第三方库
vendor: ['vue', 'vue-router', 'pinia'],
// 工具库
utils: ['lodash-es', 'axios'],
// UI 库
ui: ['element-plus']
},
// 命名格式
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
}
}
}
});3.3 预览服务器
Vite 提供了预览服务器,用于本地预览生产构建产物:
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
preview: {
// 预览端口
port: 5000,
// 自动打开浏览器
open: true,
// 允许跨域
cors: true,
// 代理配置(与开发服务器相同)
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
});🧩 插件系统
Vite 的插件系统是其生态系统的核心,通过插件可以扩展 Vite 的功能,支持各种前端框架和工具。
4.1 官方插件
Vite 提供了多个官方插件,用于支持不同的前端框架和功能:
// vite.config.js
import { defineConfig } from 'vite'
// Vue 插件
import vue from '@vitejs/plugin-vue'
// Vue JSX 插件
import vueJsx from '@vitejs/plugin-vue-jsx'
// React 插件
import react from '@vitejs/plugin-react'
// React SWC 插件(更快的编译)
import reactSwc from '@vitejs/plugin-react-swc'
// Preact 插件
import preact from '@vitejs/plugin-preact'
// Lit 插件
import lit from '@vitejs/plugin-lit'
// Svelte 插件
import { svelte } from '@sveltejs/vite-plugin-svelte'
// 传统浏览器兼容性插件
import legacy from '@vitejs/plugin-legacy'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
// 根据项目框架选择相应的插件
// vue(),
// react(),
// preact(),
// lit(),
// svelte(),
// Vue JSX 支持
// vueJsx(),
// 传统浏览器兼容性
legacy({
// 目标浏览器
targets: ['defaults', 'not IE 11'],
// 生成现代和传统两个版本
renderLegacyChunks: true,
// polyfill 注入方式
polyfills: ['es.promise.finally', 'es/map', 'es/set'],
// 现代浏览器检测
modernPolyfills: true
})
]
});4.2 常用第三方插件
4.2.1 自动导入插件
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver, AntDesignVueResolver, VantResolver } from 'unplugin-vue-components/resolvers'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
// 自动导入
AutoImport({
// 导入预设
imports: [
'vue',
'vue-router',
'pinia',
'@vueuse/core'
],
// 解析器
resolvers: [
// Element Plus 解析器
ElementPlusResolver(),
// Ant Design Vue 解析器
// AntDesignVueResolver(),
// Vant 解析器
// VantResolver(),
// 图标解析器
IconsResolver({
prefix: 'Icon'
})
],
// 生成 dts 文件
dts: './auto-imports.d.ts'
}),
// 自动导入组件
Components({
// 解析器
resolvers: [
// Element Plus 解析器
ElementPlusResolver(),
// 图标解析器
IconsResolver({
enabledCollections: ['ep', 'ant-design', 'material', 'lucide']
})
],
// 生成 dts 文件
dts: './components.d.ts'
}),
// 图标插件
Icons({
autoInstall: true,
compiler: 'vue3'
})
]
});4.2.2 路径别名插件
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
// 路径别名
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@assets': path.resolve(__dirname, './src/assets'),
'@utils': path.resolve(__dirname, './src/utils'),
'@api': path.resolve(__dirname, './src/api'),
'@store': path.resolve(__dirname, './src/store')
},
// 扩展名
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
}
});4.2.3 其他实用插件
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VitePWA } from 'vite-plugin-pwa'
import { compression } from 'vite-plugin-compression'
import { visualizer } from 'rollup-plugin-visualizer'
import htmlPurge from 'vite-plugin-purge-icons'
import eslint from 'vite-plugin-eslint'
import stylelint from 'vite-plugin-stylelint'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
// ESLint 插件
eslint({
cache: false,
include: ['src/**/*.{js,jsx,ts,tsx,vue}']
}),
// StyleLint 插件
stylelint({
fix: true,
include: ['src/**/*.{css,scss,sass,less,stylus,vue}']
}),
// PWA 插件
VitePWA({
registerType: 'autoUpdate',
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'masked-icon.svg'],
manifest: {
name: 'My App',
short_name: 'My App',
description: 'My Awesome App',
theme_color: '#ffffff',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png'
}
]
}
}),
// 压缩插件
compression({
algorithm: 'gzip',
ext: '.gz',
threshold: 10240
}),
// 构建分析插件
visualizer({
open: true,
gzipSize: true,
brotliSize: true
}),
// 图标清理插件
htmlPurge()
]
});🌍 环境配置
Vite 提供了内置的环境变量管理功能,支持多环境配置,方便在不同环境下使用不同的配置。
5.1 环境变量文件
Vite 支持以下环境变量文件:
# .env # 所有环境通用
# .env.local # 所有环境通用,不会被提交到版本控制
# .env.development # 开发环境
# .env.development.local # 开发环境,不会被提交到版本控制
# .env.production # 生产环境
# .env.production.local # 生产环境,不会被提交到版本控制
# .env.test # 测试环境
# .env.test.local # 测试环境,不会被提交到版本控制5.2 环境变量配置
# .env
# 应用标题
VITE_APP_TITLE=My App
# 应用版本
VITE_APP_VERSION=1.0.0
# API 基础 URL
VITE_API_BASE_URL=http://api.example.com
# 是否开启调试模式
VITE_APP_DEBUG=false
# .env.development
# 开发环境 API URL
VITE_API_BASE_URL=http://localhost:8080
# 开发环境开启调试模式
VITE_APP_DEBUG=true
# .env.production
# 生产环境 API URL
VITE_API_BASE_URL=https://api.production.com
# 生产环境关闭调试模式
VITE_APP_DEBUG=false
# .env.test
# 测试环境 API URL
VITE_API_BASE_URL=http://api.test.com
# 测试环境开启调试模式
VITE_APP_DEBUG=true5.3 环境变量使用
在代码中,Vite 提供了 import.meta.env 对象来访问环境变量:
// 在组件中使用环境变量
<template>
<div>
<h1>{{ appTitle }}</h1>
<p>版本: {{ appVersion }}</p>
<p>API URL: {{ apiBaseUrl }}</p>
<p v-if="isDebug">调试模式已开启</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
// 访问环境变量
const appTitle = import.meta.env.VITE_APP_TITLE
const appVersion = import.meta.env.VITE_APP_VERSION
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL
const isDebug = import.meta.env.VITE_APP_DEBUG === 'true'
// 计算属性
const apiUrl = computed(() => {
return `${apiBaseUrl}/v1`
})
console.log('应用标题:', appTitle)
console.log('API URL:', apiUrl.value)
</script>
// 在 API 配置中使用环境变量
// api/config.js
export const API_CONFIG = {
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
}
// 在路由配置中使用环境变量
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue')
},
// 条件路由配置
...(import.meta.env.VITE_APP_DEBUG === 'true' ? [
{
path: '/debug',
name: 'Debug',
component: () => import('../views/Debug.vue')
}
] : [])
]
})5.4 内置环境变量
Vite 提供了以下内置环境变量:
// 是否为开发环境
import.meta.env.DEV // 开发环境为 true
// 是否为生产环境
import.meta.env.PROD // 生产环境为 true
// 是否为 SSR 环境
import.meta.env.SSR // SSR 环境为 true
// 应用的基础路径
import.meta.env.BASE_URL // 对应 vite.config.js 中的 base 配置
// 项目根目录的绝对路径
import.meta.env.PROJECT_ROOT // 仅在开发环境可用
// 构建时间戳
import.meta.env.BUILD_TIMESTAMP // 仅在生产环境可用5.5 自定义环境变量类型
在 TypeScript 项目中,可以通过类型声明文件来定义环境变量的类型:
// src/vite-env.d.ts
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// 自定义环境变量类型
enum AppEnvironment {
Development = 'development',
Production = 'production',
Test = 'test'
}
declare interface ImportMetaEnv {
// 应用标题
readonly VITE_APP_TITLE: string
// 应用版本
readonly VITE_APP_VERSION: string
// API 基础 URL
readonly VITE_API_BASE_URL: string
// 是否开启调试模式
readonly VITE_APP_DEBUG: string
// 应用环境
readonly VITE_APP_ENV: AppEnvironment
}
declare interface ImportMeta {
readonly env: ImportMetaEnv
}📦 资源处理
Vite 提供了强大的资源处理能力,支持各种类型的静态资源和 CSS 预处理器。
6.1 静态资源
6.1.1 静态资源配置
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
// 静态资源目录
publicDir: 'public',
// 静态资源包含
assetsInclude: [
'**/*.gltf', // 3D 模型
'**/*.glb', // 3D 模型
'**/*.obj', // 3D 模型
'**/*.fbx', // 3D 模型
'**/*.mp4', // 视频
'**/*.webm', // 视频
'**/*.ogg', // 音频
'**/*.mp3', // 音频
'**/*.wav', // 音频
'**/*.woff', // 字体
'**/*.woff2', // 字体
'**/*.ttf', // 字体
'**/*.eot' // 字体
]
});6.1.2 静态资源使用
Vite 支持多种方式使用静态资源:
// 1. 导入图片
import logo from './assets/logo.png'
// 在组件中使用
<template>
<img :src="logo" alt="Logo" />
</template>
// 2. 导入样式
import './assets/styles/main.css'
// 3. 导入 JSON
import config from './config.json'
console.log(config.apiUrl)
// 4. 导入 Web Worker
import MyWorker from './worker?worker'
const worker = new MyWorker()
worker.postMessage({ type: 'ping' })
// 5. 导入 WebAssembly
import init from './module.wasm'
init().then((exports) => {
console.log(exports.add(1, 2))
})
// 6. 动态导入
const loadImage = async () => {
const { default: image } = await import('./assets/dynamic-image.png')
return image
}
// 7. 使用 public 目录下的资源
// public 目录下的资源会被直接复制到输出目录,无需导入
// 使用绝对路径访问
<img src="/favicon.ico" alt="Favicon" />6.2 CSS 处理
6.2.1 CSS 预处理器配置
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
css: {
// 启用 CSS 模块
modules: {
// 自定义 CSS 模块类名
generateScopedName: '[name]__[local]--[hash:base64:5]'
},
// 预处理器配置
preprocessorOptions: {
// SCSS 配置
scss: {
// 全局变量和混合
additionalData: `
@import "@/styles/variables.scss";
@import "@/styles/mixins.scss";
`
},
// Less 配置
less: {
math: 'always',
globalVars: {
'@primary-color': '#42b983'
}
},
// Stylus 配置
stylus: {
define: {
$primary-color: '#42b983'
}
}
},
// 启用 CSS 源映射
devSourcemap: true
}
});6.2.2 CSS 模块使用
<!-- 组件样式 -->
<style module>
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.title {
font-size: 24px;
color: var(--primary-color);
}
</style>
<template>
<div :class="$style.container">
<h1 :class="$style.title">Hello Vite</h1>
</div>
</template>
<script setup>
// 也可以使用具名导入
import styles from './Component.module.css'
</script>
<template>
<div :class="styles.container">
<h1 :class="styles.title">Hello Vite</h1>
</div>
</template>6.2.3 PostCSS 配置
Vite 默认集成了 PostCSS,可以通过 postcss.config.js 文件进行配置:
// postcss.config.js
module.exports = {
plugins: {
// 自动添加浏览器前缀
autoprefixer: {},
// CSS 嵌套
'postcss-nested': {},
// CSS 变量
'postcss-custom-properties': {},
// CSS 导入
'postcss-import': {},
// CSS 压缩
cssnano: process.env.NODE_ENV === 'production' ? {
preset: 'default'
} : false
}
}⚡ 性能优化
Vite 提供了多种性能优化选项,包括开发时优化和构建时优化。
7.1 构建优化
7.1.1 代码分割
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
// chunk 大小警告阈值
chunkSizeWarningLimit: 1500,
// 启用 CSS 代码分割
cssCodeSplit: true,
// 启用动态导入的代码分割
dynamicImportVars: true,
// Rollup 配置
rollupOptions: {
output: {
// 手动代码分割
manualChunks: {
// 第三方库
vendor: ['vue', 'vue-router', 'pinia'],
// 工具库
utils: ['lodash-es', 'axios', '@vueuse/core'],
// UI 库
ui: ['element-plus', '@element-plus/icons-vue'],
// 图表库
charts: ['echarts'],
// 地图库
maps: ['amap-jsapi-loader']
},
// 命名格式
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
}
}
}
});7.1.2 构建输出优化
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
// 构建目标
target: 'es2015',
// 输出目录
outDir: 'dist',
// 静态资源目录
assetsDir: 'assets',
// 生成源映射
sourcemap: false,
// 代码压缩
minify: 'terser',
// Terser 配置
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
// 移除未使用的变量和函数
unused: true,
// 合并变量
collapse_vars: true,
// 内联函数
inline: true
},
mangle: {
// 混淆变量名
toplevel: true,
// 保留关键字
reserved: ['$', 'jQuery']
}
},
// 清除输出目录
emptyOutDir: true,
// 产物分析
reportCompressedSize: true
}
});7.2 开发优化
7.2.1 依赖预构建
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
// 依赖预构建
optimizeDeps: {
// 需要预构建的依赖
include: [
'lodash-es',
'axios',
'echarts',
'@vueuse/core',
'element-plus'
],
// 排除不需要预构建的依赖
exclude: [
'vue',
'vue-router',
'pinia'
],
// 强制预构建
force: false,
// 预构建输出目录
esbuildOptions: {
// 目标
target: 'es2015',
// 定义全局变量
define: {
'process.env.NODE_ENV': JSON.stringify('development')
}
}
},
// 服务器配置
server: {
// 热模块替换
hmr: {
// 禁用 HMR 覆盖层
overlay: false,
// 启用 HMR 内联
clientPort: 3000
},
// 启动时打开浏览器
open: true,
// 端口
port: 3000
}
});7.2.2 缓存优化
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
// 缓存目录
cacheDir: '.vite',
// 构建缓存
build: {
// 缓存
cache: {
// 启用缓存
enabled: true,
// 缓存目录
directory: '.vite/build'
}
},
// 服务器缓存
server: {
// 启用文件系统缓存
fs: {
// 允许访问的文件
allow: ['..']
}
}
});7.3 资源优化
7.3.1 图片优化
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
// SVG 图标插件
createSvgIconsPlugin({
// SVG 图标目录
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
// 图标 ID 格式
symbolId: 'icon-[dir]-[name]'
})
],
// 构建配置
build: {
// 资产优化
assetsInlineLimit: 4096, // 4kb 以下的资源内联
// 空出目录
emptyOutDir: true
}
});7.3.2 CSS 优化
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
css: {
// 启用 CSS 模块
modules: true,
// 启用 CSS 源映射
devSourcemap: true,
// 预处理器配置
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
}
},
build: {
// 启用 CSS 代码分割
cssCodeSplit: true,
// CSS 提取
cssMinify: 'lightningcss'
}
});🎯 最佳实践
8.1 项目结构
8.1.1 推荐的项目结构
my-project/
├── public/ # 静态资源目录
│ ├── favicon.ico # 网站图标
│ └── robots.txt # 搜索引擎配置
├── src/ # 源代码目录
│ ├── assets/ # 资源文件
│ │ ├── icons/ # SVG 图标
│ │ ├── images/ # 图片
│ │ ├── fonts/ # 字体
│ │ └── styles/ # 全局样式
│ ├── components/ # 组件
│ │ ├── common/ # 通用组件
│ │ ├── layout/ # 布局组件
│ │ └── business/ # 业务组件
│ ├── composables/ # 组合式 API
│ ├── directives/ # 自定义指令
│ ├── filters/ # 过滤器
│ ├── hooks/ # 自定义钩子
│ ├── layouts/ # 布局
│ ├── plugins/ # 插件
│ ├── router/ # 路由
│ │ ├── index.js # 路由配置
│ │ └── guards.js # 路由守卫
│ ├── stores/ # 状态管理
│ │ ├── modules/ # 状态模块
│ │ └── index.js # 状态配置
│ ├── services/ # 服务
│ │ ├── api/ # API 服务
│ │ └── utils/ # 工具服务
│ ├── utils/ # 工具函数
│ ├── views/ # 页面
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── tests/ # 测试
│ ├── unit/ # 单元测试
│ └── e2e/ # 端到端测试
├── config/ # 配置
│ ├── vite/ # Vite 配置
│ │ ├── base.js # 基础配置
│ │ ├── dev.js # 开发配置
│ │ └── prod.js # 生产配置
│ └── index.js # 配置入口
├── scripts/ # 脚本
│ ├── build.js # 构建脚本
│ └── deploy.js # 部署脚本
├── index.html # HTML 入口
├── package.json # 项目配置
├── vite.config.js # Vite 配置
├── tsconfig.json # TypeScript 配置
├── tsconfig.node.json # Node.js TypeScript 配置
├── .eslintrc.cjs # ESLint 配置
├── .prettierrc.json # Prettier 配置
├── .stylelintrc.json # StyleLint 配置
├── .gitignore # Git 忽略文件
└── README.md # 项目说明8.1.2 模块化配置文件
// config/vite/base.js
import { defineConfig } from 'vite'
import path from 'path'
// 基础配置
export default defineConfig({
// 路径别名
resolve: {
alias: {
'@': path.resolve(__dirname, '../../src'),
'@components': path.resolve(__dirname, '../../src/components'),
'@assets': path.resolve(__dirname, '../../src/assets'),
'@utils': path.resolve(__dirname, '../../src/utils'),
'@api': path.resolve(__dirname, '../../src/services/api'),
'@store': path.resolve(__dirname, '../../src/stores')
}
},
// 插件配置
plugins: []
});
// config/vite/dev.js
import { defineConfig } from 'vite'
// 开发配置
export default defineConfig({
server: {
port: 3000,
open: true,
cors: true,
hmr: {
overlay: false
}
}
});
// config/vite/prod.js
import { defineConfig } from 'vite'
// 生产配置
export default defineConfig({
build: {
target: 'es2015',
minify: 'terser',
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router', 'pinia'],
utils: ['lodash-es', 'axios']
}
}
}
}
});
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import baseConfig from './config/vite/base'
import devConfig from './config/vite/dev'
import prodConfig from './config/vite/prod'
// 合并配置
const mergedConfig = defineConfig({
...baseConfig,
plugins: [
vue(),
...baseConfig.plugins
],
...(process.env.NODE_ENV === 'development' ? devConfig : prodConfig)
});
export default mergedConfig8.2 开发流程
8.2.1 使用 TypeScript
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
/* Path aliases */
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
// tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}
// src/vite-env.d.ts
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}8.2.2 代码规范
// .eslintrc.cjs
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'prettier'
],
parserOptions: {
ecmaVersion: 2021,
parser: '@typescript-eslint/parser',
sourceType: 'module'
},
plugins: [
'vue',
'@typescript-eslint'
],
rules: {
// 自定义规则
'vue/multi-word-component-names': 'off',
'@typescript-eslint/no-explicit-any': 'off'
}
}
// .prettierrc.json
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2
}
// .stylelintrc.json
{
"extends": [
"stylelint-config-standard",
"stylelint-config-prettier"
],
"rules": {
// 自定义规则
"selector-class-pattern": "^[a-z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*$",
"declaration-no-important": true
}
}
// package.json 脚本
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write .",
"stylelint": "stylelint \"**/*.{css,scss,sass,less,stylus,vue}\" --fix",
"typecheck": "tsc --noEmit",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
}
}8.2.3 自动化测试
// jest.config.js
module.exports = {
preset: '@vue/cli-plugin-unit-jest/presets/typescript',
testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[tj]s?(x)'],
collectCoverageFrom: [
'src/**/*.{vue,js,jsx,ts,tsx}',
'!src/main.ts',
'!src/App.vue',
'!src/router/index.ts',
'!src/stores/index.ts',
'!**/node_modules/**',
'!**/dist/**'
],
coverageDirectory: '<rootDir>/coverage',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
}
}
// 示例测试文件
// src/components/HelloWorld.spec.ts
import { mount } from '@vue/test-utils'
import HelloWorld from './HelloWorld.vue'
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message'
const wrapper = mount(HelloWorld, {
props: { msg }
})
expect(wrapper.text()).toMatch(msg)
})
it('renders the default message when no msg is passed', () => {
const wrapper = mount(HelloWorld)
expect(wrapper.text()).toMatch('Hello World')
})
})8.3 性能优化
8.3.1 合理使用插件
- 只使用必要的插件:插件会增加构建时间和复杂度,只使用项目真正需要的插件
- 使用官方插件:官方插件经过优化,性能更好
- 合理配置插件:根据项目需求配置插件,避免不必要的功能
- 使用插件的按需加载:如 UI 库的按需加载
8.3.2 优化构建配置
- 代码分割:使用
manualChunks合理分割代码 - 资源内联:小资源内联,减少 HTTP 请求
- 代码压缩:使用
terser或esbuild压缩代码 - Tree Shaking:移除未使用的代码
- 懒加载:使用动态导入懒加载组件和路由
8.3.3 实施缓存策略
- 浏览器缓存:使用长效缓存策略,为静态资源添加哈希值
- 构建缓存:启用 Vite 的构建缓存
- 依赖缓存:使用
optimizeDeps预构建依赖 - CDN 缓存:合理配置 CDN 缓存策略
8.3.4 开发体验优化
- 热模块替换:启用 HMR,提高开发效率
- 快速启动:使用 Vite 的极速开发服务器
- 错误提示:配置友好的错误提示
- 代码智能提示:使用 TypeScript 和编辑器插件
8.4 部署策略
8.4.1 多环境部署
// package.json 脚本
{
"scripts": {
"dev": "vite",
"build": "vite build",
"build:dev": "vite build --mode development",
"build:test": "vite build --mode test",
"build:prod": "vite build --mode production",
"preview": "vite preview"
}
}
// 部署脚本示例
// scripts/deploy.js
const { execSync } = require('child_process')
const fs = require('fs')
const path = require('path')
// 部署环境
const env = process.argv[2] || 'production'
console.log(`开始部署到 ${env} 环境...`)
// 构建
console.log('正在构建...')
execSync(`npm run build:${env}`, { stdio: 'inherit' })
// 部署到服务器
console.log('正在部署到服务器...')
// 这里根据实际部署方式修改
execSync('scp -r dist/* user@server:/path/to/destination', { stdio: 'inherit' })
console.log('部署完成!')8.4.2 Docker 部署
# Dockerfile
FROM node:18-alpine as build
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm install
# 复制源代码
COPY . .
# 构建生产版本
RUN npm run build
# 使用 Nginx 作为基础镜像
FROM nginx:alpine
# 复制构建产物到 Nginx 目录
COPY --from=build /app/dist /usr/share/nginx/html
# 复制 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 暴露端口
EXPOSE 80
# 启动 Nginx
CMD ["nginx", "-g", "daemon off;"]
# nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://api-server:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# docker-compose.yml
version: '3'
services:
frontend:
build: .
ports:
- "80:80"
depends_on:
- api-server
api-server:
image: your-api-server-image
ports:
- "8080:8080"❓ 常见问题
9.1 热更新问题
9.1.1 HMR 不生效
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
// 确保 HMR 连接正确
hmr: {
// HMR 协议
protocol: 'ws',
// HMR 主机
host: 'localhost',
// HMR 端口
port: 3000,
// 禁用 HMR 覆盖层
overlay: true,
// 启用 HMR 内联
clientPort: 3000
},
// 确保服务器主机配置正确
host: '0.0.0.0',
port: 3000
}
});9.1.2 网络环境问题
- 问题:在局域网或远程开发环境中,HMR 可能不生效
- 解决方案:配置
clientPort和host选项
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
// 允许所有主机访问
host: true,
// 端口
port: 3000,
// 热更新配置
hmr: {
// 客户端端口
clientPort: 3000,
// 禁用覆盖层
overlay: false
}
}
});9.2 路径别名问题
9.2.1 TypeScript 路径别名
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
// 路径别名
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@assets': path.resolve(__dirname, './src/assets')
}
}
});
// tsconfig.json
{
"compilerOptions": {
// 其他配置...
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@assets/*": ["src/assets/*"]
}
}
}9.2.2 路径别名不生效
- 问题:在某些情况下,路径别名可能不生效
- 解决方案:
- 确保
vite.config.js中的别名配置正确 - 确保
tsconfig.json中的路径配置与 Vite 配置一致 - 重启开发服务器
- 检查是否有拼写错误
- 确保
9.3 依赖预构建问题
9.3.1 依赖预构建失败
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
// 依赖预构建配置
optimizeDeps: {
// 需要预构建的依赖
include: [
'lodash-es',
'axios',
'echarts'
],
// 排除不需要预构建的依赖
exclude: [
'vue',
'vue-router'
],
// 强制预构建
force: true
}
});9.3.2 依赖缓存问题
- 问题:依赖预构建缓存导致的问题
- 解决方案:
- 删除
.vite目录,重新启动开发服务器 - 在
vite.config.js中设置force: true强制重新预构建 - 检查依赖版本是否正确
- 删除
9.4 构建问题
9.4.1 构建失败
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
// 构建目标
target: 'es2015',
// 输出目录
outDir: 'dist',
// 清除输出目录
emptyOutDir: true,
// 生成源映射
sourcemap: false,
// 代码压缩
minify: 'terser',
// 禁用 CSS 代码分割
cssCodeSplit: true,
// 禁用动态导入的代码分割
dynamicImportVars: true
}
});9.4.2 构建产物过大
- 问题:构建产物过大,影响加载速度
- 解决方案:
- 使用代码分割,合理分割代码
- 启用 Tree Shaking,移除未使用的代码
- 使用按需加载,减少初始加载体积
- 优化图片和静态资源
- 使用 CDN 加载第三方库
9.5 环境变量问题
9.5.1 环境变量不生效
- 问题:环境变量在代码中不生效
- 解决方案:
- 确保环境变量文件命名正确(如
.env.development) - 确保环境变量以
VITE_前缀开头 - 重启开发服务器
- 检查环境变量文件是否被忽略(如
.gitignore)
- 确保环境变量文件命名正确(如
9.5.2 环境变量类型问题
// src/vite-env.d.ts
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
// 自定义环境变量类型
declare interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
readonly VITE_API_BASE_URL: string
readonly VITE_APP_DEBUG: string
}
declare interface ImportMeta {
readonly env: ImportMetaEnv
}9.6 其他常见问题
9.6.1 浏览器兼容性
- 问题:构建产物在某些浏览器中不兼容
- 解决方案:使用
@vitejs/plugin-legacy插件
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import legacy from '@vitejs/plugin-legacy'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
legacy({
targets: ['defaults', 'not IE 11'],
renderLegacyChunks: true,
polyfills: ['es.promise.finally', 'es/map', 'es/set']
})
]
});9.6.2 静态资源加载
- 问题:静态资源加载失败
- 解决方案:
- 检查资源路径是否正确
- 确保资源文件存在
- 配置
publicDir和assetsInclude选项
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
// 静态资源目录
publicDir: 'public',
// 静态资源包含
assetsInclude: ['**/*.gltf', '**/*.glb', '**/*.mp4']
});🎉 总结
Vite 作为现代前端构建工具的代表,以其极速的开发体验和优化的构建输出,已经成为前端开发的首选工具之一。通过本文的学习,我们了解了 Vite 的核心特性、配置选项和最佳实践,可以更好地利用 Vite 提升开发效率和构建质量。
核心优势回顾
- 极速开发服务器:利用原生 ES 模块,无需打包,启动速度极快
- 即时热模块替换:修改代码后立即看到效果,无需等待重新构建
- 优化的生产构建:使用 Rollup 进行生产构建,产物体积小、性能优
- 丰富的插件生态:支持各种前端框架和工具
- 内置 TypeScript 支持:无需额外配置即可使用 TypeScript
- 智能的路径别名:简化模块导入路径
- 环境变量管理:内置多环境配置支持
最佳实践总结
- 项目结构:使用清晰的目录结构,模块化配置文件
- 开发流程:使用 TypeScript,实施代码规范,自动化测试
- 性能优化:合理使用插件,优化构建配置,实施缓存策略
- 部署策略:多环境部署,Docker 部署,CDN 缓存
未来展望
Vite 团队不断迭代更新,为前端开发带来更多惊喜:
- Vite 5:带来了更快的构建速度和更小的构建产物
- Vite SSR:服务端渲染支持
- Vite PWA:渐进式 Web 应用支持
- Vite 插件生态:越来越丰富的插件生态
通过合理使用 Vite,我们可以构建出更高效、更可维护的前端应用,为用户提供更好的体验。
📚 参考资源
10.1 官方文档
10.2 学习资源
10.2.1 教程
10.2.2 视频教程
10.2.3 博客和文章
10.3 工具和插件
10.3.1 官方插件
10.3.2 第三方插件
- unplugin-auto-import
- unplugin-vue-components
- unplugin-icons
- vite-plugin-pwa
- vite-plugin-compression
- rollup-plugin-visualizer
10.4 社区和论坛
10.5 相关工具
通过这些资源,你可以更深入地了解 Vite,掌握其高级用法,为你的前端开发之旅增添助力。
Vite 通过其快速的开发服务器和优化的构建流程,为现代前端开发提供了极佳的开发体验。通过合理配置和最佳实践,可以充分发挥 Vite 的优势。