TraceStudio-dev/docs/web/code_style.md

235 lines
9.6 KiB
Markdown
Raw Normal View History

2026-01-10 19:08:49 +08:00
# 前端代码风格与架构规范Frontend Code Style
本文档面向 TraceStudio 前端开发者与 AI 助手,定义在 `web/` 下的代码风格、目录与职责分配、面向对象与函数式的使用建议、测试规范、以及代码评审/提交约定。目标是:保持一致性、可读性、可维护性,并支持节点式分析平台的扩展性。
---
## 一、总体原则
- 以可组合composition为首选优先使用函数式 React 组件 + Hooks避免复杂继承结构。面向对象用于领域模型、服务与工具非 React UI
- 协议优先于实现优先定义接口TypeScript types / interfaces节点、API 与组件通过契约schema通信而非耦合实现细节。
- 原子化与单一职责组件应尽量小、单一、易测试。复杂视图由小组件组合而成Container/Presentational 分离或 Hook 提取)。
- 明确分层UI 组件pure→ 容器/页面(组合)→ 状态层Zustand→ API 层(`src/utils/api.ts`)→ 后端。
- 防御性编程输入校验、错误边界Error Boundary、与用户友好的错误提示。
- 可测试优先:关键逻辑与交互需附带单元/集成测试。
---
## 二、技术栈约定(回顾)
- React 19 + TypeScript 5.x强制开启 `strict`
- Zustand全局/共享状态)
- React Flow节点画布
- Vite构建
- Tailwind CSS样式 + 可选 shadcn/ui 风格组件
- 测试Vitest + React Testing LibraryE2E 推荐 Playwright
- Lint/格式化ESLint + Prettier + TypeScript ESLint rules
---
## 三、目录与职责(放哪里?)
`web/src/` 下按以下约定组织文件:
- `components/`:可复用的 UI 组件(按功能或页面子目录组织)
- 每个组件使用独立目录:`components/MyComp/` 包含 `index.tsx`、`MyComp.test.tsx`、`styles.css`(如需)、`types.ts`(组件私有 types
- `components/nodes/`React Flow 的节点自定义组件(每个节点一个文件)
- `stores/`Zustand store按 domain 分文件,如 `useStore.ts`, `userStore.ts`
- `utils/`:工具函数、类型转换、`api.ts`(与后端请求封装)、`nodeRegistry.ts`(节点注册逻辑)
- `pages/``views/`:高阶页面/路由级容器(如 Workspace 页面)
- `hooks/`:自定义 Hook业务通用逻辑便于复用
- `assets/`:静态资源(图标、示例文件)
- `styles/`:全局样式与 Tailwind 配置tailwind.css
- `tests/`:大规模集成或 e2e 脚本(可选)
- `types/`:全局共享类型定义(如 `node-types.ts`、`api-types.ts`
规则举例:
- 组件目录示例:
- `src/components/FileExplorer/index.tsx`
- `src/components/FileExplorer/FileExplorer.test.tsx`
- `src/components/FileExplorer/types.ts`
- 节点组件示例:
- `src/components/nodes/CSVLoader/index.tsx`
- `src/components/nodes/CSVLoader/preview.tsx`(可选)
- `src/components/nodes/CSVLoader/types.ts`
---
## 四、命名与导出规范
- 文件名:`kebab-case` 或 `PascalCase` 视语言习惯;组件文件夹使用 PascalCase`MyComponent`),文件导出使用 `index.tsx` 导出默认组件。
- 组件名PascalCase例如 `FileExplorer`、`HeaderBar`。
- Type / Interface后缀使用 `PascalCase`,接口前缀不强制 `I`(推荐不使用),例如 `NodeMeta`, `FileInfo`
- 常量UPPER_SNAKE_CASE 或 PascalCase 视上下文(环境变量 UPPERUI 常量 PascalCase
- Hooks`use` 前缀,例如 `useFileLoader`
- Store`use` 前缀,例如 `useStore`、`useUserStore`。
导出风格:
- 组件默认导出:`export default FileExplorer`(便于懒加载)
- 类型与工具使用具名导出:`export type { NodeMeta }``export function formatDate()`
---
## 五、组件设计规范React
1. 优先使用函数组件 + Hooks。
2. 组件职责:小、单一、可复用;复杂交互拆为子组件与 Hook。
3. Props 类型:显式声明 `type Props = { ... }``React.FC<Props>``function Comp(props: Props)`
4. 不要在组件内部进行副作用外的复杂业务逻辑——将其抽到 Hook 或 store。
5. 尽量无状态presentational组件与有状态容器container分离。
6. 使用 `ErrorBoundary` 包裹可能抛错的区域(如渲染外部数据)并显示用户友好错误。
7. 可访问性a11y可键盘操作、SVG 加上 `aria-*`、语义化标签。
示例组件骨架:
```tsx
// src/components/MyWidget/index.tsx
import React from 'react'
import type { MyWidgetProps } from './types'
export default function MyWidget(props: MyWidgetProps) {
const { title, data } = props
return (
<div className="my-widget">
<h3>{title}</h3>
{/* 渲染 */}
</div>
)
}
```
---
## 六、面向对象OOP使用指导
- 在前端工程中OOP 适用于:
- 业务模型domain models和复杂数据结构例如TraceFile、ProfileSummary
- 服务类(与后端交互的封装,如 `class FileService { upload(){} }`),特别是当有内部状态/连接需要封装时。
- 禁忌:不要为了使用类而用类来实现 UI 组件React 已以函数式为主)。
- 推荐模式:小型无状态类 + 通过接口注入(依赖反转),便于在测试中替换实现。
示例(服务类):
```ts
// src/utils/FileService.ts
export class FileService {
constructor(private baseUrl: string) {}
async upload(file: File) { /* ... */ }
}
```
---
## 七、状态管理Zustand约定
- 所有应用级状态放在 `src/stores/`,按 domain 拆分(`useStore.ts` 为全局工作流状态,`useUserStore.ts` 单独管理用户信息)。
- Store 只包含状态与同步/异步的变更方法actions避免在 store 中做 DOM 操作或复杂渲染逻辑。
- Store 的方法应返回 Promise如有异步便于调用方捕获错误与链式处理。
示例:
```ts
// src/stores/useStore.ts
export const useStore = create((set, get) => ({
nodes: [],
setNodes: (nodes) => set({ nodes }),
loadWorkflow: async (path) => { /* await fetch... */ }
}))
```
---
## 八、API 层与后端契约
- 所有后端请求通过 `src/utils/api.ts` 封装为高层方法(`getPlugins()`, `executeGraph(payload)` 等)。
- API 返回应统一为 `{ data?: any, error?: string }`,前端统一解析该结构。
- 在文档中声明关键端点与示例请求/响应(见下文 API 规范草案建议)。
---
## 九、节点插件与自定义节点约定
- 节点元数据接口(示例):
```ts
export type NodeMetadata = {
display_name: string
category: string
inputs: Array<{ name: string; type: string }>
outputs: Array<{ name: string; type: string }>
params?: Record<string, any>
}
```
- 前端 `nodeRegistry` 应暴露组件映射与 `meta`,并以 `GET /api/plugins` 为数据源。如果用户上传自定义节点并注册,后端应返回插件列表更新。
- 前端对自定义节点仅渲染元数据描述与 UI 表单;执行逻辑由后端驱动或以安全沙箱运行。
---
## 十、错误处理与日志
- 所有异步 API 调用必须有错误处理try/catch并返回友好错误到 UI非控制台
- 在关键组件使用 `try { } catch (err) { setError(err.message) }` 并在 UI 显示可复制的错误信息和“定位至节点”或“查看详细日志”按钮。
---
## 十一、测试规范
- 单元/组件测试Vitest + React Testing Library
- 文件命名:`Xxx.test.ts` / `Xxx.test.tsx`
- 覆盖核心逻辑与交互包括NodePalette 渲染、拖拽行为(可模拟 dataTransfer、Inspector 参数绑定、FileExplorer 文件操作mock API
- 断言样式优先使用可见文本、ARIA 查询与行为断言(而非实现细节)。
- 集成测试:对关键业务流(导入文件 → 创建节点 → 预览 → 运行)编写集成用例。
- E2EPlaywright建议用于文件拖放、跨窗口文件预览、上传流程
- 覆盖率门槛:建议核心模块覆盖率 >= 70%node/plugins 关键逻辑 >= 80%(可视团队资源调整)。
运行命令示例:
```bash
# 在 web/ 目录
npm run test # 运行单元测试vite/vitest
npm run test:watch # 开发时监视测试
npm run test:e2e # (若配置) 运行 e2e
```
---
## 十二、Lint / 格式化 / 提交规范
- ESLint + Prettier在 PR 前执行 `npm run lint``npm run format`
- 代码风格:开启 TypeScript `strict`、避免 `any`(必要时使用注释说明)。
- Commit 信息:使用 Conventional Commits`feat:`、`fix:`、`chore:`、`docs:`等)。
- PR 模板:每个 PR 需包含变更摘要、测试说明、影响范围、回滚/兼容性注意事项。
---
## 十三、Code Review Checklist最少项
- 代码是否小且聚焦单一职责?
- 有无单元/集成测试覆盖关键路径?
- 类型是否明确(避免 any
- 是否保持了 UI/UX 与现有组件风格一致?
- 是否包含必要的错误处理与用户提示?
- 是否有性能或安全问题(例如不受限的文件读写、直接 eval
---
## 十四、示例:将新功能放在哪儿(快速参考)
- 新增后端 API 的前端支持:
- `utils/api.ts` 添加调用方法
- `stores/` 添加状态/方法
- `components/` 添加或更新 UI
- `components/nodes/` 若涉及新节点,添加节点组件并更新 `nodeRegistry`
- 新增 UI 视图:在 `pages/` 新建页面,页面中组合已有组件或新增 container 组件。
---
## 十五、附录 - 推荐工具 & VSCode 插件
- ESLint, Prettier, TypeScript, Vitest, Playwright, Tailwind CSS Intellisense
- GitLens, EditorConfig, ESLint plugin for VSCode
---