1
0
Files
DiAL/openspec/changes/archive/2026-05-09-add-vite-react-bun-executable/design.md

122 lines
6.9 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.
## Context
当前项目是 Bun + TypeScript 的最小工程,入口文件只有 `index.ts`,尚未形成前端、后端、共享类型、测试和构建的边界。目标是在保持 Bun 单文件部署优势的同时,引入完整的 Vite + React 前端开发体验。
业界成熟实践通常不是让后端参与前端 HMR而是开发期让 Vite dev server 独立承载前端,使用 proxy 将 `/api/*` 转发给后端生产期由前端构建生成静态资源再由后端服务这些资源。Go/Rust 生态常用类似 `embed` 的方式把 Vite `dist/` 打入单个二进制Bun 可通过 `bun build --compile` 与 embedded files/full-stack asset 能力实现同类目标。
```
开发期
Browser
|
v
Vite dev server :5173
|-- React HMR
|-- /api/* proxy
|
v
Bun API server :3000
生产期
Browser
|
v
gateway-checker executable
|-- /api/* Bun API
|-- /health 健康检查
|-- /assets/* Vite 静态资源
|-- /* React SPA fallback
```
## Goals / Non-Goals
**Goals:**
- 建立 Vite + React + TypeScript 前端应用结构,保留开发期 HMR。
- 建立 Bun 后端服务结构,统一承载 API、健康检查和生产前端资源。
- 提供一个可运行 demo前端页面通过 `/api/demo` 调用后端并展示响应。
- 建立前后端共享类型边界,避免重复定义基础接口类型。
- 建立生产构建链路,输出单个 Bun standalone executable。
- 保持前端可拆离:前端只通过 HTTP `/api/*` 依赖后端,不直接 import 后端实现。
- 更新 README记录结构、命令、测试、构建和运行方式。
**Non-Goals:**
- 不引入 SSR、React Server Components、Next.js 或其他全栈框架。
- 不引入数据库、认证、用户系统或业务功能。
- 不要求一次性完成多平台发布矩阵,只定义可扩展的 target 机制。
- 不把运行期配置、日志或可变数据嵌入 executable。
- 不在开发期强制单端口访问;开发期可以使用 Vite 端口作为浏览器入口。
## Decisions
### Decision: 使用 Vite + React 作为前端开发框架
采用 Vite + React + TypeScript开发期由 Vite 提供 HMR生产期由 `vite build` 输出静态资源。React 适合后续构建复杂管理界面、状态页、图表和交互式检测视图。
替代方案:使用 Bun 原生 HTML imports。该方案更简单、依赖更少但前端生态、插件、测试和组件体系弱于 Vite。
替代方案:使用 Next.js。该方案能力更强但 SSR/路由/部署模型与“Bun 单 executable”目标存在额外摩擦。
### Decision: 开发期 Vite proxy `/api/*` 到 Bun 后端
浏览器开发入口默认使用 Vite dev server前端请求统一使用相对路径 `/api/*`。Vite 负责把这些请求代理到 Bun 后端服务,从而保持同源开发体验,避免 CORS 和硬编码后端地址。
替代方案Bun 后端反向代理 Vite dev server。该方案可以让开发期也统一一个端口但会增加胶水代码并且容易干扰 Vite HMR 行为。
### Decision: 生产期由 Bun 服务 Vite `dist/`
生产构建先执行 Vite build再让 Bun 后端服务 `index.html``assets/*` 和其他静态资源。非 API、非静态资源路径 fallback 到 `index.html`,用于支持 React SPA 路由刷新。
替代方案:前端独立部署到 CDN。该方案扩展性更好但不满足当前“一个可执行程序包含前后端”的目标。
### Decision: 单 executable 是发布形态,不是代码耦合方式
前端和后端在源码层保持清晰边界,只通过 HTTP API 和共享类型协作。打包层负责将 Vite 产物嵌入 Bun executable。这样未来若需要 CDN、独立前端部署或多客户端复用 API不需要重写后端业务代码。
替代方案:后端源码直接 import 前端源码或前端模块。该方案短期简单,但会模糊运行时边界,增加后续拆离成本。
### Decision: API 路径统一保留在 `/api/*`
所有业务 API 使用 `/api/*` 前缀,健康检查使用 `/health`。demo API 使用 `/api/demo`,返回前端可展示的 JSON 响应。生产期路由优先级为 API、健康检查、静态资源、SPA fallback。未命中的 `/api/*` 必须返回 JSON 404不能 fallback 到前端页面。
替代方案API 与页面路径混排。该方案不利于 Vite proxy、生产 fallback 和未来前端独立部署。
### Decision: 运行配置使用环境变量或 CLI 参数
host、port、日志级别等运行期配置不嵌入 executable优先从 CLI 参数或环境变量读取。executable 内只包含只读程序代码和前端静态资源。
替代方案:构建期写死配置。该方案部署简单,但不同环境需要重新构建,且不利于发布同一个二进制。
### Decision: demo 是验收基线而不是业务功能
demo 只证明前端开发、后端 API、生产静态服务和 executable 打包链路能跑通。页面应展示来自 `/api/demo` 的后端响应,并在 README 中记录开发期访问方式和 executable 运行后的验证方式。
替代方案:只搭建空白 React 页面和空 API。该方案能证明结构存在但不能证明前后端开发和打包后联通链路真实可用。
## Risks / Trade-offs
- [Risk] Bun standalone executable 与 Vite `dist/` 嵌入方式相对 Go `embed` 更年轻。→ Mitigation: 先实现最小静态资源嵌入和端到端构建测试,再扩展多平台构建。
- [Risk] Vite hashed assets、SPA fallback 和 Bun 静态路由可能出现路径映射问题。→ Mitigation: 对 `/`, `/assets/*`, 前端路由刷新和 `/api/*` 404 编写测试或构建后验证。
- [Risk] 依赖数量会明显增加。→ Mitigation: 初期只引入 Vite、React、React DOM 和必要类型,不引入 UI 组件库、状态管理或路由库,除非后续需求明确。
- [Risk] 单 executable 会把前端资源大小计入二进制。→ Mitigation: 保留 Vite 产物压缩能力,后续可按需启用分离部署或 CDN。
- [Risk] 开发期前端和后端是两个进程,启动命令更复杂。→ Mitigation: 提供 `dev:web``dev:server``dev` 聚合脚本,并在 README 中说明。
## Migration Plan
1. 保留当前最小入口语义,重构为新的 server 入口。
2. 新增 web、server、shared 和 scripts 目录结构。
3. 引入最小 Vite + React 依赖并配置开发代理。
4. 实现 Bun API、健康检查和生产静态资源服务。
5. 增加测试和构建验证。
6. 更新 README 作为项目结构和命令的权威说明。
回滚策略:如果 Vite 集成阻塞,可以保留 Bun 后端结构,移除 web 目录和前端构建脚本,退回 Bun 原生 HTML imports 或后端-only 形态。
## Open Questions
- 前端是否需要路由库,例如 React Router还是先保持单页面组件状态
- 是否需要 UI 组件库,例如 TDesign、shadcn/ui 或保持纯 CSS
- 生产 executable 首期目标平台是当前 macOS还是同时需要 Linux x64/arm64