完成 Muse Studio React SPA 基座和六个用户端功能域,接入 MSW Mock、Tiptap 写作台、知识库资料管理、智能体槽位预检绑定、市场授权安装和个人中心用量权益视图。
3.0 KiB
3.0 KiB
muse-studio 写作台与 AI 协作实现留痕
任务背景
在 muse-studio 前端子项目集成 Tiptap 富文本编辑器,实现本地 IndexedDB 影子层与远程 API 的双向防抖同步,接入 SSE AI 流式生成文本,并实现字符级高亮差异比对及采纳替换的闭环流程。
核心设计与踩坑总结
1. 分级 Diff 字符比对设计 (Coarse-to-Fine)
- 挑战:经典的 DP(动态规划)LCS 算法时间复杂度为 $O(N \times M)$。在长篇小说场景下,对 3000 字以上的内容进行字符级 LCS 对比,计算矩阵元素高达近千万,直接导致浏览器 UI 线程卡死(ANR)。
- 优化实现:
- 段落级粗筛:以段落(
\n)为元素单元,首先运行一遍粗粒度的段落 LCS。 - 局部字符 LCS 细筛:如果段落被判定为
modified(即相邻的一段被删除、一段被新增,视为修改),且单段字数在安全限制(乘积小于 1,000,000)内,才对其进行细粒度的字符级 LCS 比对。 - 非空安全断言:在 TS 极严模式(
noUncheckedIndexedAccess: true)下,对二维矩阵dp[i]级别的读取,使用局部变量承接和非空断言(!),消除对象可能为undefined的编译问题。
- 段落级粗筛:以段落(
- 效果:长文本 Diff 运算时长由秒级缩短至 4 毫秒,彻底消除了卡顿风险。
2. 编辑器双防抖与临别落库机制
- ** IndexedDB IO 去抖 (500ms)**:打字时内容先进入本地 IndexedDB 去抖保存,避免高频按键对磁盘读写的密集事务挤占,优化 INP 打字卡顿。
- API 远程去抖 (2000ms):延迟 2 秒调用
PUT接口,同步成功后销毁本地影子草稿以释放磁盘。 - 临别落库 (Flush):为防范打字结束 2 秒内用户突然离开页面导致最新修改丢失,扩展
debounce模块提供.cancel()与.flush()能力。在编辑器useEffect卸载 cleanup 中:useEffect(() => { return () => { debouncedAPISave.flush(); // 立即将挂起的定时任务提交 API 执行 debouncedAPISave.cancel(); // 释放定时器引用 }; }, [blockId]);
3. Zustand Selector 精准状态更新
- 挑战:多栏式写作台包含章节大纲、编辑器、AI 面板。如果解构式订阅 Zustand Store,打字时高频的
isDirty变化会触发整棵组件树重渲染,造成严重输入卡顿。 - 避坑:组件必须使用精细 Selector 单独订阅特定状态,严禁解构大对象,阻断不必要的 React Re-render:
const markDirty = useEditorStore((state) => state.markDirty);
4. 远程 API 同步失败异常捕获 (sync_failed)
- 实现:如果
PUT同步接口失败,通过catch捕获异常,立刻将 IndexedDB 对应小节的本地缓存状态覆写为status: 'sync_failed'。 - 恢复:编辑器组件初始化挂载时,查询该小节是否存在
sync_failed状态记录,若存在则提示恢复横幅“恢复草稿 / 忽略并覆写”,闭环了离线保存安全网。