TraceStudio-dev/docs/web/code_style.md
Boshuang Zhao 5790ec164f add web v2
2026-01-10 19:08:49 +08:00

235 lines
9.6 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.

# 前端代码风格与架构规范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
---