- 引入 React Router v7 (Declarative mode) 实现 SPA 路由 - 重构 Layout 为 Header + 侧边栏 + 内容区的企业 Admin 布局 - 新增侧边栏菜单组件,支持折叠/展开,状态持久化到 localStorage - 新增示例页面:仪表盘、用户管理、系统设置、404 - 菜单配置与路由统一为单一数据源 (menu.tsx) - Vite code splitting 新增 vendor-router 组 - 更新 DEVELOPMENT.md 和 README.md 文档
31 KiB
my-app 开发文档
本文档面向 my-app 项目的开发者,介绍项目结构、前后端架构、构建流程、测试、代码规范等内容。
用户使用说明请参阅 README.md。
目录
项目结构
src/
server/
bootstrap.ts 后端统一启动引导(loadServerConfig → startServer)
config.ts CLI 参数解析与配置文件加载(可选 YAML configPath,支持 --help/-h)
dev.ts 开发模式启动入口(mode: "development")
main.ts 生产模式启动入口(mode: "production",安全头启用)
server.ts HTTP server 启动工厂(Bun.serve routes 声明式路由 + fetch fallback 静态资源服务)
static.ts 生产模式静态资源服务(SPA fallback、Content-Type 映射、immutable 缓存)
helpers.ts 共享响应格式化工具(见下方函数清单)
middleware.ts API 参数校验中间件(validateIdParam、validatePagination、validateTimeRange)
routes/ API 路由 handler(按端点拆分)
health.ts GET /health
shared/
api.ts 前后端共享 TypeScript 类型
app.ts 应用全局常量(name、title、subtitle、description、version)
web/ React 前端(通过 Vite 构建)
index.html HTML 入口
app.tsx 根组件(Admin 布局:Header + Sidebar + Content)
main.tsx 入口(BrowserRouter + QueryClient 挂载 + ErrorBoundary + ReactQueryDevtools + TDesign CSS 导入)
routes.tsx 路由配置(定义所有页面路由)
styles.css 全局样式与自定义 CSS 变量
css.d.ts CSS 模块类型声明
pages/ 页面组件
dashboard/
index.tsx 仪表盘页(欢迎语 + /health 联调示例)
users/
index.tsx 用户管理页(占位)
settings/
index.tsx 系统设置页(占位)
404/
index.tsx 404 页面
components/ UI 组件
ErrorBoundary.tsx React 错误边界,捕获渲染异常并展示降级 UI
Sidebar/
index.tsx 侧边栏菜单组件(TDesign Menu + 折叠控制)
hooks/ React hooks
use-theme-preference.ts 主题偏好 hook(system/light/dark,localStorage 记忆 + matchMedia 监听)
use-sidebar-collapsed.ts 侧边栏折叠状态 hook(localStorage 记忆)
utils/ 前端工具函数
time.ts 时间处理(formatCountdown、formatDurationUnit、formatRelativeTime、isOlderThan、subtractHours)
menu.tsx 菜单配置(路由与菜单项统一数据源)
routes.tsx 路由配置(定义所有页面路由)
scripts/
dev.ts 双进程开发服务(Bun API server + Vite dev server)
build.ts Vite → codegen → Bun compile 三步构建流水线
clean.ts 清理构建产物与临时文件
tests/ Bun test 测试(结构镜像 src 目录)
setup.ts 全局测试配置(jsdom、polyfill)
helpers.ts 测试辅助工具(rmRetry)
server/ 后端测试
bootstrap.test.ts
config.test.ts
middleware.test.ts
static.test.ts
web/ 前端测试
App.test.tsx
test-utils.tsx
openspec/ OpenSpec 变更与规格文档
config.example.yaml 配置文件示例
前后端边界
前端只通过 HTTP 调用后端,API 路径为 /api/* 和 /health。共享类型放在 src/shared,前端不得 import src/server 的运行时实现。
一、后端开发指引
1.1 架构概览
启动流程:
dev.ts / main.ts → parseRuntimeArgs(cli args)
→ bootstrap({ configPath, mode })
→ loadServerConfig(configPath):可选 YAML 解析 → ServerConfig{ host, port }
→ startServer({ config, mode }):Bun.serve routes 声明式路由 + fetch fallback
→ 注册 SIGINT/SIGTERM shutdown
HTTP 请求:
Request → Bun.serve routes 声明式匹配 → routes/*.ts(handler)
→ helpers.ts(响应格式化) → Response
前端: fetch fallback → serveStaticAsset (生产) / Vite proxy (开发)
1.2 库使用优先级
后端代码开发遵循严格的库选择顺序:
| 优先级 | 来源 | 典型用途 |
|---|---|---|
| 1 | Bun 内置 API | Bun.serve、Bun.file、Bun.YAML、Bun.spawn、bun:sqlite(如需数据存储) |
| 2 | es-toolkit | 类型判断(isPlainObject/isNil/isEmptyObject)、深度比较(isEqual)、并发控制(Semaphore) |
| 3 | 标准 Web API | Object.fromEntries、Headers、fetch、AbortController、Response |
| 4 | 主流三方库 | 按需引入,优先社区活跃、类型完善的库 |
| 5 | 自行实现 | 仅在以上都无法满足时(如 parseDuration、parseSize 等专项逻辑) |
原则:新增依赖前先检查上述每一层级是否已有可用方案。禁止随意引入新依赖。
1.3 API 路由开发
路由文件位于 src/server/routes/,每个端点一个文件。路由通过 server.ts 的 Bun.serve({ routes }) 声明式注册,使用 per-method handler 对象:
// server.ts 中的路由注册
routes: {
"/api/*": () => jsonResponse(createApiError("API route not found", 404), { mode, status: 404 }),
"/health": {
GET: () => handleHealth(mode),
},
}
Handler 函数签名:
// 无依赖的路由
export function handleHealth(mode: RuntimeMode): Response;
请求处理流程:
Bun.serve的routes对象按路径 + HTTP 方法匹配请求- 未匹配方法的请求落入
/api/*通配符(返回 404) - 各 handler 内部通过
helpers.ts的jsonResponse、createApiError等格式化输出 - 需要参数校验时使用
middleware.ts提供的校验函数,返回Response实例表示校验失败(直接返回),返回数据对象表示通过
新增路由步骤:
- 在
src/server/routes/下创建<name>.ts - 实现 handler 函数并 export
- 在
server.ts的routes对象中注册路径和 method handler - 在
tests/server/中添加对应测试
1.4 共享工具
-
helpers.ts:跨路由共用的响应工具函数createApiError(error, status)— 构造 API 错误体createHeaders(mode, init)— 创建响应 Headers(生产模式附加安全头:X-Content-Type-Options、Referrer-Policy)createHealthResponse()— 构造健康检查响应{ ok: true, service, timestamp }formatDuration(ms)— 毫秒转为可读时长字符串jsonResponse(body, options)— JSON 响应构造
-
middleware.ts:API 参数校验函数validateIdParam(idStr, mode)— 校验 ID 参数格式(字母数字下划线连字符,字母开头),返回{ id }或ResponsevalidatePagination(pageParam, pageSizeParam, mode)— 校验分页参数(默认 page=1, pageSize=20,pageSize 上限 200),返回{ page, pageSize }或ResponsevalidateTimeRange(from, to, mode)— 校验时间范围参数(ISO 格式、from < to),返回{ from, to }或Response
-
static.ts:生产模式静态资源服务serveStaticAsset(pathname, assets)— 静态资源分发(文件扩展名路由 → immutable 缓存,无扩展名 → SPA fallback 返回 index.html)hasFileExtension(path)/contentTypeFor(path)/htmlResponse(html)— 辅助函数
1.5 类型定义规范
- 共享类型以
src/shared/api.ts为唯一源头,前后端共同引用 - 应用常量以
src/shared/app.ts为唯一源头,定义APP对象(name、title、subtitle、description、version),前后端及构建脚本共同引用 - 前端不得
import src/server/下的任何文件 - 严格联合类型优先于宽类型:如
RuntimeMode: "development" | "production" | "test"而非RuntimeMode: string - API 响应类型(
ApiErrorResponse、HealthResponse)定义在 shared 中
1.6 配置文件规范
配置加载流程:
CLI argv → parseRuntimeArgs → { configPath? }
→ loadServerConfig(configPath)
→ 可选 YAML 文件解析 → env 覆盖 → 默认值
→ ServerConfig{ host, port }
ServerConfig 包含以下字段:
| 字段 | 来源 | 默认值 |
|---|---|---|
host |
process.env["HOST"] → YAML server.host → 默认 |
127.0.0.1 |
port |
process.env["PORT"] → YAML server.port → 默认 |
3000 |
配置文件示例(config.example.yaml):
server:
host: "127.0.0.1"
port: 3000
1.7 错误模式
- API 错误:
{ error: "描述", status: <code> },状态码 400/404 - 日志:非致命异常用
console.warn,启动失败用console.error+process.exit(1)
二、前端开发指引
2.1 技术栈概览
| 层面 | 技术 | 用途 |
|---|---|---|
| 框架 | React 19 | UI 组件开发 |
| 构建 | Vite(开发)+ Bun compile(生产) | 开发服务 HMR 与生产构建 |
| 语言 | TypeScript | 类型安全 |
| UI 库 | TDesign React + tdesign-icons-react | UI 组件与图标 |
| 数据层 | TanStack Query (React Query) + React Query Devtools | 服务端状态管理与自动刷新 |
| 路由 | React Router v7 (Declarative mode) | SPA 路由与页面导航 |
不引入的依赖:状态管理库(TanStack Query 即服务端状态层,组件内用 useState 足够)
2.2 组件树与数据流
main.tsx
└── StrictMode
└── ErrorBoundary(React 错误边界)
└── QueryClientProvider(TanStack Query 全局挂载)
└── BrowserRouter(React Router 路由)
├── App(根组件,Admin 布局)
│ ├── useThemePreference() ── Header 主题模式 RadioGroup(系统/明亮/黑暗)
│ ├── useSidebarCollapsed() ── 侧边栏折叠状态(localStorage 记忆)
│ ├── Layout
│ │ ├── Header(折叠按钮 + 品牌名 + 页标题 + 主题切换)
│ │ └── Layout(嵌套)
│ │ ├── Aside
│ │ │ └── Sidebar(TDesign Menu,菜单项点击导航)
│ │ └── Content
│ │ └── AppRoutes(路由配置)
│ │ ├── / → DashboardPage(欢迎语 + /health 联调)
│ │ ├── /users → UsersPage(占位)
│ │ ├── /settings → SettingsPage(占位)
│ │ └── * → NotFoundPage(404)
└── ReactQueryDevtools(开发工具,仅开发环境)
Hook 架构:
hooks/use-theme-preference.ts(浏览器 UI 偏好)
├── ThemePreference: system / light / dark(RadioGroup 受控值)
├── EffectiveTheme: light / dark(写入 document.documentElement theme-mode)
├── localStorage key: theme.preference(同一浏览器记忆)
└── matchMedia("(prefers-color-scheme: dark)")(系统模式下跟随系统明暗变化)
hooks/use-sidebar-collapsed.ts(侧边栏折叠状态)
├── collapsed: boolean(折叠状态)
├── localStorage key: sidebar.collapsed(同一浏览器记忆)
└── toggleCollapsed()(切换折叠状态)
菜单配置:
utils/menu-config.ts(路由与菜单统一数据源)
├── MENU_ITEMS: MenuItemConfig[](菜单项配置数组)
│ ├── { value: "dashboard", label: "仪表盘", path: "/", icon: <DashboardIcon /> }
│ ├── { value: "users", label: "用户管理", path: "/users", icon: <UserIcon /> }
│ └── { value: "settings", label: "系统设置", path: "/settings", icon: <SettingIcon /> }
└── Sidebar 和 Routes 共同引用,保证菜单项与路由同步
2.3 TanStack Query 数据层
Query Key 规范
// 使用 structured array(非字符串),以便精确匹配和按 prefix 失效
const queryKeys = {
health: () => ["health"] as const,
};
- Key 使用 structured array(非字符串),以便精确匹配和按 prefix 失效
- 使用
as const保持字面量类型
查询配置规范
// 全局级查询(需要持续刷新)
useQuery({
queryKey: queryKeys.health(),
queryFn: () => fetchJson<HealthResponse>("/health"),
refetchInterval: 30000, // 30s 轮询
refetchIntervalInBackground: false, // 切后台不轮询
staleTime: 5000, // 5s 内视为 fresh
});
fetch 封装
async function fetchJson<T>(url: string): Promise<T> {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json() as Promise<T>;
}
- 统一使用
fetch(不引入 axios),与后端共享 Web API 生态 - 错误抛异常,由 TanStack Query 的
error状态承接
QueryClient 全局配置
new QueryClient({
defaultOptions: {
queries: {
retry: 1, // 失败重试 1 次
refetchOnWindowFocus: true, // 窗口聚焦时刷新
staleTime: 5000, // 5s 内视为 fresh,避免重复请求
},
},
});
2.4 组件开发规范
文件命名与导入
- 每个 React 组件一个
.tsx文件,文件名使用 PascalCase(如ErrorBoundary.tsx) - 组件 props 定义为
interface XxxProps,紧邻组件函数声明 - 类型从
../shared/api导入,使用type导入(import type { ... })
import type { HealthResponse } from "../shared/api";
interface AppProps {
title?: string;
}
export function App({ title }: AppProps) {
// ...
}
组件拆分原则
- 展示组件(
components/):纯渲染逻辑,通过 props 接收数据,通过回调返回事件 - 容器逻辑放在 hooks 中,组件只做数据消费
- 工具函数(时间处理等)放在
utils/,保持纯函数无副作用
2.5 样式开发规范
前端基于 TDesign React 构建 UI,样式开发遵循以下优先级(从高到低):
- 使用 TDesign 组件:布局、间距、排版优先使用 TDesign 组件(如 Space、Divider、Typography)
- 使用 TDesign 组件 props:通过组件的 props 参数控制外观(如
theme、variant、size) - 使用 TDesign CSS tokens:颜色、间距、字体等使用
--td-*CSS 变量(如--td-success-color、--td-comp-margin-xxl) - 在 styles.css 中定义 CSS 类:无法通过上述方式满足的样式需求,集中定义在
styles.css中 - 自行开发组件:仅在 TDesign 无法满足需求时自行开发
红线:
- 严禁在组件中使用
style属性内联调整样式 - 严禁通过 CSS 覆盖 TDesign 组件内部类名(如
.t-tab-panel),如需定制使用组件的classNameprop - 严禁使用
!important - 颜色统一使用 TDesign CSS tokens(
--td-success-color、--td-error-color、--td-warning-color等),不使用硬编码色值
styles.css 组织:
- 自定义 CSS 变量定义在
:root中 - 布局类(
.dashboard、.dashboard-header-controls)定义全局页面结构 - 组件修饰类为自定义视觉组件提供样式变体
- 通用工具类(
.full-width、.text-disabled、.tabular-nums)提供公用排版能力
2.6 前端测试规范
- 测试目录:
tests/web/,结构对应src/web/ - 重点测试 纯函数(时间处理、格式化等)和组件渲染
- 使用
bun:test框架 - 组件测试使用
@testing-library/react的语义化查询(getByText、getByRole)而非 CSS 选择器 - 测试用户行为而非实现细节:模拟用户点击、输入等操作,而非直接调用组件方法
- 只 mock 系统边界:mock fetch 返回预设响应,使用真实的 QueryClientProvider 包裹组件
三、项目运行、集成与打包
3.1 开发期运行
bun run dev [config.yaml]
scripts/dev.ts 同时启动两个进程:
- Bun API server(端口 3000):后端 API 服务,
--watch监听后端文件变更自动重启 - Vite dev server(端口 5173):前端 SPA + HMR 热更新
开发时访问 http://127.0.0.1:5173,Vite 自动将 /api 和 /health 请求代理到后端。
也可以单独启动:
bun run dev:server [config.yaml] # 仅启动后端 API server(--watch 模式)
bun run dev:web # 仅启动 Vite dev server
3.2 前后端集成方式
双进程开发架构
开发模式下前后端分别由 Vite 和 Bun 服务:
- Vite dev server 负责前端 SPA、HMR、模块热替换
- Bun API server 负责后端 API 路由
- Vite 通过 proxy 配置将
/api/*和/health转发到 Bun
生产模式架构
生产模式下前端通过 Vite 构建为静态资源,通过 import with { type: "file" } 嵌入 Bun 可执行文件:
// server.ts
const server = Bun.serve({
fetch(req) {
// staticAssets 存在时服务嵌入的前端资源
if (staticAssets) {
return serveStaticAsset(new URL(req.url).pathname, staticAssets);
}
return new Response("Frontend is served by Vite dev server on :5173", { status: 404 });
},
routes: {
"/api/*": () => ...,
"/health": { GET: () => handleHealth(mode) },
},
});
路由优先级
Bun routes 的匹配规则:具体路径 > 通配符。/health 优先于 /*。
未匹配 method 的请求(如 POST /health)会落入 /api/* 通配符返回 404;若无该通配符会落入 fetch fallback。
非 API 路径由 fetch fallback 处理:有文件扩展名的返回对应静态资源或 404,无扩展名的返回 SPA index.html。
3.3 构建打包
构建命令
bun run build
构建流程
scripts/build.ts 执行三步流水线:
1. Vite build → dist/web/ (前端静态资源,含 code splitting)
2. Code generation → .build/static-assets.ts + .build/server-entry.ts
3. Bun compile → dist/dial-server (单可执行文件)
- Vite 构建前端资源到
dist/web/,自动 code splitting(vendor-react、vendor-tdesign、vendor-chart) - Code generation 扫描
dist/web/生成import with { type: "file" }声明,将资源嵌入 binary - Bun compile 以
.build/server-entry.ts为入口编译最终可执行文件 .build/临时目录在构建完成后自动清理
产物
| 产物 | 用途 |
|---|---|
dist/dial-server |
生产可执行文件(含前端资源,单文件部署) |
dist/web/ |
Vite 构建的前端资源(构建中间产物) |
构建参数
| 环境变量 | 说明 |
|---|---|
BUN_TARGET/BUILD_TARGET |
交叉编译目标平台(如 bun-linux-x64) |
运行可执行文件
./dist/dial-server [config.yaml]
启动后:
- 访问
http://127.0.0.1:3000/→ 返回前端 SPA - 访问
http://127.0.0.1:3000/api/*→ 返回后端 API - 访问
http://127.0.0.1:3000/health→ 返回健康检查 JSON
清理
bun run clean
# 清理 dist/ 构建产物和 .build/ 临时文件
3.4 开发工作流
日常开发循环
bun run dev [config.yaml] # 启动双进程开发环境(Vite :5173 + API :3000)
# 访问 http://127.0.0.1:5173
# 修改前端代码 → Vite HMR 热更新 / 修改后端代码 → --watch 自动重启
bun run check # 提交前运行完整质量检查
完整验证流程
bun run verify
# = bun run check + bun run build
verify 适合 CI 或正式提交前,会完整验证类型检查、lint、格式、单元测试和生产构建。
3.5 脚本说明
| 脚本 | 文件 | 说明 |
|---|---|---|
bun run dev |
scripts/dev.ts |
双进程开发服务(Vite :5173 + API :3000) |
bun run dev:server |
src/server/dev.ts |
仅启动后端 API server(--watch 模式) |
bun run dev:web |
Vite CLI | 仅启动 Vite dev server |
bun run build |
scripts/build.ts |
Vite → codegen → Bun compile 三步构建 |
bun run clean |
scripts/clean.ts |
清理构建缓存与临时文件 |
3.6 环境变量
| 变量 | 用途 | 默认值 |
|---|---|---|
BUN_TARGET/BUILD_TARGET |
交叉编译目标平台(仅在 bun run build 时有效) |
当前平台 |
HOST |
服务监听地址 | 127.0.0.1 |
PORT |
服务监听端口 | 3000 |
3.7 项目配置文件
| 文件 | 用途 |
|---|---|
package.json |
项目信息、脚本、依赖声明 |
tsconfig.json |
TypeScript 配置(ESNext 模块、严格模式) |
eslint.config.js |
ESLint 规则(含前端不得 import server 的检查) |
commitlint.config.js |
commitlint 提交信息格式校验 |
.prettierrc.json |
Prettier 格式化规则(printWidth: 120) |
.prettierignore |
Prettier 排除路径 |
.lintstagedrc.json |
lint-staged 配置(TS/TSX → ESLint,MD/JSON/YAML → Prettier) |
config.example.yaml |
配置文件示例 |
vite.config.ts |
Vite 构建配置(React 插件、代码分割、API proxy) |
bunfig.toml |
Bun 配置(测试 preload、排除规则) |
opencode.json |
OpenCode 工具配置 |
3.8 依赖管理
- 包管理器:仅使用
bun,禁止使用 npm、pnpm、yarn - 安装依赖:
bun install - 运行工具:使用
bunx,禁止使用npx、pnpx - 锁文件:
bun.lock
3.9 目录约定
| 目录 | 约定 |
|---|---|
src/server/ |
后端代码,不能 import src/web/(HTML import 除外) |
src/web/ |
前端代码,不能 import src/server/ |
src/shared/ |
前后端共享类型,双向可引用 |
scripts/ |
独立运行脚本,可 import 项目源码 |
tests/ |
测试目录,结构镜像 src 目录 |
dist/ |
构建产物(gitignore) |
openspec/ |
OpenSpec 变更管理与规格文档 |
代码质量
项目使用多层代码质量保障体系:ESLint 类型感知规则 + Perfectionist 导入排序 + Prettier 格式化(通过 eslint-plugin-prettier 集成至 ESLint)+ TypeScript 严格模式 + Git hooks 自动化。
bun run lint # ESLint 检查(含类型感知规则、导入排序、导入验证、Prettier 格式)
bun run format # Prettier 自动格式化
bun run typecheck # TypeScript 类型检查
bun test # 运行所有测试
bun run check # 一键运行 typecheck + lint + test
bun run verify # 完整验证(check + build)
check 是日常开发推荐的质量检查命令。
ESLint 规则
配置文件:eslint.config.js
| 配置来源 | 用途 |
|---|---|
@eslint/js recommended |
JavaScript 基础规则 |
typescript-eslint recommended-type-checked |
TypeScript 类型感知规则(no-floating-promises 等) |
typescript-eslint stylistic-type-checked |
TypeScript 风格规则(命名规范、语法选择等) |
eslint-plugin-perfectionist recommended-natural |
导入语句和命名导出自动排序 |
eslint-plugin-import |
导入路径验证、循环依赖检测、重复导入合并 |
eslint-plugin-react-hooks recommended |
React Hooks 规则(依赖数组完整性检查等) |
eslint-plugin-react-refresh |
React Fast Refresh 兼容性检查 |
eslint-plugin-prettier recommended + eslint-config-prettier |
将 Prettier 格式集成为 ESLint 规则,禁用冲突规则 |
前端导入限制:src/web/ 下的文件禁止 import src/server/ 下的运行时实现,通过 no-restricted-imports 规则强制执行。
Prettier 配置
配置文件:.prettierrc.json,通过 eslint-plugin-prettier 集成为 ESLint 规则(lint 命令同时检查格式),也可通过 format 命令独立运行。
显式声明所有格式化参数(printWidth: 120、semi: true、singleQuote: false、trailingComma: "all"、endOfLine: "lf" 等),确保不同开发环境产出完全一致的格式化结果。
TypeScript 严格标志
| 标志 | 值 | 说明 |
|---|---|---|
strict |
true | 全局严格模式 |
noUnusedLocals |
true | 未使用局部变量视为错误 |
noUnusedParameters |
false | 保留关闭(路由 handler 统一签名需要) |
noPropertyAccessFromIndexSignature |
true | 禁止通过点号访问索引签名属性,强制使用括号语法 |
noUncheckedIndexedAccess |
true | 数组/Map 访问必须运行时真值检查 |
noImplicitOverride |
true | 子类覆盖父类方法时必须显式使用 override 关键字 |
verbatimModuleSyntax |
true | 强制 import type 纯类型导入,与 Bun 构建兼容 |
Git Hooks
通过 husky 在 commit 阶段自动执行检查:
| Hook | 行为 |
|---|---|
pre-commit |
lint-staged 对变更文件运行 eslint --fix(TS/TSX,含 Prettier 格式修复)或 prettier --write(MD/JSON/YAML) |
commit-msg |
commitlint 校验提交信息格式 类型: 简短描述 |
提交类型限定:feat、fix、refactor、docs、style、test、chore。
bun install 时自动初始化 husky hooks,无需手动配置。
质量检查完整清单
提交代码前建议运行:
bun run verify
CI 或正式提交前执行完整验证(类型检查 + lint + 格式 + 测试 + 构建),确保代码可编译并通过所有检查。
测试
项目采用两层测试体系:单元测试 + 组件测试。所有测试使用 bun:test 运行。
测试分层
| 层级 | 覆盖范围 | 位置 | 命令 |
|---|---|---|---|
| 单元测试 | 后端函数、纯函数、常量 | tests/server/**/*.test.ts、tests/web/{utils,hooks}/**/*.test.ts |
bun test tests/server、bun test tests/web |
| 组件测试 | React 组件渲染和交互 | tests/web/components/**/*.test.tsx |
bun test tests/web |
运行命令
bun test # 运行所有单元测试和组件测试
bun test tests/server # 只运行后端单元测试
bun test tests/web # 只运行前端测试(单元 + 组件)
bun run check # 日常开发(类型检查 + lint + 测试)
bun run verify # 完整验证(check + 构建)
组件测试环境
组件测试使用 jsdom 模拟浏览器环境,配置位于 tests/setup.ts(通过 bunfig.toml preload 加载):
- jsdom 提供完整的 DOM 环境
- TDesign 组件所需的 polyfill:ResizeObserver、IntersectionObserver、MutationObserver、matchMedia、attachEvent
- 全局
afterEach清理 document.body 内容,确保测试隔离
编写规范
- 优先使用
@testing-library/react的语义化查询(getByText、getByRole)而非 CSS 选择器 - 测试用户行为而非实现细节:模拟用户点击、输入等操作,而非直接调用组件方法
- 只 mock 系统边界:mock fetch 返回预设响应,使用真实的 QueryClientProvider 包裹组件
- 组件测试文件命名:
tests/web/ComponentName.test.tsx - 测试目录镜像源码目录:
tests/server/config.test.ts对应src/server/config.ts
已知限制
- 当前仅为单页面应用,不涉及用户认证和权限控制
- 不支持集群部署,单进程运行
- 配置文件仅支持 YAML 格式,不支持热加载
- 无国际化和多语言支持