Files
zhuangang/topics/frontend/vite/01-dev-build-config.md
T

105 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: frontend.vite.dev-build-config
title: Vite 8:开发服务器原理、Rolldown 构建、环境变量、代理(含 SSE)、插件和拆包
type: lesson
domain: frontend
stack: [vite]
tags: [Vite, Rolldown, ESM, HMR, 环境变量, 代理, 插件, 虚拟模块, 拆包]
level: intermediate
prerequisites: [frontend.typescript.type-system]
est_hours: 2.5
related: [frontend.webpack.build-optimization, frontend.vite.scenario.webpack-to-vite, frontend.vite.interview]
week: [7]
order: 1
---
# Vite 8:开发服务器原理、Rolldown 构建、环境变量、代理(含 SSE)、插件和拆包
> 基于 Vite 8.3 编写并实际构建验证。Vite 8 的生产构建改为基于 Rust 编写的 **Rolldown**(Vite 7 及以前:开发时用 esbuild 预构建依赖,生产用 Rollup 打包);`build.rollupOptions` 改名为 `build.rolldownOptions`(旧名仍可用但已标记弃用),拆包推荐 `output.codeSplitting`。以官方文档为准:https://vite.dev/guide/ 、https://rolldown.rs/ 。
## 解释说明
### 为什么开发时快
- **开发**:不打包。浏览器原生支持 ES 模块(`<script type="module">`),请求哪个文件,Vite 就即时转换哪个文件(TS → JS、`.vue` → JS)。第三方依赖会预构建(把 CommonJS 转成 ESM、把很多小文件合成一个),并强缓存。
- **热更新(HMR)**:文件修改后只让对应模块失效并重新请求,速度与项目大小基本无关。
- **生产构建**:仍然要打包(减少请求数、tree shaking、压缩、拆包)。
### 常用配置
| 需求 | 配置 |
| --- | --- |
| 路径别名 | `resolve.alias` |
| 环境变量 | `.env`、`.env.[mode]`;浏览器代码只能读取 `VITE_` 前缀的变量(`import.meta.env.VITE_XXX`);配置文件中用 `loadEnv` |
| 开发代理 | `server.proxy`,解决开发时的跨域,支持 `rewrite` |
| 插件 | Rollup / Rolldown 兼容的插件钩子(`resolveId`、`load`、`transform`)+ Vite 专有钩子(`configureServer`、`transformIndexHtml`、`handleHotUpdate`) |
| 拆包 | Vite 8:`build.rolldownOptions.output.codeSplitting.groups`;动态 `import()` 自动拆包 |
| 兼容旧浏览器 | `@vitejs/plugin-legacy` |
### Monorepo
pnpm workspace + Vite 是常见组合:多个应用共用组件库和工具包,`workspace:*` 引用本地包。
## 案例
AI 客服前端项目:开发时 `/api` 代理到本地 FastAPI,`/stream` 代理 SSE 流式接口;构建时注入版本号(便于排查线上问题对应哪个版本);Vue 运行时单独拆包,长期缓存。
## 代码示例
完整项目:[examples/vite-config](examples/vite-config/)。已验证:`tsc` 类型检查通过;`vite build` 输出独立的 `vendor-vue` 和按需加载的 `heavy` chunk;开发服务器代理普通接口(`/api/hello` → 后端 `/hello`)和 SSE(每 0.5 秒一条,逐条到达,没有被缓冲)。
自定义插件——虚拟模块([vite.config.ts](examples/vite-config/vite.config.ts)):
```ts
function buildInfo(version: string): Plugin {
const id = "virtual:build-info";
const resolved = "\0" + id;
return {
name: "build-info",
resolveId(source) { return source === id ? resolved : null; },
load(moduleId) {
if (moduleId !== resolved) return null;
return `export default ${JSON.stringify({ version, builtAt: new Date().toISOString() })};`;
},
};
}
```
代理和拆包:
```ts
server: {
proxy: {
"/api": { target: apiTarget, changeOrigin: true, rewrite: (p) => p.replace(/^\/api/, "") },
"/stream": { target: apiTarget, changeOrigin: true },
},
},
build: {
rolldownOptions: {
output: { codeSplitting: { groups: [{ name: "vendor-vue", test: /node_modules[\\/]@?vue/ }] } },
},
},
```
构建输出:
```text
dist/assets/heavy-xxxx.js 0.08 kB
dist/assets/index-xxxx.js 2.54 kB
dist/assets/vendor-vue-xxxx.js 60.80 kB
```
## 易错点
- 把密钥放到 `VITE_` 前缀的变量中:会被打包进浏览器代码,任何人都能看到。
- 以为开发代理在生产环境也生效:生产环境需要 Nginx 或网关转发。
- 开发正常、构建后报错:开发不打包,CommonJS 依赖、动态路径、大小写敏感的路径在构建时才暴露问题,提交前要跑一次 `vite build`。
- 照搬旧文章的 `rollupOptions.output.manualChunks`:Vite 8 中仍可用但已弃用,新项目使用 `codeSplitting`。
- 拆包拆得太碎:请求数增加,反而变慢。
## 面试常问
- Vite 为什么比 webpack 开发时快?生产构建为什么还要打包?
- Vite 的环境变量是如何区分浏览器可见和不可见的?
- 写过 Vite 插件吗?说说钩子。