Skip to content

Commit c122dfa

Browse files
committed
docs(canvas): refresh architecture audit
1 parent 1920477 commit c122dfa

1 file changed

Lines changed: 45 additions & 37 deletions

File tree

refs/canvas-architecture-audit.md

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
# Canvas 模块架构审计
22

3-
日期: 2026-03-23
4-
范围: `src/pages/canvas.tsx``src/stores/canvasStore.ts``src/stores/canvasRuntimeStore.ts``src/features/canvas/*`
3+
日期: 2026-03-24
4+
范围: `src/pages/canvas.tsx``src/stores/canvasStore.ts``src/features/canvas/runtime/*``src/features/canvas/*`
55
评价口径: 是否适合后续迭代,不评价 UI 完成度
66

77
## 状态更新
88

9-
- 状态: `canvasStore` 第一阶段 seam 拆分已落地;`CanvasViewport` 第二刀 seam 拆分也已落地,已从“stage shell + viewport navigation hook + marquee selection hook + text/overlay host”继续收缩为“composition shell + stage shell + tool/input orchestrator + overlay host + lifecycle/navigation seam”;panel 第一刀 seam 收口也已落地,已从“panel 直接决定领域更新”收缩为“panel view + model hook + pure planner/state seam”;文本会话 P1 也已落地,已从“hook + refs + effects 串联状态机”继续收口为“pure reducer + effect runner + thin hook adapter + session snapshot”。
10-
- 总评: `8.0/10`
9+
- 状态: `canvasStore` 第一阶段 seam 拆分已落地;`CanvasViewport` 第二刀 seam 拆分也已落地,已从“stage shell + viewport navigation hook + marquee selection hook + text/overlay host”继续收缩为“composition shell + stage shell + tool/input orchestrator + overlay host + lifecycle/navigation seam”;panel 第一刀 seam 收口也已落地,已从“panel 直接决定领域更新”收缩为“panel view + model hook + pure planner/state seam”;文本会话 P1 也已落地,已从“hook + refs + effects 串联状态机”继续收口为“pure reducer + effect runner + thin hook adapter + session snapshot”;runtime preview P1 也已落地,已从“隐式全局单例 + 全局 store 取数”收口为“`CanvasPage` 下的 scoped provider + runtime scope + preview controller + narrow hooks”
10+
- 总评: `8.2/10`
1111
- 当前最强的一层: 文档内核
12-
- 当前最弱的两层: runtime preview / 页面与路由装配
13-
- 当前最明显的结构热点: 页面入口仍带一部分恢复策略`canvasRuntimeStore` 仍直接依赖全局 store 取数,文本属性修改入口也还没有完全统一到同一个 use-case seam
14-
- 验证基线: `pnpm test` 通过,相关回归共 `113` 个测试文件、`456` 个 case 全部通过;`pnpm lint` 通过,但保留 `5` 个既有 warning;`pnpm build:client` 通过;本轮额外做了 architecture + bug/regression 两轮 review,均无新增阻断问题;另做了基于 `agent-browser` 的文本 smoke 验证,跑通 create -> commit、create -> cancel、edit -> switch workbench 三条路径
12+
- 当前最弱的两层: 页面与路由装配 / 渲染与导出
13+
- 当前最明显的结构热点: 页面入口仍带一部分恢复策略,导出入口仍保留 stage snapshot 分支,文本属性修改入口也还没有完全统一到同一个 use-case seam
14+
- 验证基线: `pnpm test` 通过,相关回归共 `116` 个测试文件、`476` 个 case 全部通过;`pnpm lint` 通过,但保留 `5` 个既有 warning;`pnpm build:client` 通过;本轮额外做了 architecture + bug/regression + performance 三轮 review,均无新增阻断问题
1515
- 下一阶段优先级:
16-
1. 处理页面入口 / 文本会话 / runtime preview 的应用层边界
17-
2. 再继续收紧 `canvasStore` 的 active-workbench 门面,避免它重新长回万能入口
18-
3. `CanvasExportDialog` / `CanvasImageEditPanel` 等剩余入口继续并入现有 seam,避免局部反弹
16+
1. 处理页面入口 / 路由恢复策略的应用层边界
17+
2. 统一导出 / 图片编辑 / 属性修改剩余入口,避免绕开现有 seam
18+
3. 继续保护 `runtime preview` / 文本会话 / `CanvasViewport` / `canvasStore` active-workbench 门面,避免复杂度回流
1919

2020
## 评分口径
2121

@@ -87,11 +87,12 @@
8787

8888
评分: `6/10`
8989

90-
重构优先级: `P2`
90+
重构优先级: `P1`
9191

9292
判断:
9393

94-
- 还没有坏到必须立刻拆,但已经超出“纯页面壳”的范围。
94+
- 这一层现在已经是最明确的下一刀目标。
95+
- 如果继续把恢复策略、panel 切换策略和 URL state 叠在入口层,这里会重新成为新的复杂度汇聚点。
9596

9697
## 2. 文档内核
9798

@@ -212,13 +213,17 @@
212213
判断:
213214

214215
- 这层已经从“最大结构瓶颈”降到了“可继续承接后续拆分”的状态。
215-
- 目前不需要立刻继续深拆它,下一刀应该转向 `CanvasViewport`、文本会话与 runtime preview
216+
- 目前不需要立刻继续深拆它,下一刀应该转向页面入口 / 路由恢复与剩余导出入口统一
216217

217218
## 4. 运行时预览管线
218219

219220
文件重点:
220221

221-
- `src/stores/canvasRuntimeStore.ts`
222+
- `src/features/canvas/runtime/CanvasRuntimeProvider.tsx`
223+
- `src/features/canvas/runtime/canvasRuntimeScope.ts`
224+
- `src/features/canvas/runtime/canvasPreviewRuntimeController.ts`
225+
- `src/features/canvas/runtime/canvasPreviewRuntimeState.ts`
226+
- `src/features/canvas/runtime/canvasRuntimeHooks.ts`
222227
- `src/features/canvas/boardImageRendering.ts`
223228

224229
职责:
@@ -236,35 +241,38 @@
236241

237242
依赖方向:
238243

239-
- runtime store 依赖 `useCanvasStore.getState()``useAssetStore.getState()`
240-
- element 组件和 edit panel 依赖 runtime store
244+
- runtime scope 依赖 `CanvasRuntimeProvider` 显式输入的 `workbenchId``workbench``viewportScale`,以及 `assetStore` 发出的 `assets:changed`
245+
- `ImageElement``CanvasImageEditPanel`、selection hooks 依赖 scoped runtime hooks,而不是全局 runtime store
241246

242247
关键状态转换/不变量:
243248

244249
- interactive preview 优先于 background preview
245250
- 交互结束后要自动升级为 settled/background 版本
251+
- `workbenchId` 切换、页面卸载或 `currentUser:reset` 时必须 dispose active request、queued task、settle timer、backing canvas、draft adjustments 和 selection preview
252+
- scope 切换后旧请求结果不能落回新 scope
246253
- 缓存淘汰不能踢掉 rendering/queued 中的任务
247254
- preview source 释放时要及时清空 backing store
248255

249256
优点:
250257

251-
- 相比持久化 store,这层至少已经被单独抽出来
252-
- preview 调度和缓存语义明确
253-
- 对交互预览和背景预览做了清晰区分
258+
- runtime preview 现在是 `CanvasPage` 下的 scoped service,生命周期终于和 workbench/page 对齐
259+
- `CanvasPreviewRuntimeController` 只保留任务排队、优先级、落库、淘汰和 stale result 忽略,职责比原来清楚很多
260+
- runtime asset 改成 scope 内的 per-asset snapshot + listener,`ImageElement` 不再为读单个 asset 扫整份资产表
261+
- selection preview 和图片渲染 controller 共用 scope,但边界已经拆开,不再混成一块宽 store
254262

255263
问题:
256264

257-
- 还不是真正独立的 runtime service,仍直接从全局 store 拉数据
258-
- 通过 element id 全局扫描 workbench element,边界不够清晰
259-
- 模块级队列和 slot 状态让这层更像“全局单例运行时”,未来做 workbench scope、销毁时机会更麻烦
265+
- 这层虽然已经 service 化,但仍依赖 UI 消费端遵守 request/release discipline;后续新入口如果绕开 hooks,仍可能把泄漏重新带回来
266+
- preview runtime 只覆盖编辑态预览,不覆盖导出主路径;“编辑预览”和“最终导出”仍是两套相邻但未统一的管线
267+
- asset 变更现在通过 `assets:changed` 事件增量推送,性能边界更好,但事件契约需要继续保持窄而稳定,避免重新长成宽广播
260268

261-
评分: `6.5/10`
269+
评分: `8.6/10`
262270

263-
重构优先级: `P2`
271+
重构优先级: `已完成本轮 P1,后续降为 P2`
264272

265273
判断:
266274

267-
- 拆分方向是对的,但还没拆彻底
275+
- 这一层已经达到当前阶段的 `8.5+` 目标,可以从“首要拆分对象”降到“需要防止反弹的已收口 seam”
268276

269277
## 5. 视口与交互引擎
270278

@@ -518,7 +526,7 @@
518526

519527
评分: `7/10`
520528

521-
重构优先级: `P3`
529+
重构优先级: `P2`
522530

523531
判断:
524532

@@ -531,7 +539,7 @@
531539
- 页面装配: `src/pages/canvas.tsx`
532540
- 文档内核: `src/features/canvas/document/*`
533541
- 持久化与提交队列: `src/stores/canvasStore.ts``src/features/canvas/store/*`
534-
- 运行时预览: `src/stores/canvasRuntimeStore.ts`
542+
- 运行时预览: `src/features/canvas/runtime/*`
535543
- 视口与交互: `src/features/canvas/CanvasViewport.tsx``src/features/canvas/CanvasViewportStageShell.tsx``src/features/canvas/CanvasViewportOverlayHost.tsx``src/features/canvas/hooks/useCanvasViewportLifecycle.ts``src/features/canvas/hooks/useCanvasViewportNavigation.ts``src/features/canvas/hooks/useCanvasViewportToolOrchestrator.ts``src/features/canvas/hooks/useCanvasMarqueeSelection.ts`
536544
- 文本会话: `src/features/canvas/hooks/useCanvasTextSession.ts`
537545
- 面板层: `src/features/canvas/CanvasLayerPanel.tsx``CanvasStoryPanel.tsx``CanvasPropertiesPanel.tsx`
@@ -541,7 +549,7 @@
541549

542550
- `src/stores/canvasStore.test.ts`
543551
- `src/features/canvas/store/canvasWorkbenchState.test.ts`
544-
- `src/stores/canvasRuntimeStore.test.ts`
552+
- `src/features/canvas/runtime/canvasPreviewRuntimeState.test.ts`
545553
- `src/features/canvas/document/commands.test.ts`
546554
- `src/features/canvas/document/resolve.test.ts`
547555
- `src/features/canvas/renderCanvasDocument.test.ts`
@@ -555,32 +563,32 @@
555563
### P1
556564

557565
- 页面入口的恢复策略下沉为更明确的应用层
558-
- runtime preview 从全局 store 读取模型转向更明确的 workbench-scoped 输入
559566

560567
### P2
561568

569+
- 保护 runtime preview 新的 scoped service seam,不让新的图片编辑或选择逻辑重新绕开 provider / narrow hooks
562570
- 保护文本会话新的 reducer / effect runner / snapshot seam,不让新的文本能力重新堆回 hook
563571
- 继续收紧 `canvasStore` 的 active-workbench 门面,避免它重新长回“万能接口集合”
564572
-`CanvasExportDialog` / `CanvasImageEditPanel` 等剩余入口继续并入现有 panel seam,避免局部反弹
573+
- 统一导出主路径,减少 stage snapshot 分支
565574
- 保护 `CanvasViewport` 新的 stage / tool / overlay seam,不让新的交互策略重新堆回组合壳
566575

567576
### P3
568577

569578
- 保护文档内核,不做推倒重写
570-
- 统一导出主路径,减少 stage snapshot 分支
571579

572580
## 推荐的拆分顺序
573581

574-
1. 先处理页面入口 / runtime preview 的 service 化和边界下沉
575-
2. 再继续收紧 `canvasStore` 对上层暴露的 active-workbench 门面
576-
3. 同时保护文本会话与 `CanvasViewport` 新的 seam,不让新的交互策略重新回流
577-
4. 最后把剩余未收口的 panel 入口并到现有 seam 上,避免重新长回组件内规则
582+
1. 先处理页面入口 / 路由恢复策略的 service 化和边界下沉
583+
2. 再统一导出 / 图片编辑 / 属性修改这些仍分散的应用层入口
584+
3. 继续收紧 `canvasStore` 对上层暴露的 active-workbench 门面
585+
4. 同时保护 runtime preview、文本会话与 `CanvasViewport` 新的 seam,不让新的交互策略重新回流
578586

579587
## 最终判断
580588

581-
这轮之后,最紧急的 seam 已经从 panel 层和文本会话残留宿主,转向了页面入口 / runtime preview 的应用层边界
589+
这轮之后,最紧急的 seam 已经从 panel 层、文本会话残留宿主和 runtime preview,全都转向了页面入口 / 路由恢复与导出入口统一
582590

583-
- 如果继续堆功能,复杂度会优先集中在页面入口和 runtime preview,而不是重新首先压垮文本会话`CanvasViewport`、panel 层或 `canvasStore.ts`
591+
- 如果继续堆功能,复杂度会优先集中在页面入口和导出相关入口,而不是重新首先压垮 runtime preview、文本会话`CanvasViewport`、panel 层或 `canvasStore.ts`
584592
- panel 层现在已经能继续承接下一轮拆分,但还不值得宣布“整个 canvas 完成”
585-
- 文本会话与 `CanvasViewport` 这两层已经可以承接后续功能,但前提是不要把新的恢复策略、DOM 宿主逻辑和工具策略重新塞回组合壳
593+
- runtime preview、文本会话与 `CanvasViewport` 这几层已经可以承接后续功能,但前提是不要把新的恢复策略、导出旁路或工具策略重新塞回这些 seam
586594
- 文档内核这条健康链路仍然应该继续被保护,后续重构仍应围绕上层应用边界展开

0 commit comments

Comments
 (0)