Files
pixel/docs/FRONTEND_OPTIMIZATION.md
张鹏 f9f4560459 Initial commit: Pixel AI comic/video creation platform
- FastAPI backend with SQLModel, Alembic migrations, AgentScope agents
- Next.js 15 frontend with React 19, Tailwind, Zustand, React Flow
- Multi-provider AI system (DashScope, Kling, MiniMax, Volcengine, OpenAI, etc.)
- All HTTP clients migrated from sync requests to async httpx
- Admin-managed API keys via environment variables
- SSRF vulnerability fixed in ensure_url()
2026-04-29 01:20:12 +08:00

10 KiB
Raw Permalink Blame History

前端优化建议

本文档基于对当前前端代码的检查,给出可执行的优化建议,按优先级和类别组织。


一、已修复问题

1. 项目设置保存 API 路径错误

  • 位置frontend/src/components/canvas/panels/management/project-details/tabs/SettingsTab.tsx
  • 问题:使用 fetch(\${OpenAPI.BASE}/api/projects/${projectId}`)请求的是/api/projects/:id,而后端路由为 /api/v1/projects/:id`,导致 404。
  • 修复:改为使用生成的 API 客户端 DefaultService.updateProject(projectId, updateData),保证请求路径为 /api/v1/projects/:id
  • 说明:若后端需要持久化 typestatusdefaultImageModel 等,需在 UpdateProjectRequest 中声明对应字段。

二、配置与一致性

2. API Base URL 与 Rewrites 统一(已落地)

  • 现状
    • next.config.mjs 使用 API_URL(无 NEXT_PUBLIC_)做 rewrites。
    • frontend/src/lib/client.ts 使用 NEXT_PUBLIC_API_URL || 'http://localhost:8000' 设置 OpenAPI.BASE
  • 已做
    • client.ts 改为 OpenAPI.BASE = process.env.NEXT_PUBLIC_API_URL ?? '',默认走同源 + rewrites。
    • next.config.mjs 增加注释说明 API_URLNEXT_PUBLIC_API_URL 的职责。
    • 新增 frontend/.env.example,说明 API_URL(服务端 rewritesNEXT_PUBLIC_API_URL(浏览器端,不设则用同源)。

3. 依赖声明(已落地)

  • 现状canvasStore.ts 使用 lodash-es(如 debounce),但 package.json 中只有 @types/lodash-esdevDependencylodash-es 为间接依赖。
  • 已做:在 dependencies 中显式添加 lodash-es: ^4.17.21

三、数据请求与状态

4. 项目页用 React Query 替代手写 fetch已落地

  • 位置frontend/src/app/project/[id]/page.tsx
  • 已做
    • 新增 useProjectWorkspace(projectId)useProjects.ts),内部使用 useQuery + getProject(id, false, true),缓存 key 为 projectKeys.workspace(id),与列表/详情隔离。
    • 项目页改为使用该 hook无 projectId 时展示「无效的项目」loading 时展示 LoadingStateerror 时展示错误文案 +「重试」按钮(调用 refetch)。
    • 数据同步到 useProjectStore 在 hook 的 useEffect 中完成,依赖仅 projectIdquery.data,避免 setter 导致重复请求。

5. 项目页初始化逻辑(已落地)

  • 已做:在 useProjectWorkspace 内用 initialEpisodeSetRef 保证「有集数据且当前无选中集时自动选中第一集」只执行一次;切换 projectId 时重置该 ref避免 refetch 覆盖用户已选集。

四、性能与包体积

6. 大组件与动态加载(已落地)

  • 现状Canvas.tsxAppNode.tsx 已对部分重量级组件使用 next/dynamicImageCropper、SketchEditor、SettingsModal、ProjectDetailsModal、ExpandedView、RightSidebar、各 Node Renderer方向正确。
  • 已做
    • Canvas:底部输入栏 InteractionInput 改为 next/dynamic 按需加载,首屏不阻塞;展示「加载输入栏...」占位。
    • InteractionInputChatDisplay 改为 next/dynamic,仅在用户打开「助手」聊天时加载对应 chunk。
    • next.config.mjsoptimizePackageImports 增加 @radix-ui/react-dialog@radix-ui/react-dropdown-menu@radix-ui/react-select@radix-ui/react-tabs,与现有 @lobehub/iconslucide-reactframer-motion 一起做 barrel 优化;可定期检查是否再加大库。

7. 画布相关 memo 与订阅(已落地)

  • 现状Canvas 已对 Sidebar、RightSidebar、CanvasContextMenu 使用 memoZustand 需注意选择器粒度。
  • 已做
    • 单字段订阅:画布相关 hooks 与组件中,凡只用 store 单一字段的,一律改为 useProjectStore((s) => s.xxx) / useCanvasStore((s) => s.xxx)(如 useNodeExecutionuseCanvasPersistenceuseGenerationHistoryCanvasManagerStoryboardDetailsCreateAssetForm)。
    • 多字段订阅:需要多个字段的改用 useShallow,避免整 store 订阅导致无关变更触发重渲染。已改:useNodeActionsuseCanvasInitializationuseAssetSaverStoryboardsTabScriptTabAssetsTabProjectDetailsModalEpisodeDetailsCanvasRightDockOverviewTabSettingsTab
    • 回调稳定性:上述从 store 取出的 actionupdateAssetsetProject)由 Zustand 提供,引用稳定,子组件不会因回调引用变而多余重渲染。

五、错误处理与健壮性

8. 使用 ErrorBoundary 包裹画布(已落地)

  • 位置frontend/src/app/project/[id]/page.tsx
  • 已做:项目页已用 CanvasErrorBoundary 包裹 <Canvas />,画布渲染异常会展示 fallback不再直接白屏。

9. 控制台与类型(进行中)

  • 已做(第一批)
    • logger 参数类型从 any[] 收紧为 unknown[]
    • 核心链路改造为 loggerOfflineSyncProviderCanvasPersistenceServiceuseCanvasInitialization
  • 后续:其余 console.*any 仍较多,建议按模块持续替换(交互输入、项目管理、设置页优先)。

六、代码结构与可维护性

10. 超大类/文件拆分(进行中)

  • 现状InteractionInput.tsxAutoResizeTextarea.tsx 等单文件超过 700 行,逻辑多、状态多。

  • 风险

    • 修改任意一处逻辑都可能影响到完全无关的功能,容易产生回归。
    • 代码评审成本高,新同学上手困难。
    • 无法对局部逻辑做针对性单测或 Storybook。
  • 建议(结构拆分)

    • 按“Tab/模式”(如 text / image / video / audio、或“编辑态 vs 创建态”拆成子组件或自定义 hooksuseInteractionEditModeuseGenerationSubmit),主文件只做组合与布局。
    • 通用逻辑(如输入框自适应高度、回车发送、快捷键、草稿保存)沉淀为 useXXX hooks 或 components/common/ 下的基础组件,避免在多个页面重复实现。
    • 对于复用度低但逻辑复杂的块(如“生成参数面板”“节点执行状态展示”),放到 components/canvas/interaction/ 等子目录中,以“目录 + index 组件”形式归类。
  • 建议(渐进式重构策略)

    • 以“先抽 hooks 再拆 UI”为原则先把明显的纯业务逻辑如表单状态、提交节流、API 调用)抽到 hooks再将 View 拆分为多个视觉组件。
    • 每次 PR 控制拆分粒度(例如一次只拆出一个 Tab 或一个大功能块),并配合简单的回归路径说明(“本次拆分仅影响 xx Tab 的输入与发送”)。
    • 对已拆分出的 hooks/子组件,在命名与文件路径上保持稳定,避免后续再次大规模移动。
  • 已做(第一步)

    • AutoResizeTextarea 中 mention 解析与 chip 构建抽离到 controls/interaction-input/mentionUtils.ts,减少主组件体积并提高复用性。

11. API 调用方式统一

  • 现状:绝大多数使用 DefaultService.*,仅 SettingsTab 曾用裸 fetch(已改为 DefaultService
  • 风险
    • 手写 URL/api/v1/...)容易与后端路由或版本前缀不一致,导致线上才暴露问题。
    • 缺失统一的错误处理与类型约束,不利于后续做全局 toast、重试等能力。
  • 建议(编码规范)
    • 新功能 一律优先使用 生成的 DefaultService/各 Service不再手写 fetch + 字符串路径。
    • 仅在极少数场景(如第三方 webhook、中转代理允许使用裸 fetch,并在代码上方用注释说明原因。
    • 不在组件内直接使用 fetch,而是封装到 frontend/src/lib/api/xxx.ts 或对应 Service wrapper 中,组件只关心“调用哪个方法”。
  • 建议(基础设施)
    • 如有需要,可在 lib/client.ts 或单独文件中,封装统一的 request/mutation helper例如整合 React Query、错误提示、埋点等再由 DefaultService 在内部复用。
    • 为常用的实体(如 Project、Episode、Asset提供对应 useProjectQueryuseProjectMutation 等 hooks对外只暴露 hooks不暴露底层 Service 调用细节。
    • 在代码评审 Checklist 中增加一项:“是否使用了生成的 Service而不是手写 fetch”,借此约束新增代码。

12. 国际化 (i18n)

  • 现状:已接入 i18next部分文案使用 useTranslation,同时存在大量中文硬编码。
  • 建议:若计划多语言,逐步将界面文案迁到 i18n key若短期仅中文可在文档中说明当前策略避免混用导致维护成本增加。

七、测试与质量

13. React Query 默认配置(已落地)

  • 已做
    • QueryProvider 默认值调整为更保守策略:staleTime: 1minretry: 1refetchOnReconnect: true
    • useProjects / useProject / useProjectWorkspace 上显式配置 staleTimeretryretryDelayrefetchOnReconnect;其中 workspace 查询单独设置 staleTime: 60s,避免沿用全局一刀切。

14. 端到端与关键路径(进行中)

  • 已做(基线)
    • 新增 Playwright 配置:frontend/playwright.config.ts
    • 新增关键路径 E2Efrontend/tests/e2e/project-canvas.spec.ts(进入项目 → 载入画布 → 新增提示词节点 → 编辑内容 → 触发保存并断言保存请求)。
    • 新增脚本:frontend/package.jsone2e / e2e:headed
  • 后续:补充分镜编辑、素材拖拽、失败重试等场景。

八、小结优先级

优先级 说明
项目设置 API 路径 已修复
项目页 loading/error 与 React Query 已落地
画布 ErrorBoundary 避免白屏
API Base 与 env 说明 减少部署/联调困惑
lodash-es 显式依赖 依赖健康
大组件与动态加载 已落地
画布 memo 与细粒度订阅 已落地
大组件拆分(超大类拆 hooks/子组件) 性能与可维护性
console → logger、减少 any 长期可维护性
i18n 策略统一 若有多语言计划

如需对某一项做具体改动(例如贴出 patch 或分步实现),可以指定编号或文件路径继续细化。