phase 5 part 2: vite 8, webpack 5, fe-testing-perf topics with verified examples

This commit is contained in:
Shikui Wang committed 2026-10-23 16:29:27 +08:00
1 parent 7b5cae7d24
commit 9eeb10aede
38 files changed
+1823 -37

No files matched your search

+104
View File
@@ -0,0 +1,104 @@
---
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 插件吗?说说钩子。