Appearance
Vite现代构建工具
课程概述
本章节深入探讨 Vite 现代构建工具,了解其核心原理、优势特性、配置方法以及在 React 项目中的最佳实践。Vite 是新一代前端构建工具,它利用浏览器原生 ES 模块功能和现代 JavaScript 工具链,为开发者提供极速的开发体验。
学习目标
- 理解 Vite 的核心工作原理和设计理念
- 掌握 Vite 在 React 项目中的配置和使用
- 了解 Vite 与传统构建工具的区别
- 学习 Vite 的性能优化策略
- 掌握 Vite 的开发服务器和生产构建
- 理解 Vite 的插件系统和生态
第一部分:Vite 简介
1.1 什么是 Vite
Vite(法语意为"快速的")是由 Vue.js 作者尤雨溪创建的新一代前端构建工具。它诞生于 2020 年,旨在解决传统构建工具在大型项目中启动缓慢的问题。
核心特性:
- 极速的服务器启动 - 无需打包,即时启动开发服务器
- 快速的热模块替换(HMR) - 无论应用规模多大,HMR 始终快速
- 真正的按需编译 - 只编译当前页面需要的代码
- 丰富的功能 - 对 TypeScript、JSX、CSS 等开箱即用
- 优化的构建 - 预配置 Rollup 构建,输出高度优化的静态资源
- 通用的插件接口 - Rollup 插件兼容,丰富的插件生态
1.2 Vite 的诞生背景
传统构建工具的痛点:
在 Vite 出现之前,前端开发主要使用 Webpack、Parcel 等打包工具:
javascript
// 传统开发流程
1. 启动开发服务器 → 构建整个应用 → 服务启动 (可能需要几十秒甚至几分钟)
2. 修改代码 → 重新构建模块 → 热更新 (延迟明显)
3. 项目越大,启动和热更新越慢Vite 的解决方案:
javascript
// Vite 开发流程
1. 启动开发服务器 → 即时启动 (通常 < 1 秒)
2. 修改代码 → 精确热更新 → 几乎瞬间完成
3. 项目规模不影响启动和更新速度1.3 Vite 的核心原理
开发环境原理
Vite 在开发环境利用浏览器原生的 ES 模块支持:
javascript
// 传统打包工具:需要先打包所有模块
Bundle → Dev Server → Browser
// Vite:直接提供 ES 模块
Dev Server (ESM) → Browser (Native Import)工作流程:
- 使用 esbuild 预构建依赖 - 将 CommonJS/UMD 转换为 ESM
- 源码使用原生 ESM - 浏览器直接请求需要的模块
- 按需编译 - 只编译浏览器请求的模块
- 利用 HTTP 缓存 - 依赖模块强缓存,源码模块协商缓存
javascript
// index.html
<!DOCTYPE html>
<html>
<head>
<script type="module" src="/src/main.jsx"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
// main.jsx (浏览器直接请求)
import React from 'react' // 预构建的依赖
import App from './App' // 源码,按需编译生产环境原理
虽然原生 ESM 已被广泛支持,但在生产环境使用未打包的 ESM 仍然存在网络性能问题:
javascript
// Vite 生产构建使用 Rollup
1. Tree-shaking
2. 代码分割
3. 压缩优化
4. 静态资源处理1.4 为什么选择 Vite
性能优势:
javascript
// 启动速度对比 (大型项目)
Webpack: 30-60 秒
Vite: < 1 秒
// HMR 速度对比
Webpack: 2-5 秒
Vite: < 100 毫秒开发体验优势:
- 零配置 - 开箱即用,默认配置已经很好
- 快速反馈 - 修改代码立即看到效果
- 现代化 - 原生支持 TS、JSX、CSS Modules 等
- 灵活性 - 丰富的插件系统,易于扩展
第二部分:Vite 快速开始
2.1 环境要求
Vite 需要 Node.js 版本 18+ 或 20+:
bash
# 检查 Node.js 版本
node -v
# 推荐使用 Node.js 20 LTS2.2 创建 Vite 项目
使用 npm
bash
# 创建新项目
npm create vite@latest
# 按提示选择:
# Project name: my-react-app
# Select a framework: React
# Select a variant: TypeScript + SWC使用指定模板
bash
# 直接创建 React + TypeScript 项目
npm create vite@latest my-react-app -- --template react-ts
# 可用模板:
# vanilla, vanilla-ts
# vue, vue-ts
# react, react-ts, react-swc, react-swc-ts
# preact, preact-ts
# lit, lit-ts
# svelte, svelte-ts项目结构
my-react-app/
├── node_modules/
├── public/
│ └── vite.svg
├── src/
│ ├── assets/
│ │ └── react.svg
│ ├── App.css
│ ├── App.tsx
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts
├── .gitignore
├── index.html # 入口 HTML
├── package.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts # Vite 配置文件2.3 启动开发服务器
bash
# 安装依赖
npm install
# 启动开发服务器
npm run dev
# 输出:
# VITE v5.0.0 ready in 500 ms
#
# ➜ Local: http://localhost:5173/
# ➜ Network: use --host to expose开发服务器特性:
javascript
// 1. 极速启动
// 2. 热模块替换 (HMR)
// 3. 源码映射 (Source Maps)
// 4. 错误覆盖层 (Error Overlay)2.4 项目配置
基础的 vite.config.ts:
typescript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
port: 3000, // 自定义端口
open: true, // 自动打开浏览器
cors: true, // 允许跨域
},
build: {
outDir: 'dist', // 输出目录
sourcemap: true, // 生成 source map
},
})2.5 基础使用示例
导入静态资源
typescript
// src/App.tsx
import { useState } from 'react'
import reactLogo from './assets/react.svg' // 导入图片
import './App.css' // 导入 CSS
function App() {
const [count, setCount] = useState(0)
return (
<div className="App">
<div>
<img src={reactLogo} className="logo react" alt="React logo" />
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
</div>
</div>
)
}
export default App环境变量
typescript
// .env
VITE_API_URL=https://api.example.com
// .env.development
VITE_API_URL=http://localhost:3001
// .env.production
VITE_API_URL=https://api.production.comtypescript
// 使用环境变量
const apiUrl = import.meta.env.VITE_API_URL
const isDev = import.meta.env.DEV
const isProd = import.meta.env.PROD
console.log('API URL:', apiUrl)
console.log('Is Development:', isDev)第三部分:深入理解 Vite
3.1 依赖预构建
Vite 使用 esbuild 预构建依赖,这是 Vite 快速的关键:
javascript
// node_modules/.vite/deps/ 目录结构
.vite/
└── deps/
├── react.js
├── react-dom_client.js
└── _metadata.json预构建的目的:
- CommonJS 和 UMD 兼容性 - 转换为 ESM
- 性能优化 - 减少模块请求数量
typescript
// vite.config.ts
export default defineConfig({
optimizeDeps: {
include: ['lodash-es', 'axios'], // 强制预构建
exclude: ['your-esm-package'], // 排除预构建
esbuildOptions: {
define: {
global: 'globalThis' // 定义全局变量
}
}
}
})依赖发现
Vite 自动发现需要预构建的依赖:
javascript
// 第一次运行时
1. 扫描所有源码中的 import
2. 检测需要预构建的依赖
3. 使用 esbuild 构建
4. 缓存到 node_modules/.vite
// 后续运行
直接使用缓存,除非:
- package.json 的 dependencies 改变
- 包管理器的 lockfile 改变
- vite.config.ts 相关配置改变3.2 模块热替换 (HMR)
Vite 提供了一套原生 ESM 的 HMR API:
typescript
// src/components/Counter.tsx
import { useState } from 'react'
export function Counter() {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
)
}
// HMR API (React 插件自动处理)
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// 模块更新时的回调
})
}HMR 工作原理:
javascript
// 1. 文件改变
src/components/Counter.tsx 修改
// 2. Vite 检测到改变
通过 chokidar 监听文件系统
// 3. 重新编译模块
只编译改变的模块及其依赖
// 4. WebSocket 推送更新
Server → Client: { type: 'update', path: '/src/components/Counter.tsx' }
// 5. 浏览器更新模块
动态 import 新模块,替换旧模块自定义 HMR:
typescript
// 处理状态保持
if (import.meta.hot) {
import.meta.hot.accept()
import.meta.hot.dispose((data) => {
// 保存状态
data.count = count
})
if (import.meta.hot.data) {
// 恢复状态
count = import.meta.hot.data.count
}
}3.3 CSS 处理
Vite 原生支持多种 CSS 方案:
普通 CSS
typescript
// 直接导入 CSS
import './style.css'
// CSS 会被注入到页面中CSS Modules
css
/* Button.module.css */
.button {
background: blue;
color: white;
}
.primary {
background: green;
}typescript
// Button.tsx
import styles from './Button.module.css'
function Button() {
return (
<button className={styles.button}>
Click me
</button>
)
}CSS 预处理器
bash
# 安装预处理器
npm install -D sass
npm install -D less
npm install -D stylusscss
// styles.scss
$primary-color: #3498db;
.container {
background: $primary-color;
.title {
font-size: 2rem;
}
}typescript
// 直接导入
import './styles.scss'PostCSS
bash
# 安装 PostCSS 和插件
npm install -D postcss autoprefixer tailwindcssjavascript
// postcss.config.js
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}CSS-in-JS
typescript
// 使用 styled-components
import styled from 'styled-components'
const Button = styled.button`
background: blue;
color: white;
padding: 10px 20px;
&:hover {
background: darkblue;
}
`3.4 静态资源处理
导入资源为 URL
typescript
// 导入图片
import imgUrl from './assets/logo.png'
// imgUrl 是资源的公共路径
<img src={imgUrl} alt="Logo" />导入资源为字符串
typescript
// 导入为原始字符串
import shaderCode from './shader.glsl?raw'
// 导入 Web Worker
import Worker from './worker?worker'
const worker = new Worker()公共资源
public/
├── favicon.ico
├── robots.txt
└── images/
└── hero.jpghtml
<!-- 直接引用 public 目录下的资源 -->
<img src="/images/hero.jpg" alt="Hero" />资源优化
typescript
// vite.config.ts
export default defineConfig({
build: {
assetsInlineLimit: 4096, // 小于 4kb 的资源内联为 base64
rollupOptions: {
output: {
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'chunks/[name]-[hash].js',
entryFileNames: 'entries/[name]-[hash].js',
}
}
}
})3.5 TypeScript 支持
Vite 原生支持 TypeScript:
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": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}注意事项:
- Vite 只进行转译,不进行类型检查
- 类型检查应该由 IDE 和构建流程处理
json
// package.json
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build", // 构建前类型检查
"type-check": "tsc --noEmit" // 单独类型检查
}
}第四部分:Vite 构建优化
4.1 代码分割
Vite 使用 Rollup 的代码分割功能:
typescript
// 动态导入自动分割
const UserProfile = lazy(() => import('./components/UserProfile'))
// 手动分割配置
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'lodash': ['lodash-es'],
}
}
}
}
})自动分割策略
typescript
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// 将 node_modules 中的模块分割到 vendor chunk
if (id.includes('node_modules')) {
return 'vendor'
}
// 根据路径分割
if (id.includes('/src/components/')) {
return 'components'
}
}
}
}
}
})4.2 Tree Shaking
Vite 利用 ES 模块的静态结构进行 Tree Shaking:
typescript
// utils.ts
export function usedFunction() {
return 'This will be included'
}
export function unusedFunction() {
return 'This will be removed'
}
// main.ts
import { usedFunction } from './utils'
console.log(usedFunction())
// unusedFunction 会被 tree-shake 掉优化建议:
typescript
// 1. 使用 ES 模块导入
import { specific } from 'package' // 好
const pkg = require('package') // 不好
// 2. 避免副作用
// package.json
{
"sideEffects": false, // 表示包没有副作用
// 或
"sideEffects": ["*.css"] // 只有 CSS 有副作用
}
// 3. 使用具名导出
export { foo, bar } // 好
export default { foo, bar } // 不好4.3 生产构建
bash
# 构建生产版本
npm run build
# 构建输出
dist/
├── assets/
│ ├── index-abc123.css
│ ├── index-def456.js
│ └── logo-ghi789.png
└── index.html构建配置:
typescript
// vite.config.ts
export default defineConfig({
build: {
target: 'es2015', // 浏览器兼容目标
outDir: 'dist', // 输出目录
assetsDir: 'assets', // 静态资源目录
minify: 'terser', // 压缩方式
terserOptions: {
compress: {
drop_console: true, // 移除 console
drop_debugger: true, // 移除 debugger
}
},
sourcemap: false, // 是否生成 sourcemap
chunkSizeWarningLimit: 500, // chunk 大小警告限制
cssCodeSplit: true, // CSS 代码分割
}
})4.4 预览构建
bash
# 预览生产构建
npm run preview
# 输出:
# VITE v5.0.0 built in 2.5s
#
# ➜ Local: http://localhost:4173/
# ➜ Network: use --host to exposetypescript
// vite.config.ts
export default defineConfig({
preview: {
port: 8080,
open: true,
}
})4.5 压缩优化
Gzip 压缩
bash
npm install -D vite-plugin-compressiontypescript
// vite.config.ts
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
react(),
viteCompression({
algorithm: 'gzip',
ext: '.gz',
threshold: 10240, // 大于 10kb 才压缩
})
]
})Brotli 压缩
typescript
export default defineConfig({
plugins: [
react(),
viteCompression({
algorithm: 'brotliCompress',
ext: '.br',
threshold: 10240,
})
]
})第五部分:Vite 插件系统
5.1 使用插件
Vite 插件系统基于 Rollup 插件接口:
typescript
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
react(),
visualizer({
open: true,
gzipSize: true,
brotliSize: true,
})
]
})5.2 常用插件
React 插件
bash
# React with SWC (推荐,更快)
npm install -D @vitejs/plugin-react-swc
# React with Babel
npm install -D @vitejs/plugin-reacttypescript
import react from '@vitejs/plugin-react-swc'
export default defineConfig({
plugins: [
react({
// SWC 选项
jsxImportSource: '@emotion/react',
})
]
})SVG 插件
bash
npm install -D vite-plugin-svgrtypescript
import svgr from 'vite-plugin-svgr'
export default defineConfig({
plugins: [
react(),
svgr({
svgrOptions: {
icon: true,
}
})
]
})typescript
// 使用
import { ReactComponent as Logo } from './logo.svg'
function App() {
return <Logo />
}PWA 插件
bash
npm install -D vite-plugin-pwatypescript
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [
react(),
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: 'My App',
short_name: 'App',
theme_color: '#ffffff',
icons: [
{
src: '/icon-192.png',
sizes: '192x192',
type: 'image/png'
}
]
}
})
]
})自动导入插件
bash
npm install -D unplugin-auto-importtypescript
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
react(),
AutoImport({
imports: ['react', 'react-router-dom'],
dts: 'src/auto-imports.d.ts',
})
]
})typescript
// 无需手动导入
// import { useState, useEffect } from 'react'
function App() {
const [count, setCount] = useState(0) // 自动导入
useEffect(() => {
console.log(count)
}, [count])
}5.3 创建自定义插件
简单插件
typescript
// plugins/myPlugin.ts
import type { Plugin } from 'vite'
export function myPlugin(): Plugin {
return {
name: 'my-plugin',
// 开发服务器启动时调用
configureServer(server) {
console.log('Dev server started')
},
// 转换代码
transform(code, id) {
if (id.endsWith('.custom')) {
return {
code: transformCode(code),
map: null
}
}
}
}
}完整示例:自动注入版本号
typescript
// plugins/injectVersion.ts
import type { Plugin } from 'vite'
export function injectVersion(): Plugin {
return {
name: 'inject-version',
transformIndexHtml(html) {
const version = process.env.npm_package_version
return html.replace(
'</head>',
`<meta name="version" content="${version}"></head>`
)
},
transform(code, id) {
if (id.endsWith('.tsx') || id.endsWith('.ts')) {
return code.replace(
'__APP_VERSION__',
JSON.stringify(process.env.npm_package_version)
)
}
}
}
}typescript
// vite.config.ts
import { injectVersion } from './plugins/injectVersion'
export default defineConfig({
plugins: [
react(),
injectVersion()
]
})typescript
// 使用
console.log('App version:', __APP_VERSION__)第六部分:Vite 高级特性
6.1 多页面应用
typescript
// vite.config.ts
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'),
}
}
}
})project/
├── index.html
├── admin/
│ └── index.html
├── mobile/
│ └── index.html
└── src/
├── main.tsx
├── admin.tsx
└── mobile.tsx6.2 Library 模式
构建一个库:
typescript
// vite.config.ts
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: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM'
}
}
}
}
})typescript
// src/index.ts
export { Button } from './components/Button'
export { Input } from './components/Input'
export type { ButtonProps } from './components/Button'6.3 后端集成
Express 集成
typescript
// server.js
import express from 'express'
import { createServer as createViteServer } from 'vite'
async function createServer() {
const app = express()
// 创建 Vite 服务器
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'custom'
})
// 使用 Vite 的中间件
app.use(vite.middlewares)
app.use('*', async (req, res) => {
try {
// 读取 index.html
let template = fs.readFileSync(
path.resolve(__dirname, 'index.html'),
'utf-8'
)
// 应用 Vite HTML 转换
template = await vite.transformIndexHtml(req.originalUrl, template)
// 渲染应用
const { render } = await vite.ssrLoadModule('/src/entry-server.tsx')
const appHtml = await render(req.originalUrl)
const html = template.replace(`<!--app-html-->`, appHtml)
res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
} catch (e) {
vite.ssrFixStacktrace(e)
res.status(500).end(e.stack)
}
})
app.listen(3000)
}
createServer()6.4 SSR 支持
typescript
// vite.config.ts
export default defineConfig({
build: {
ssr: true,
rollupOptions: {
input: './src/entry-server.tsx'
}
}
})typescript
// src/entry-server.tsx
import { renderToString } from 'react-dom/server'
import App from './App'
export function render() {
const html = renderToString(<App />)
return { html }
}6.5 Web Worker
typescript
// worker.ts
self.addEventListener('message', (e) => {
const result = e.data * 2
self.postMessage(result)
})typescript
// 使用 Worker
import MyWorker from './worker?worker'
const worker = new MyWorker()
worker.postMessage(10)
worker.addEventListener('message', (e) => {
console.log('Result:', e.data) // 20
})Worker 配置:
typescript
// vite.config.ts
export default defineConfig({
worker: {
format: 'es', // 'es' | 'iife'
plugins: [
// Worker 特定插件
]
}
})第七部分:性能优化实践
7.1 开发环境优化
减少依赖预构建
typescript
export default defineConfig({
optimizeDeps: {
entries: ['src/main.tsx'], // 限制入口文件
exclude: [
'large-package-not-used-initially'
]
}
})使用 SWC 替代 Babel
bash
npm install -D @vitejs/plugin-react-swctypescript
// 更快的 JSX 转换
import react from '@vitejs/plugin-react-swc'
export default defineConfig({
plugins: [react()]
})7.2 生产环境优化
减小包体积
typescript
export default defineConfig({
build: {
// 启用 CSS 代码分割
cssCodeSplit: true,
// 移除 console 和 debugger
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log']
}
},
// 分割大块
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'router': ['react-router-dom'],
'ui': ['@mui/material']
}
}
}
}
})资源优化
typescript
export default defineConfig({
build: {
// 图片内联限制
assetsInlineLimit: 4096,
// 静态资源目录
assetsDir: 'assets',
rollupOptions: {
output: {
// 自定义文件命名
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.')
const ext = info[info.length - 1]
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(ext)) {
return `images/[name]-[hash][extname]`
}
if (/woff2?|ttf|otf|eot/i.test(ext)) {
return `fonts/[name]-[hash][extname]`
}
return `assets/[name]-[hash][extname]`
}
}
}
}
})7.3 缓存策略
typescript
export default defineConfig({
build: {
rollupOptions: {
output: {
// 使用 hash 命名,利用浏览器缓存
entryFileNames: 'js/[name]-[hash].js',
chunkFileNames: 'js/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash][extname]'
}
}
},
// 开发环境缓存
cacheDir: 'node_modules/.vite'
})7.4 监控和分析
Bundle 分析
bash
npm install -D rollup-plugin-visualizertypescript
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
react(),
visualizer({
open: true,
filename: 'dist/stats.html',
gzipSize: true,
brotliSize: true,
})
]
})构建性能分析
typescript
export default defineConfig({
build: {
// 启用性能分析
reportCompressedSize: true,
// Rollup 性能分析
rollupOptions: {
plugins: [
{
name: 'timing',
buildStart() {
this.buildStartTime = Date.now()
},
buildEnd() {
console.log(
`Build time: ${Date.now() - this.buildStartTime}ms`
)
}
}
]
}
}
})第八部分:迁移到 Vite
8.1 从 Create React App 迁移
1. 安装依赖
bash
npm install -D vite @vitejs/plugin-react-swc2. 创建配置文件
typescript
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
},
build: {
outDir: 'build',
}
})3. 更新 index.html
html
<!-- CRA -->
<script src="%PUBLIC_URL%/index.js"></script>
<!-- Vite -->
<script type="module" src="/src/main.tsx"></script>4. 更新环境变量
bash
# CRA
REACT_APP_API_URL=xxx
# Vite
VITE_API_URL=xxxtypescript
// CRA
process.env.REACT_APP_API_URL
// Vite
import.meta.env.VITE_API_URL5. 更新 package.json
json
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
}
}8.2 从 Webpack 迁移
处理别名
typescript
// webpack.config.js
{
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
}
// vite.config.ts
import { resolve } from 'path'
export default defineConfig({
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
}
})处理全局变量
typescript
// webpack.config.js
new webpack.DefinePlugin({
__DEV__: JSON.stringify(true)
})
// vite.config.ts
export default defineConfig({
define: {
__DEV__: JSON.stringify(true)
}
})处理静态资源
typescript
// Webpack
import logo from './logo.png'
// Vite (相同)
import logo from './logo.png'
// Webpack raw-loader
import txt from 'raw-loader!./file.txt'
// Vite
import txt from './file.txt?raw'第九部分:故障排除
9.1 常见问题
依赖预构建问题
bash
# 清除预构建缓存
rm -rf node_modules/.vite
# 或使用命令
npx vite --force端口占用
typescript
export default defineConfig({
server: {
port: 3000,
strictPort: false, // 端口被占用时自动尝试下一个
}
})CORS 问题
typescript
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})9.2 调试技巧
启用调试日志
bash
# 开发环境
DEBUG=vite:* vite
# 构建
DEBUG=vite:* vite build源码映射
typescript
export default defineConfig({
build: {
sourcemap: true, // 或 'inline' | 'hidden'
}
})第十部分:最佳实践总结
10.1 项目结构
src/
├── assets/ # 静态资源
├── components/ # 组件
├── hooks/ # 自定义 Hooks
├── pages/ # 页面
├── services/ # API 服务
├── stores/ # 状态管理
├── styles/ # 全局样式
├── types/ # 类型定义
├── utils/ # 工具函数
├── App.tsx
└── main.tsx10.2 配置建议
typescript
// vite.config.ts - 完整配置示例
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { resolve } from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
'@components': resolve(__dirname, 'src/components'),
'@utils': resolve(__dirname, 'src/utils'),
}
},
server: {
port: 3000,
open: true,
cors: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
}
}
},
build: {
target: 'es2015',
outDir: 'dist',
sourcemap: false,
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
}
},
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'router': ['react-router-dom'],
}
}
}
},
optimizeDeps: {
include: ['react', 'react-dom'],
}
})10.3 开发建议
- 使用 TypeScript - 获得更好的类型安全
- 合理使用代码分割 - 提升加载性能
- 优化依赖 - 只导入需要的模块
- 使用环境变量 - 区分不同环境配置
- 启用 HMR - 提升开发效率
- 配置路径别名 - 简化导入路径
- 使用合适的插件 - 扩展功能
- 定期更新依赖 - 获得最新特性和修复
10.4 性能检查清单
- [ ] 启用代码分割
- [ ] 配置合理的 chunk 策略
- [ ] 压缩资源 (Gzip/Brotli)
- [ ] 优化图片资源
- [ ] 启用 Tree Shaking
- [ ] 移除未使用的依赖
- [ ] 使用动态导入
- [ ] 配置缓存策略
- [ ] 分析 bundle 大小
- [ ] 监控构建性能
总结
Vite 作为新一代构建工具,通过利用现代浏览器特性和优秀的工程设计,为开发者提供了极致的开发体验:
- 极速的开发启动 - 无需等待,即时启动
- 快速的热更新 - 精确更新,即时反馈
- 优化的生产构建 - 高效打包,性能卓越
- 丰富的生态系统 - 插件众多,易于扩展
- 简单的配置 - 开箱即用,配置简单
掌握 Vite 能够显著提升 React 项目的开发效率和应用性能,是现代前端开发者必备的技能之一。