# 前端代码风格与架构规范(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 Library;E2E 推荐 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 视上下文(环境变量 UPPER,UI 常量 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` 或 `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 (

{title}

{/* 渲染 */}
) } ``` --- ## 六、面向对象(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 } ``` - 前端 `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 查询与行为断言(而非实现细节)。 - 集成测试:对关键业务流(导入文件 → 创建节点 → 预览 → 运行)编写集成用例。 - E2E:Playwright(建议用于文件拖放、跨窗口文件预览、上传流程) - 覆盖率门槛:建议核心模块覆盖率 >= 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 ---