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

9.6 KiB
Raw Permalink Blame History

前端代码风格与架构规范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.tsxMyComp.test.tsxstyles.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.tsapi-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-casePascalCase 视语言习惯;组件文件夹使用 PascalCaseMyComponent),文件导出使用 index.tsx 导出默认组件。
  • 组件名PascalCase例如 FileExplorerHeaderBar
  • Type / Interface后缀使用 PascalCase,接口前缀不强制 I(推荐不使用),例如 NodeMeta, FileInfo
  • 常量UPPER_SNAKE_CASE 或 PascalCase 视上下文(环境变量 UPPERUI 常量 PascalCase
  • Hooksuse 前缀,例如 useFileLoader
  • Storeuse 前缀,例如 useStoreuseUserStore

导出风格:

  • 组件默认导出: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-*、语义化标签。

示例组件骨架:

// 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 已以函数式为主)。
  • 推荐模式:小型无状态类 + 通过接口注入(依赖反转),便于在测试中替换实现。

示例(服务类):

// 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如有异步便于调用方捕获错误与链式处理。

示例:

// 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 规范草案建议)。

九、节点插件与自定义节点约定

  • 节点元数据接口(示例):
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%(可视团队资源调整)。

运行命令示例:

# 在 web/ 目录
npm run test        # 运行单元测试vite/vitest
npm run test:watch  # 开发时监视测试
npm run test:e2e    # (若配置) 运行 e2e

十二、Lint / 格式化 / 提交规范

  • ESLint + Prettier在 PR 前执行 npm run lintnpm run format
  • 代码风格:开启 TypeScript strict、避免 any(必要时使用注释说明)。
  • Commit 信息:使用 Conventional Commitsfeat: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