> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Vite 初级指南
- URL: https://blog.vercanti.com/vite-chu-ji-zhi-nan/
- Published: 2026-08-28T14:35:23.000Z
- Updated: 2026-08-28T14:58:44.000Z
- Description: Vite 是一个现代前端构建工具，由 Vue 作者尤雨溪创建。它的核心设计目标是解决传统打包工具（如 Webpack）在大型项目中开发体验缓慢的问题。 Webpack 的工作方式是在启动开发服务器前，先把所有模块打包成 bundle，然后再提供服务。随着项目规模增大，这个打包过程会越来越慢，冷启动时间可能长达数十秒甚至数分钟。 Vite 采用了完全不同的策略： Vite 在不同阶段使用不同策略： 这种分离设计保证了开发体验极速，同时生产产物质量有保障。 Vite 5+ 要求 Node.js 版本： 建议使用 LTS 版本。可用 node -v 检查当前版
- Author: yellowdog
- Tags: 前端开发, Vite

> 官方文档：<https://cn.vitejs.dev/>  
> 适用版本：Vite 5.x（2026-05-07 核实）

## 1\. Vite 是什么

Vite 是一个现代前端构建工具，由 Vue 作者尤雨溪创建。它的核心设计目标是解决传统打包工具（如 Webpack）在大型项目中开发体验缓慢的问题。

### 和 Webpack 的对比：为什么更快

Webpack 的工作方式是在启动开发服务器前，先把所有模块打包成 bundle，然后再提供服务。随着项目规模增大，这个打包过程会越来越慢，冷启动时间可能长达数十秒甚至数分钟。

Vite 采用了完全不同的策略：

- 开发阶段：利用浏览器原生 ES Module（ESM）支持，直接按需提供源文件，不需要提前打包。浏览器请求哪个模块，Vite 就处理哪个模块，启动时间极短（通常不超过 1 秒）。
- 依赖预构建：第三方库（node\_modules）用 esbuild 提前处理，esbuild 用 Go 编写，比 JavaScript 工具快 10-100 倍。
- 热更新（HMR）：修改文件后只更新变化的模块，而不是重新打包整个应用，速度极快且不随项目体积增大而变慢。

| 维度    | Webpack    | Vite                |
| ----- | ---------- | ------------------- |
| 开发启动  | 打包所有模块后启动  | 直接启动，按需编译           |
| 热更新速度 | 随项目变大变慢    | 始终极快（模块级别）          |
| 底层工具  | JavaScript | esbuild（Go）+ Rollup |
| 生产构建  | Webpack 打包 | Rollup 打包           |
| 配置复杂度 | 较高         | 较低，约定优于配置           |

### 开发服务器 vs 生产构建

Vite 在不同阶段使用不同策略：

- 开发服务器：基于原生 ESM，浏览器直接处理模块图，Vite 只做必要的转换（如 TypeScript 编译、JSX 转换）
- 生产构建：使用 Rollup 打包，因为 Rollup 的 tree-shaking 和代码分割能力更成熟，产物更优化

这种分离设计保证了开发体验极速，同时生产产物质量有保障。

### 适用场景

- 单页应用（SPA）：Vue、React、Svelte 等框架项目
- 多页应用（MPA）：多个独立 HTML 入口
- 库开发：构建可发布的 JavaScript 库
- 原型快速搭建：极低的启动成本
- 不适合：需要兼容 IE11 或极老旧浏览器的场景（可用 @vitejs/plugin-legacy 补救，但有性能代价）

---

## 2\. 安装与创建项目

### Node.js 版本要求

Vite 5+ 要求 Node.js 版本：

- `18.x`（18.0.0+）
- `20.x`（20.19.0+）
- `22.x`（22.12.0+）

建议使用 LTS 版本。可用 `node -v` 检查当前版本。

### 使用 `npm create vite@latest` 创建项目

这是最推荐的方式，会交互式引导选择框架和语言：

```bash
npm create vite@latest

```

也可以直接指定项目名和模板，跳过交互：

```bash
# 格式：npm create vite@latest <项目名> -- --template <模板名>
npm create vite@latest my-app -- --template vue
npm create vite@latest my-app -- --template react-ts

```

等价的其他包管理器写法：

```bash
# yarn
yarn create vite my-app --template vue

# pnpm
pnpm create vite my-app --template react

# bun
bun create vite my-app --template svelte

```

### 官方模板列表

| 模板名          | 框架                  | 语言         |
| ------------ | ------------------- | ---------- |
| vanilla      | 无框架                 | JavaScript |
| vanilla-ts   | 无框架                 | TypeScript |
| vue          | Vue 3               | JavaScript |
| vue-ts       | Vue 3               | TypeScript |
| react        | React               | JavaScript |
| react-ts     | React               | TypeScript |
| react-swc    | React（SWC 编译）       | JavaScript |
| react-swc-ts | React（SWC 编译）       | TypeScript |
| preact       | Preact              | JavaScript |
| preact-ts    | Preact              | TypeScript |
| lit          | Lit（Web Components） | JavaScript |
| lit-ts       | Lit                 | TypeScript |
| svelte       | Svelte              | JavaScript |
| svelte-ts    | Svelte              | TypeScript |
| solid        | Solid.js            | JavaScript |
| solid-ts     | Solid.js            | TypeScript |
| qwik         | Qwik                | JavaScript |
| qwik-ts      | Qwik                | TypeScript |

### 手动安装方式

如果需要将 Vite 加入已有项目：

```bash
# 安装 Vite
npm install -D vite

# 若使用 Vue，还需要安装插件
npm install -D @vitejs/plugin-vue

# 若使用 React，还需要安装插件
npm install -D @vitejs/plugin-react

```

然后在 `package.json` 中添加脚本：

```json
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

```

并在项目根目录创建 `index.html` 作为入口（详见第 3 节）。

### 创建项目后的步骤

```bash
cd my-app
npm install
npm run dev

```

---

## 3\. 项目结构

### 典型目录结构

```
my-project/
├── public/              # 静态资源（不经过 Vite 处理，直接复制到 dist/）
│   └── favicon.ico
├── src/
│   ├── assets/          # 经过 Vite 处理的资源（图片、字体等）
│   ├── components/      # 组件
│   ├── main.js          # JavaScript 入口文件
│   └── App.vue          # 根组件（Vue 示例）
├── index.html           # HTML 入口（Vite 项目核心）
├── vite.config.js       # Vite 配置文件
├── package.json
└── .env                 # 环境变量文件

```

### index.html 为什么是核心

在 Webpack 项目中，`index.html` 通常放在 `public/` 目录，是一个模板文件，由 `html-webpack-plugin` 注入打包后的 bundle 路径。真正的入口是 `webpack.config.js` 里指定的 JS 文件。

Vite 的设计截然不同：`index.html` 就是项目真正的入口，放在项目根目录。Vite 把 `index.html` 视为模块图的一部分，直接解析其中的 `<script type="module">` 标签，从而找到 JS 入口：

```html
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My App</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- Vite 从这里找到入口，不需要额外配置 -->
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

```

这个设计带来的好处：

- HTML 文件中可以直接使用 `<link>` 和 `<script>` 引用资源，Vite 会自动处理
- 多页应用只需要多个 HTML 文件，不需要复杂配置
- 开发和生产环境的 HTML 处理方式一致

### public 目录 vs src/assets 目录

| 特性   | public/                     | src/assets/              |
| ---- | --------------------------- | ------------------------ |
| 处理方式 | 直接复制，不做任何处理                 | 经过 Vite 处理（hash 文件名、压缩等） |
| 引用方式 | 用绝对路径 /favicon.ico          | 用 import 语句或相对路径         |
| 适合内容 | 不需要处理的文件，如 robots.txt、已压缩的库 | 需要版本化管理的图片、字体、CSS        |
| 缓存控制 | 无 hash，靠服务器配置缓存             | 有内容 hash，可长期缓存           |

---

## 4\. vite.config.js 基础配置

### 完整配置示例

```javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  // 项目根目录（index.html 所在位置）
  root: process.cwd(),

  // 部署的基础路径，部署到子路径时修改此项
  base: '/',

  // 静态资源目录
  publicDir: 'public',

  // 插件列表
  plugins: [vue()],

  // 模块解析选项
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
    },
    extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'],
  },

  // 全局常量替换
  define: {
    __APP_VERSION__: JSON.stringify('1.0.0'),
  },

  // 环境变量文件目录
  envDir: '.',

  // 暴露给客户端的环境变量前缀
  envPrefix: 'VITE_',

  // 日志级别
  logLevel: 'info',

  // 启动时是否清屏
  clearScreen: true,

  // 应用类型
  appType: 'spa',

  // 开发服务器配置
  server: {
    port: 5173,
    open: true,
  },

  // 构建配置
  build: {
    outDir: 'dist',
    minify: 'esbuild',
  },
})

```

### 顶级参数说明

| 参数          | 类型                   | 默认值           | 是否必填     | 说明                                    |                                      |         |
| ----------- | -------------------- | ------------- | -------- | ------------------------------------- | ------------------------------------ | ------- |
| root        | string               | process.cwd() | 否        | 项目根目录，index.html 所在位置，所有相对路径基于此目录解析   |                                      |         |
| base        | string               | '/'           | 否        | 开发和生产的公共基础路径。部署到子路径时必须修改，如 '/my-app/' |                                      |         |
| publicDir   | string \| false      | 'public'      | 否        | 静态资源目录，其中的文件直接复制到输出目录。设为 false 禁用此功能  |                                      |         |
| plugins     | Plugin\[\]           | \[\]          | 否        | 插件数组，Vite 和 Rollup 插件均可使用             |                                      |         |
| define      | Record<string, any>  | {}            | 否        | 定义全局常量替换。值会在编译时直接替换到代码中               |                                      |         |
| envDir      | string               | root          | 否        | 加载 .env 文件的目录                         |                                      |         |
| envPrefix   | string \| string\[\] | 'VITE\_'      | 否        | 以此前缀开头的环境变量才会暴露给客户端代码                 |                                      |         |
| logLevel    | 'info' \| 'warn'     | 'error'       | 'silent' | 'info'                                | 否                                    | 控制台输出级别 |
| clearScreen | boolean              | true          | 否        | 重新打印日志前是否清屏                           |                                      |         |
| appType     | 'spa' \| 'mpa'       | 'custom'      | 'spa'    | 否                                     | 应用类型。mpa 禁用 SPA 回退，custom 禁用 HTML 处理 |         |

### resolve 参数说明

| 参数                 | 类型                              | 默认值                                                       | 是否必填 | 说明                                |
| ------------------ | ------------------------------- | --------------------------------------------------------- | ---- | --------------------------------- |
| resolve.alias      | Record<string, string> \| Array | {}                                                        | 否    | 路径别名，将 @ 等短路径映射到实际目录，简化 import 路径 |
| resolve.extensions | string\[\]                      | \['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'\] | 否    | 无扩展名 import 时自动尝试的后缀列表，从左到右依次尝试   |

路径别名配置示例：

```javascript
import { resolve } from 'path'

export default defineConfig({
  resolve: {
    alias: {
      // 将 @/components/Button 映射到 src/components/Button
      '@': resolve(__dirname, 'src'),
      // 也可以用数组形式，支持正则
      // { find: /^@\//, replacement: resolve(__dirname, 'src') + '/' }
    },
  },
})

```

使用别名后，import 可以这样写：

```javascript
// 不用再写 ../../components/Button
import Button from '@/components/Button.vue'

```

---

## 5\. 开发服务器

### server 参数说明

| 参数                | 类型                           | 默认值           | 是否必填 | 说明                                      |
| ----------------- | ---------------------------- | ------------- | ---- | --------------------------------------- |
| server.host       | string \| boolean            | 'localhost'   | 否    | 监听地址。设为 '0.0.0.0' 或 true 可以让局域网内其他设备访问  |
| server.port       | number                       | 5173          | 否    | 开发服务器端口                                 |
| server.strictPort | boolean                      | false         | 否    | true 时端口被占用直接报错退出，false 时自动尝试下一个可用端口    |
| server.open       | boolean \| string            | false         | 否    | 启动后自动打开浏览器。传字符串则打开指定路径，如 '/docs'        |
| server.proxy      | Record<string, ProxyOptions> | {}            | 否    | 反向代理配置，将匹配的请求转发到其他服务器                   |
| server.cors       | boolean \| CorsOptions       | 仅允许 localhost | 否    | 配置跨域资源共享。true 允许所有来源                    |
| server.https      | HttpsServerOptions           | undefined     | 否    | 启用 TLS。通常配合 @vitejs/plugin-basic-ssl 使用 |
| server.hmr        | boolean \| HmrOptions        | true          | 否    | 热模块替换配置。false 禁用 HMR                    |

### 常用 server 配置示例

```javascript
export default defineConfig({
  server: {
    // 监听所有地址，手机也能访问
    host: '0.0.0.0',
    // 使用 3000 端口
    port: 3000,
    // 端口被占用时报错而非自动换端口
    strictPort: true,
    // 启动后自动打开浏览器
    open: true,
  },
})

```

### 代理配置详细示例

开发时前端跑在 `localhost:5173`，后端 API 跑在 `localhost:8080`，直接请求会因跨域被浏览器拒绝。用代理可以让 Vite 把 `/api` 开头的请求转发到后端：

```javascript
export default defineConfig({
  server: {
    proxy: {
      // 字符串简写：将 /api 开头的请求代理到目标地址
      '/api': 'http://localhost:8080',

      // 对象写法，支持更多选项
      '/api/v2': {
        target: 'http://localhost:8080',
        // 修改请求头中的 Origin 为目标地址（解决某些服务端的 Host 校验）
        changeOrigin: true,
        // 重写路径：去掉 /api 前缀
        // /api/users → /users
        rewrite: (path) => path.replace(/^\/api/, ''),
      },

      // 代理 WebSocket
      '/socket.io': {
        target: 'ws://localhost:8080',
        ws: true,
      },

      // 使用正则匹配
      '^/fallback/.*': {
        target: 'http://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/fallback/, ''),
      },
    },
  },
})

```

代理选项说明：

| 选项           | 类型       | 默认值   | 说明                   |
| ------------ | -------- | ----- | -------------------- |
| target       | string   | \-    | 转发目标地址               |
| changeOrigin | boolean  | false | 是否修改请求头的 Host 为目标域名  |
| rewrite      | Function | \-    | 重写请求路径的函数，参数为原始路径字符串 |
| ws           | boolean  | false | 是否代理 WebSocket       |
| secure       | boolean  | true  | 目标为 HTTPS 时是否验证证书    |

---

## 6\. 环境变量

### .env 文件加载顺序

Vite 按以下顺序加载环境变量文件，后面的文件优先级更高（会覆盖前面的同名变量）：

```
.env                  # 所有环境都加载
.env.local            # 所有环境都加载，但不提交到 Git（应加入 .gitignore）
.env.[mode]           # 只在指定 mode 下加载（如 .env.development、.env.production）
.env.[mode].local     # 只在指定 mode 下加载，不提交到 Git

```

默认 mode：

- `npm run dev` → mode 为 `development`
- `npm run build` → mode 为 `production`

自定义 mode：

```bash
# 加载 .env.staging 文件
vite build --mode staging

```

### VITE\_ 前缀规则

只有以 `VITE_` 开头的变量才会被暴露给客户端代码（打包到最终产物）。没有此前缀的变量只能在 Vite 配置文件（Node.js 环境）中访问，不会泄露给浏览器。

```bash
# .env 文件示例

# 这个变量会暴露给客户端，可在浏览器代码中访问
VITE_API_URL=https://api.example.com
VITE_APP_TITLE=My Application

# 这个变量不会暴露给客户端（没有 VITE_ 前缀）
DATABASE_PASSWORD=secret123

```

### import.meta.env 内置属性

| 属性                        | 类型      | 说明                                     |
| ------------------------- | ------- | -------------------------------------- |
| import.meta.env.MODE      | string  | 当前运行的模式，如 'development' 或 'production' |
| import.meta.env.BASE\_URL | string  | 部署的基础 URL，对应 vite.config.js 中的 base 配置 |
| import.meta.env.PROD      | boolean | 是否为生产环境                                |
| import.meta.env.DEV       | boolean | 是否为开发环境（与 PROD 相反）                     |
| import.meta.env.SSR       | boolean | 是否在服务端渲染环境中运行                          |

在代码中使用：

```javascript
// 获取自定义环境变量
const apiUrl = import.meta.env.VITE_API_URL

// 根据环境执行不同逻辑
if (import.meta.env.DEV) {
  console.log('当前为开发环境')
}

if (import.meta.env.PROD) {
  // 生产环境才启用统计
  initAnalytics()
}

```

### .env 文件示例

```bash
# .env.development
VITE_API_URL=http://localhost:8080/api
VITE_APP_TITLE=My App (Dev)
VITE_ENABLE_MOCK=true

```

```bash
# .env.production
VITE_API_URL=https://api.example.com
VITE_APP_TITLE=My App
VITE_ENABLE_MOCK=false

```

### TypeScript 类型补全

默认情况下 `import.meta.env` 的自定义变量没有类型提示。在 `src/vite-env.d.ts` 中扩展 `ImportMetaEnv` 接口来获得类型提示：

```typescript
// src/vite-env.d.ts
/// <reference types="vite/client" />

interface ImportMetaEnv {
  // 在这里声明自定义环境变量的类型
  readonly VITE_API_URL: string
  readonly VITE_APP_TITLE: string
  readonly VITE_ENABLE_MOCK: string  // .env 中的值都是字符串
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

```

---

## 7\. 静态资源处理

### import 资源文件

Vite 支持直接用 `import` 导入图片、字体等静态资源，返回处理后的资源 URL：

```javascript
// 导入图片，imgUrl 是处理后的 URL（生产环境会带 hash）
import imgUrl from './assets/logo.png'

// 在代码中使用
const img = document.createElement('img')
img.src = imgUrl
document.body.appendChild(img)

```

在 Vue 单文件组件中：

```vue
<template>
  <!-- 模板中可以直接使用相对路径，Vite 自动处理 -->
  <img src="./assets/logo.png" alt="logo" />
</template>

<script setup>
import logoUrl from './assets/logo.png'
</script>

```

### 查询参数修饰符

导入资源时可以加查询参数改变 Vite 的处理方式：

| 查询参数    | 说明                       | 使用场景                  |
| ------- | ------------------------ | --------------------- |
| ?url    | 强制返回 URL 字符串（即使文件很小也不内联） | 需要明确 URL 的情况          |
| ?raw    | 返回文件内容的字符串               | 读取 GLSL shader、文本文件内容 |
| ?inline | 强制内联为 base64 URL（即使文件较大） | 确保资源内联避免额外请求          |

```javascript
// ?url：始终获取 URL，不内联
import iconUrl from './icon.svg?url'

// ?raw：获取文件的原始文本内容
import shaderSource from './shader.glsl?raw'
console.log(shaderSource) // 文件的字符串内容

// ?inline：强制 base64 内联
import smallIcon from './icon.png?inline'
// smallIcon 为 'data:image/png;base64,...'

```

### public 目录 vs src/assets 目录的区别

详细比较：

| 特性          | public/                       | src/assets/          |
| ----------- | ----------------------------- | -------------------- |
| 处理方式        | 原样复制，不做任何转换                   | Vite 处理：压缩、添加 hash 等 |
| 引用方式        | HTML/CSS/JS 中用绝对路径如 /logo.png | 用 import 或相对路径       |
| 能否用 import  | 不能                            | 可以                   |
| 文件名是否带 hash | 否，文件名不变                       | 是，如 logo.a1b2c3.png  |
| 浏览器缓存       | 需要服务器配置 Cache-Control         | 可长期缓存（hash 变化即更新）    |
| 适合什么文件      | robots.txt、favicon、已处理的第三方 JS | 项目自己的图片、字体、图标        |

```html
<!-- public/ 中的文件，用绝对路径引用 -->
<link rel="icon" href="/favicon.ico" />
<img src="/images/hero.jpg" />

```

```javascript
// src/assets/ 中的文件，用 import
import heroImage from './assets/images/hero.jpg'

```

### assetsInlineLimit

小于此阈值的资源会被内联为 base64 URL，避免额外的 HTTP 请求。大于此阈值的资源会生成独立文件。

默认值为 4096 字节（4KB）。在 `vite.config.js` 中配置：

```javascript
export default defineConfig({
  build: {
    // 8KB 以下的资源内联，设为 0 禁用内联
    assetsInlineLimit: 8192,
  },
})

```

---

## 8\. 常用插件

### 官方插件

| 插件                       | 安装命令                              | 用途                     |
| ------------------------ | --------------------------------- | ---------------------- |
| @vitejs/plugin-vue       | npm i -D @vitejs/plugin-vue       | Vue 3 单文件组件（.vue）支持    |
| @vitejs/plugin-vue-jsx   | npm i -D @vitejs/plugin-vue-jsx   | Vue 3 JSX/TSX 支持       |
| @vitejs/plugin-react     | npm i -D @vitejs/plugin-react     | React 支持（使用 Babel）     |
| @vitejs/plugin-react-swc | npm i -D @vitejs/plugin-react-swc | React 支持（使用 SWC，速度更快）  |
| @vitejs/plugin-legacy    | npm i -D @vitejs/plugin-legacy    | 兼容旧版浏览器（自动注入 polyfill） |

### 社区常用插件

| 插件                      | 安装命令                             | 用途                                  |
| ----------------------- | -------------------------------- | ----------------------------------- |
| vite-plugin-checker     | npm i -D vite-plugin-checker     | 在开发服务器中运行 TypeScript/ESLint 检查并显示错误 |
| unplugin-auto-import    | npm i -D unplugin-auto-import    | 自动导入 Vue/React API，无需手动 import      |
| unplugin-vue-components | npm i -D unplugin-vue-components | Vue 组件自动按需导入                        |

### @vitejs/plugin-vue 配置示例

```javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [
    vue({
      // 包含 Vue 的自定义块（如 <docs>）的文件
      include: [/\.vue$/],
      // 启用响应式语法糖（实验性）
      // reactivityTransform: true,
    }),
  ],
})

```

### @vitejs/plugin-react 配置示例

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react({
      // 包含 JSX 的文件（默认只处理 .jsx/.tsx）
      include: '**/*.{jsx,tsx}',
      // Babel 插件，用于添加装饰器等特性
      babel: {
        plugins: ['@babel/plugin-proposal-decorators'],
      },
    }),
  ],
})

```

### @vitejs/plugin-react-swc 配置示例

SWC 是用 Rust 编写的编译器，比 Babel 快很多，推荐新项目使用：

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'

export default defineConfig({
  plugins: [
    react({
      // 启用 TypeScript 装饰器支持
      // tsDecorators: true,
    }),
  ],
})

```

### @vitejs/plugin-legacy 配置示例

用于支持不支持原生 ESM 的旧浏览器（如 IE11 时代的浏览器）：

```bash
# 需要同时安装 terser
npm install -D @vitejs/plugin-legacy terser

```

```javascript
import { defineConfig } from 'vite'
import legacy from '@vitejs/plugin-legacy'

export default defineConfig({
  plugins: [
    legacy({
      // 目标浏览器，使用 browserslist 语法
      targets: ['defaults', 'not IE 11'],
      // 额外的 polyfill
      additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
    }),
  ],
})

```

### vite-plugin-checker 配置示例

在浏览器中显示 TypeScript 编译错误（而不只是在终端）：

```bash
npm install -D vite-plugin-checker

```

```javascript
import { defineConfig } from 'vite'
import checker from 'vite-plugin-checker'

export default defineConfig({
  plugins: [
    checker({
      // 启用 TypeScript 检查
      typescript: true,
      // 启用 ESLint 检查
      eslint: {
        lintCommand: 'eslint "./src/**/*.{ts,tsx,vue}"',
      },
    }),
  ],
})

```

### unplugin-auto-import 配置示例

自动导入常用 API，无需每个文件都写 `import { ref, computed } from 'vue'`：

```bash
npm install -D unplugin-auto-import

```

```javascript
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      // 自动导入的来源
      imports: [
        'vue',          // ref, computed, watch 等
        'vue-router',   // useRouter, useRoute 等
        'pinia',        // defineStore, storeToRefs 等
      ],
      // 生成类型声明文件（TypeScript 项目推荐）
      dts: 'src/auto-imports.d.ts',
    }),
  ],
})

```

### unplugin-vue-components 配置示例

Vue 组件自动按需导入，无需手动注册组件：

```bash
npm install -D unplugin-vue-components

```

```javascript
import { defineConfig } from 'vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    Components({
      // 组件目录（默认为 src/components）
      dirs: ['src/components'],
      // 使用 Element Plus 自动按需导入
      resolvers: [ElementPlusResolver()],
      // 生成类型声明文件
      dts: 'src/components.d.ts',
    }),
  ],
})

```

---

## 9\. 生产构建基础

### 构建命令

```bash
# 构建生产版本，输出到 dist/ 目录
npm run build
# 等价于
npx vite build

# 预览构建产物（本地启动一个静态文件服务器）
npm run preview
# 等价于
npx vite preview

```

`vite preview` 是用来验证构建产物是否正常的工具，它会启动一个简单的 HTTP 服务器提供 `dist/` 目录的文件，用于在部署前本地测试。它不是用于生产部署的服务器。

### build 参数说明

| 参数                      | 类型                    | 默认值                         | 是否必填      | 说明                                                     |                                                                      |
| ----------------------- | --------------------- | --------------------------- | --------- | ------------------------------------------------------ | -------------------------------------------------------------------- |
| build.outDir            | string                | 'dist'                      | 否         | 构建输出目录，相对于 root                                        |                                                                      |
| build.assetsDir         | string                | 'assets'                    | 否         | 静态资源的存放子目录（在 outDir 内）                                 |                                                                      |
| build.target            | string \| string\[\]  | 'baseline-widely-available' | 否         | 构建产物的浏览器兼容目标。baseline-widely-available 约等于 Chrome 107+ |                                                                      |
| build.minify            | 'esbuild' \| 'terser' | false                       | 'esbuild' | 否                                                      | 代码压缩工具。esbuild 速度快，terser 压缩率更高，false 不压缩                            |
| build.sourcemap         | boolean \| 'inline'   | 'hidden'                    | false     | 否                                                      | 是否生成 source map。true 生成独立 .map 文件，'inline' 内联到产物，'hidden' 生成但不在产物中引用 |
| build.assetsInlineLimit | number                | 4096                        | 否         | 小于此字节数的资源内联为 base64，减少 HTTP 请求                         |                                                                      |

### 完整 build 配置示例

```javascript
export default defineConfig({
  build: {
    // 输出到 dist 目录
    outDir: 'dist',

    // 静态资源放到 dist/assets/ 下
    assetsDir: 'assets',

    // 目标浏览器：支持现代浏览器
    target: 'baseline-widely-available',

    // 使用 esbuild 压缩（更快）
    minify: 'esbuild',

    // 生成 source map（调试生产问题时有用）
    sourcemap: false,

    // 小于 4KB 的资源内联
    assetsInlineLimit: 4096,

    // Rollup 打包选项
    rollupOptions: {
      output: {
        // 手动分包：将第三方库单独打包
        manualChunks: {
          vendor: ['vue', 'vue-router', 'pinia'],
        },
      },
    },
  },
})

```

### 构建产物结构

```
dist/
├── index.html
└── assets/
    ├── index-a1b2c3.js      # 主 JS（带内容 hash）
    ├── vendor-d4e5f6.js     # 第三方库（如果有 manualChunks 配置）
    ├── index-g7h8i9.css     # 样式文件
    └── logo-j1k2l3.png      # 图片资源

```

---

## 10\. 常见问题与踩坑

### process.env.NODE\_ENV 不可用

Webpack 项目中常用 `process.env.NODE_ENV` 判断环境，但在 Vite 项目中直接使用会报错（浏览器没有 `process` 对象）。

正确做法是使用 `import.meta.env`：

```javascript
// 错误写法（Vite 项目中不可用）
if (process.env.NODE_ENV === 'production') {
  // ...
}

// 正确写法
if (import.meta.env.PROD) {
  // ...
}

// 或者
if (import.meta.env.MODE === 'production') {
  // ...
}

```

如果引用的第三方库内部使用了 `process.env.NODE_ENV`，可以在 `vite.config.js` 中用 `define` 手动注入：

```javascript
export default defineConfig({
  define: {
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
  },
})

```

### 部署后资源 404：忘记配置 base

将项目部署到子路径（如 `https://example.com/my-app/`）时，如果没有配置 `base`，构建产物中的资源路径仍然是根路径 `/`，导致 404。

```javascript
// 错误：部署到子路径时没有配置 base
export default defineConfig({
  // 没有 base 配置，默认 '/'
})

// 正确：配置 base 为子路径
export default defineConfig({
  base: '/my-app/', // 必须以 / 结尾
})

```

部署到 GitHub Pages 时通常需要将 `base` 设为仓库名：

```javascript
export default defineConfig({
  base: '/repo-name/',
})

```

### public 里的文件不能用 import 引用

`public/` 目录中的文件不经过 Vite 处理，因此不能用 ES `import` 语句引用，必须用绝对路径字符串。

```javascript
// 错误：public 目录的文件不能用 import
import logo from '/public/logo.png'  // 报错

// 正确：用绝对路径字符串
const logo = '/logo.png'  // public/ 中的文件用根路径
img.src = logo

// 如果需要用 import，应把文件放在 src/assets/ 中
import logoUrl from './assets/logo.png'  // 正确

```

在 HTML 中引用 public 文件：

```html
<!-- 正确：绝对路径 -->
<img src="/logo.png" />

<!-- 错误：不要写成 /public/logo.png -->
<img src="/public/logo.png" />

```

### HMR 失效的常见原因

热更新不生效时，可以从以下方面排查：

1. 文件不在 Vite 监听范围内：默认监听 `root` 目录。`node_modules` 中的文件变化不触发 HMR。
2. 导出方式问题：组件没有默认导出，或导出方式不标准。
3. 副作用阻止了 HMR：模块有不可恢复的副作用（如修改了全局状态），Vite 会回退到全页刷新。
4. 网络问题：HMR 通过 WebSocket 通信，如果 WebSocket 连接失败，HMR 就无法工作。可以在 `server.hmr` 中配置：

```javascript
export default defineConfig({
  server: {
    hmr: {
      // 手动指定 HMR 通信用的 host 和 port
      host: 'localhost',
      port: 5173,
      // 显示 HMR 连接错误
      overlay: true,
    },
  },
})

```

1. 在生产构建后测试 HMR：`vite preview` 不支持 HMR，HMR 只在开发模式（`vite`）下有效。

### 依赖预构建缓存问题

Vite 会把 `node_modules` 中的依赖预构建后缓存到 `node_modules/.vite/deps/` 目录。有时候这个缓存会过期或损坏，导致奇怪的问题（如模块找不到、版本不一致等）。

解决方法：

```bash
# 方法一：启动时强制重新预构建（推荐）
npx vite --force

# 方法二：手动删除缓存目录
rm -rf node_modules/.vite

# 方法三：重新安装依赖
rm -rf node_modules
npm install

```

也可以在配置中控制哪些依赖需要预构建：

```javascript
export default defineConfig({
  optimizeDeps: {
    // 强制预构建这些依赖（即使 Vite 自动检测时没发现）
    include: ['some-package'],
    // 排除某些依赖不进行预构建
    exclude: ['another-package'],
  },
})

```

### import.meta.env 变量只能用完整变量名

Vite 在构建时通过静态替换来注入环境变量，因此不能用动态方式访问：

```javascript
// 错误：动态访问，Vite 无法在构建时替换
const key = 'VITE_API_URL'
const value = import.meta.env[key]  // 生产构建后可能为 undefined

// 正确：用完整的变量名
const value = import.meta.env.VITE_API_URL

```

---

---

## 最佳实践

**始终通过 `import.meta.env.VITE_xxx` 访问环境变量，不拼接变量名**：Vite 在构建时静态替换 `import.meta.env` 中的变量，若用变量名拼接（如 `` `VITE_${key}` ``），构建时无法识别，运行时返回 `undefined`。

**生产构建前运行 `vite preview` 验证产物**：`dev` 模式和 `build` 产物的行为可能不同（如路径别名、资源引用），用 `preview` 在本地模拟生产环境，比直接部署再排查问题高效。

**合理配置 `optimizeDeps.include` 加速冷启动**：对于较大的 CommonJS 依赖（如某些 UI 库），预构建默认有时无法自动检测到，手动加入 `include` 列表可避免首次访问时再编译的延迟。

**使用路径别名（`@` → `src/`）替代相对路径导入**：深层嵌套的 `../../../components/xxx` 难以维护，配置 `resolve.alias` 后统一用 `@/components/xxx`，移动文件时只需修改别名配置一处。

```typescript
// vite.config.ts
import { resolve } from 'path'
export default defineConfig({
  resolve: {
    alias: { '@': resolve(__dirname, 'src') }
  }
})

```

---

## 常见陷阱

### 陷阱：修改 `vite.config.ts` 后开发服务器未重启，配置未生效

**现象：** 修改了 `vite.config.ts` 的 `server.port` 或 `resolve.alias`，但行为没有变化。  
**原因：** Vite 开发服务器在启动时读取配置，配置变更后需要重启服务器才生效；部分配置（如插件列表）不支持热更新。  
**解决：** 停止 `vite` 进程后重新启动；或检查 Vite 版本是否支持配置热重载（`--config` flag 变更会自动重启）。

### 陷阱：`import` 图片路径在构建后变为 `undefined`

**现象：** 开发环境图片正常显示，`vite build` 后图片加载 404 或 `src` 为 `undefined`。  
**原因：** 用字符串拼接动态路径（如 `` `/assets/${name}.png` ``）无法被 Vite 静态分析，不会被打包处理；Vite 只处理静态 `import` 或 `new URL(path, import.meta.url)` 形式。  
**解决：** 用 `new URL(`./assets/${name}.png`, import.meta.url).href` 动态引用资源；或将动态图片放到 `public/` 目录（不经过 Vite 处理，路径保持不变）。

### 陷阱：`process.env.NODE_ENV` 在 Vite 项目中无法访问

**现象：** 代码中使用 `process.env.NODE_ENV`，浏览器报 `process is not defined`。  
**原因：** Vite 不自动注入 `process` 全局变量（这是 Webpack 的行为）；Vite 使用 `import.meta.env.MODE` 代替。  
**解决：** 将 `process.env.NODE_ENV` 替换为 `import.meta.env.MODE`；或在 `vite.config.ts` 中配置 `define: { 'process.env.NODE_ENV': JSON.stringify(mode) }` 手动注入。

---

## 参见

- [Vite中级指南](https://blog.vercanti.com/vite-zhong-ji-zhi-nan/)
- [Vite高级指南](https://blog.vercanti.com/vite-gao-ji-zhi-nan/)
- [Vue3入门](https://blog.vercanti.com/vue-3-ru-men-zhi-nan/)
- [TypeScript完全指南](https://blog.vercanti.com/typescript-wan-quan-zhi-nan/)