Files
bun-app-template/DEVELOPMENT.md
lanyuanxiaoyao 4caf502908 feat: 重构前端为企业 Admin 后台布局,引入 React Router 路由
- 引入 React Router v7 (Declarative mode) 实现 SPA 路由
- 重构 Layout 为 Header + 侧边栏 + 内容区的企业 Admin 布局
- 新增侧边栏菜单组件,支持折叠/展开,状态持久化到 localStorage
- 新增示例页面:仪表盘、用户管理、系统设置、404
- 菜单配置与路由统一为单一数据源 (menu.tsx)
- Vite code splitting 新增 vendor-router 组
- 更新 DEVELOPMENT.md 和 README.md 文档
2026-05-20 19:06:14 +08:00

710 lines
31 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.
my-app 开发文档
本文档面向 `my-app` 项目的开发者,介绍项目结构、前后端架构、构建流程、测试、代码规范等内容。
用户使用说明请参阅 [README.md](README.md)。
## 目录
- [项目结构](#项目结构)
- [前后端边界](#前后端边界)
- [一、后端开发指引](#一后端开发指引)
- [二、前端开发指引](#二前端开发指引)
- [三、项目运行、集成与打包](#三项目运行集成与打包)
- [代码质量](#代码质量)
- [测试](#测试)
- [已知限制](#已知限制)
---
## 项目结构
```text
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 主题偏好 hooksystem/light/darklocalStorage 记忆 + matchMedia 监听)
use-sidebar-collapsed.ts 侧边栏折叠状态 hooklocalStorage 记忆)
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 对象:
```typescript
// server.ts 中的路由注册
routes: {
"/api/*": () => jsonResponse(createApiError("API route not found", 404), { mode, status: 404 }),
"/health": {
GET: () => handleHealth(mode),
},
}
```
Handler 函数签名:
```typescript
// 无依赖的路由
export function handleHealth(mode: RuntimeMode): Response;
```
**请求处理流程**
1. `Bun.serve``routes` 对象按路径 + HTTP 方法匹配请求
2. 未匹配方法的请求落入 `/api/*` 通配符(返回 404
3. 各 handler 内部通过 `helpers.ts``jsonResponse``createApiError` 等格式化输出
4. 需要参数校验时使用 `middleware.ts` 提供的校验函数,返回 `Response` 实例表示校验失败(直接返回),返回数据对象表示通过
**新增路由步骤**
1.`src/server/routes/` 下创建 `<name>.ts`
2. 实现 handler 函数并 export
3.`server.ts``routes` 对象中注册路径和 method handler
4.`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 }``Response`
- `validatePagination(pageParam, pageSizeParam, mode)` — 校验分页参数(默认 page=1, pageSize=20pageSize 上限 200返回 `{ page, pageSize }``Response`
- `validateTimeRange(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`
```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
└── ErrorBoundaryReact 错误边界)
└── QueryClientProviderTanStack Query 全局挂载)
└── BrowserRouterReact Router 路由)
├── App根组件Admin 布局)
│ ├── useThemePreference() ── Header 主题模式 RadioGroup系统/明亮/黑暗)
│ ├── useSidebarCollapsed() ── 侧边栏折叠状态localStorage 记忆)
│ ├── Layout
│ │ ├── Header折叠按钮 + 品牌名 + 页标题 + 主题切换)
│ │ └── Layout嵌套
│ │ ├── Aside
│ │ │ └── SidebarTDesign Menu菜单项点击导航
│ │ └── Content
│ │ └── AppRoutes路由配置
│ │ ├── / → DashboardPage欢迎语 + /health 联调)
│ │ ├── /users → UsersPage占位
│ │ ├── /settings → SettingsPage占位
│ │ └── * → NotFoundPage404
└── ReactQueryDevtools开发工具仅开发环境
```
**Hook 架构**
```
hooks/use-theme-preference.ts浏览器 UI 偏好)
├── ThemePreference: system / light / darkRadioGroup 受控值)
├── 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 规范
```typescript
// 使用 structured array非字符串以便精确匹配和按 prefix 失效
const queryKeys = {
health: () => ["health"] as const,
};
```
- Key 使用 **structured array**(非字符串),以便精确匹配和按 prefix 失效
- 使用 `as const` 保持字面量类型
#### 查询配置规范
```typescript
// 全局级查询(需要持续刷新)
useQuery({
queryKey: queryKeys.health(),
queryFn: () => fetchJson<HealthResponse>("/health"),
refetchInterval: 30000, // 30s 轮询
refetchIntervalInBackground: false, // 切后台不轮询
staleTime: 5000, // 5s 内视为 fresh
});
```
#### fetch 封装
```typescript
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 全局配置
```typescript
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 { ... }`
```typescript
import type { HealthResponse } from "../shared/api";
interface AppProps {
title?: string;
}
export function App({ title }: AppProps) {
// ...
}
```
#### 组件拆分原则
- **展示组件**`components/`):纯渲染逻辑,通过 props 接收数据,通过回调返回事件
- **容器逻辑**放在 hooks 中,组件只做数据消费
- **工具函数**(时间处理等)放在 `utils/`,保持纯函数无副作用
### 2.5 样式开发规范
前端基于 TDesign React 构建 UI样式开发遵循以下优先级从高到低
1. **使用 TDesign 组件**:布局、间距、排版优先使用 TDesign 组件(如 Space、Divider、Typography
2. **使用 TDesign 组件 props**:通过组件的 props 参数控制外观(如 `theme``variant``size`
3. **使用 TDesign CSS tokens**:颜色、间距、字体等使用 `--td-*` CSS 变量(如 `--td-success-color``--td-comp-margin-xxl`
4. **在 styles.css 中定义 CSS 类**:无法通过上述方式满足的样式需求,集中定义在 `styles.css`
5. **自行开发组件**:仅在 TDesign 无法满足需求时自行开发
**红线**
- **严禁在组件中使用 `style` 属性内联调整样式**
- **严禁通过 CSS 覆盖 TDesign 组件内部类名**(如 `.t-tab-panel`),如需定制使用组件的 `className` prop
- **严禁使用 `!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 开发期运行
```bash
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` 请求代理到后端。
也可以单独启动:
```bash
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 可执行文件:
```typescript
// 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 构建打包
#### 构建命令
```bash
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 splittingvendor-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` |
#### 运行可执行文件
```bash
./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
#### 清理
```bash
bun run clean
# 清理 dist/ 构建产物和 .build/ 临时文件
```
### 3.4 开发工作流
#### 日常开发循环
```bash
bun run dev [config.yaml] # 启动双进程开发环境Vite :5173 + API :3000
# 访问 http://127.0.0.1:5173
# 修改前端代码 → Vite HMR 热更新 / 修改后端代码 → --watch 自动重启
bun run check # 提交前运行完整质量检查
```
#### 完整验证流程
```bash
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 → ESLintMD/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 自动化。
```bash
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无需手动配置。
### 质量检查完整清单
提交代码前建议运行:
```bash
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` |
### 运行命令
```bash
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 组件所需的 polyfillResizeObserver、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 格式,不支持热加载
- 无国际化和多语言支持