
Slate v2 事务运行时硬切割架构从快照驱动走向 Commit Record 驱动的富文本编辑器内核【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate导读本文基于 plate 仓库中的docs/plans/2026-04-21-slate-v2-hard-cut-transaction-runtime-architecture-plan.md架构计划系统讲解 Slate v2 如何以「数据模型优先 事务执行边界 提交记录驱动渲染」的方式重建编辑器运行时核心slate只负责文档树、操作、事务与脏区元数据slate-dom负责 DOM 翻译与浏览器修复slate-react通过语义岛semantic islands、活动走廊active corridor与遮挡壳occlusion shells消费提交元数据slate-browser负责浏览器行为证明。读完本文你将掌握事务边界十步契约、EditorCommit/DirtyRegion/OperationClass的类型设计、六项硬切割的取舍逻辑、Live Reads API 的复杂度约束以及 Phase 0–10 的分阶段落地路径与可复现的驱动门禁命令。1. 计划背景为什么是「硬切割」而不是补丁该计划的起点是一个明确的判断旧的运行时架构需要被替换而不是被修补。支撑这一判断的证据来自两个方向巨大文档huge-doc性能工作证明了方向正确数据模型优先、渲染优化、实时读取这些方向在 5000 块文档的基准中已经拿到收益详见第 12 节执行记录中的基准数据。富文本 CmdZ 回归暴露了实现仍处于过渡态模型真相model truth、DOM 真相DOM truth与 React 修复React repair三者之间还没有一个显式的运行时契约来统一治理。只要这三者各自为政任何一层的变化都可能在不经意间破坏撤销、光标与渲染的一致性。因此这份计划的主题句是构建最终的 Slate v2 运行时架构并用一套不可妥协的原则栈约束后续所有设计。2. 不可妥协的原则栈Non-Negotiable Principle Stack计划用六条原则锁定架构方向任何后续阶段决策都不得违背数据模型优先Data model first核心模型是唯一的文档真相源。操作仍是协作/历史真相Operations remain the collaboration/history truthOperation是序列化、可分发的事实单元。事务是本地执行边界Transactions are the local execution boundary一次本地编辑 一个事务 一个提交记录。面向渲染器的实时读取与脏度是一等公民核心 API渲染层需要的不是「拿到整棵快照自己判断」而是核心直接给出的 live read 与 dirty metadata。React 通过消费运行时 API 来优化而不是反过来塑造核心核心不为 React 变形React 适配核心。浏览器编辑行为用slate-browser证明而不是从合成 React 测试中假设模型证明与 DOM 证明必须双轨并存。3. 六项硬切割决策Hard Cuts计划明确这些切割是架构层面的切割architecture cuts不是表面清理cosmetic cleanup。3.1 切割「子节点计数分块」Child-Count Chunking作为架构子节点计数分块按子节点数量切块渲染在 v2 中只能保留在**遗留对比夹具legacy comparison fixtures与基准基线benchmark baselines**里它不能定义以下任何一项公开 v2 运行时 APIslate-react渲染结构选区语义覆盖层overlay失效策略未来性能声明其替代所有者是语义岛semantic islands、活动走廊active corridor、遮挡壳occlusion shells、显式壳激活explicit shell activation以及5000 块 v2-vs-legacy 证明门禁。3.2 切割decorate作为主覆盖层模型decorate旧的回调式装饰 API只允许作为兼容适配器存活。主模型是类型化覆盖层源typed overlay sourcesdecorations装饰annotations注释widgets挂件review comments评审评论external overlay stores外部覆盖层存储共享投影内核shared projection kernel计划特别强调评审/评论 UI 不是文本装饰Widget UI 也不是文本装饰——它们需要的是同一套投影内核上的不同类型化源而不是被塞进decorate回调里。3.3 切割「快照热读」Snapshot-Hot ReadsEditor.getSnapshot()被判定为观察者observer产物。它被允许用于稳定的外部存储快照devtools测试非紧急 selector当脏元数据表明需要时覆盖层重算它被禁止用于紧急的活动文本渲染DOM 持有的文本修复活动走廊更新已挂载节点查找保持光标的编辑处理核心逻辑是「回答某条活动路径是否变脏」绝不能通过重建整棵快照来实现。3.4 切割「隐式直接 DOM 同步」直接 DOM 同步DOM-owned text绕过 React 直接写 DOM 文本必须成为一种具名能力named capability而不是 DOM 形状的巧合。它必须声明资格eligibility什么条件下允许退出原因opt-out reasons为什么不满足修复所有权repair ownershipundo/redo/delete/paste 由谁修浏览器证明browser proof可访问性等价accessibility equivalence不安全的行必须回退到 React 渲染。3.5 切割「通过选区变更来激活壳」Shell Activation Through Selection Mutation激活activation与选区selection是两个独立概念激活 挂载或提升一个岛island选区变更 改变用户可见的光标/范围状态如果激活有意要选中它必须发布一个真实的选区操作selection operation如果激活只是准备渲染它绝不能改动选区3.6 切割「引擎内部的遗留兼容」遗留兼容只能以**薄适配器thin adapters**的形式存在于公开边界public boundaries。它不能强迫以下任何一项改变形态核心事务形状core transaction shape脏度模型dirtiness model运行时索引runtime indexesslate-react订阅拓扑覆盖层源模型浏览器修复契约4. 目标包架构Target Package Architecture4.1packages/slate数据模型优先的核心拥有JSON 风格文档树operations操作selection选区marks标记normalization规范化refs 与 bookmarks引用与书签事务执行transaction execution运行时身份runtime identity实时 path/runtime-id 索引live path/runtime-id indexes操作分类元数据operation class metadata脏区元数据dirty-region metadata面向观察者的增量不可变快照incremental immutable snapshots for observers不拥有React 渲染DOM 节点浏览器选区剪贴板传输壳 UI平台编辑怪癖4.2packages/slate-dom浏览器真相与修复层拥有DOM point/range 翻译DOM 选区真相浏览器选区修复beforeinput/input 解释剪贴板传输组合输入与 IME 边界逻辑DOM 身份映射浏览器怪癖消费核心实时读取核心运行时 id核心事务提交元数据不拥有React 订阅策略覆盖层源存储产品渲染策略4.3packages/slate-browser浏览器证明基础设施它不是产品 API而是证明脊柱proof spine。它必须证明Playwright 桌面编辑器行为连接的 Chrome 行为剪贴板 text/HTML/Slate-fragment 行为IME 与组合输入选区与选中文本零宽字符与占位符边界历史 undo/redo/delete/backspaceiframe/shadow/scoped 表面在自动化可靠的前提下Appium/agent-browser 移动传输行稳定的ready契约应成为受维护示例与浏览器证明调用点的默认方式。4.4packages/slate-reactReact 渲染与订阅拥有React 订阅selector 失效语义岛活动走廊遮挡壳壳激活 UI覆盖层投影接线DOM 持有纯文本能力React 回退渲染React 拥有可见树时的浏览器修复调度消费核心提交记录core commit records核心脏区core dirty regions核心实时读取core live readsslate-dom的浏览器映射与事件解释不做不从完整快照推断核心脏度不让核心变成 React 形状不把子节点计数分块藏为隐藏回退5. 核心运行时契约Core Runtime Contract5.1 事务边界Transaction Boundary事务是本地执行单元。每个事务按顺序完成十个步骤打开实时可变的事务状态live mutable transaction state应用一个或多个操作operations更新 refs/bookmarks对操作分类classify operations追踪脏路径与运行时 iddirty paths and runtime ids规范化脏区normalize dirty regions更新实时索引live indexes产出一个提交记录commit record更新观察者快照状态只通知订阅者一次notify subscribers once而operations 仍然是序列化的协作/历史事实——事务是本地执行边界操作才是跨端分发的事实。5.2 提交记录Commit Record计划给出了目标类型定义这是整个架构最核心的数据结构type OperationClass text | selection | mark | structural | replace; type DirtyRegion { paths: Path[]; runtimeIds: RuntimeId[]; topLevelRange: [number, number] | null; wholeDocument: boolean; }; type EditorCommit { version: number; previousVersion: number; operations: readonly Operation[]; classes: ReadonlySetOperationClass; dirty: DirtyRegion; selectionChanged: boolean; marksChanged: boolean; textChanged: boolean; structureChanged: boolean; snapshotChanged: boolean; };配套规则禁止通过 JSON diff 整棵文档来推断基本操作类禁止为了回答「活动路径是否变脏」而重建完整快照replace是显式且宽泛的类代表整文档替换结构性操作必须发布足够的父级/顶层脏度供岛islands使用文本操作必须在可能的情况下发布精确的文本路径与运行时 id5.3 实时读取Live Reads核心必须暴露不克隆文档树的实时读取 APIEditor.getLiveNode(editor, path); Editor.getLiveText(editor, path); Editor.getLiveSelection(editor); Editor.getRuntimeId(editor, path); Editor.getPathByRuntimeId(editor, runtimeId); Editor.getChangedOperations(editor, sinceVersion); Editor.getLastCommit(editor);复杂度约束活动路径读取为O(depth)runtime id → path 查找为O(1)或摊还接近 O(1)live read 必须明确文档化为「实时」公开的不可变读取留在快照车道snapshot lane5.4 增量快照/索引维护Incremental Snapshot/Index Maintenance快照仍然有价值但必须从提交元数据维护复用未变更的子树reuse unchanged subtrees增量更新 path/runtime-id 索引仅在 replace/未知结构性场景宽泛失效完整重建只是回退方案不是常见路径6. React 运行时契约React Runtime Contract6.1 Selector 失效Selector InvalidationSelector 消费提交记录commit records并应声明或推断以下依赖之一selection 依赖marks 依赖活动路径依赖runtime id 依赖顶层范围依赖整快照依赖把每个 selector 默认退化为整快照唤醒是一种回归——这正是快照热读要被切割的原因。6.2 语义岛Semantic Islands岛是语义/运行时单元不是子节点计数块。它由以下信号驱动顶层脏范围top-level dirty ranges活动走廊active corridor壳激活状态shell activation state覆盖层源脏度overlay source dirtiness浏览器选区需求browser selection needs不活动的岛可以被遮挡occluded活动的岛必须保持完整编辑语义。6.3 DOM 持有的纯文本能力DOM-Owned Plain Text Capability只有全部条件为真时才允许绕过 React 直接操作 DOM 文本提交类仅为 text-only目标是活动的已挂载文本路径无组合输入composition无自定义renderText无自定义renderLeaf无自定义renderSegment无 decorations/projections/widgets 影响该文本不涉及占位符或零宽字符恰好一个 DOM 字符串节点映射到该文本节点可访问性文本等价必须提供修复事件repair events的行undoredodelete backwarddelete forwardpaste replacementcomposition cancel/commitselection repair作用于活动文本的外部模型操作任何资格检查失败一律回退到 React。7. Overlay 架构Overlay Architecture主覆盖层内核primary overlay kernel职责通过操作映射覆盖层源接受源作用域的脏元数据只投影可见/活动范围支持重叠安全的切片overlap-safe slicing支持 decorations、annotations、widgets、comments 与 review UI向 React 暴露一个投影存储契约one projection store contractdecorate兼容性把遗留回调包装成 decoration 源永远不拥有核心投影架构一旦包/示例迁移证明该适配器大多是死重dead weight可以硬切割8. 浏览器证明架构Browser Proof Architectureslate-browser是证明脊柱。每个面向浏览器的运行时声明都需要以下之一直接 Playwright 证明连接浏览器证明Appium/agent-browser 移动证明带确切原因的显式延迟人工设备阻塞项必须的浏览器证明族beforeinput/input 文本插入keydown 回退插入undo/redo 历史热键原生historyUndo/historyRedodelete/backspaceselect-all跨壳范围选区range selection across shells壳激活键盘与指针剪贴板纯文本剪贴板 HTMLSlate fragment 粘贴/复制IME 组合输入占位符与零宽自定义渲染回退decorations/projections/widgets 回退可访问性属性与焦点顺序iframe/shadow DOM/scoped 表面两条硬性规则纯模型证明不能关闭浏览器编辑车道纯 DOM 证明不能关闭模型车道。对高风险编辑路径模型断言与 DOM 断言必须同时存在。9. 执行阶段Execution PhasesPhase 0 – Phase 10Phase 0冻结硬切割与基线Ownerdocs、基准 harness如需、证明 harness如需Actions把子节点计数分块标记为 legacy-only 架构把decorate标记为兼容适配器把快照热读标记为禁止盘点slate-react中每一个紧急Editor.getSnapshot()使用点盘点每个子节点计数分块依赖盘点每个直接 DOM 同步资格检查与修复事件最早门禁仅文档/状态更新计划内聚焦 grep 盘点bun completion-check保持 pendingPhase 1核心提交记录契约Ownerpackages/slateActions引入显式EditorCommit发布操作类发布脏区发布Editor.getLastCommit(editor)让订阅者收到提交记录而非弱快照变更保持 operations 作为历史/协作真相最早门禁bun test ./packages/slate/test/transaction-contract.ts --bail 1bun test ./packages/slate/test/snapshot-contract.ts --bail 1bun test ./packages/slate/test/surface-contract.ts --bail 1bun run bench:core:observation:compare:localPhase 2实时索引与增量快照Ownerpackages/slateActions增量维护 runtime id→path 索引与 path→runtime id 索引让getPathByRuntimeId在编辑压力下达到 O(1) 或接近从脏区更新快照/索引完整重建只作为宽泛 replace/未知结构场景的回退最早门禁runtime id/path 移位测试快照不可变测试bun run bench:core:huge-document:compare:localbun run bench:core:observation:compare:localPhase 3slate-dom浏览器修复契约Ownerpackages/slate-dompackages/slate-react仅限 React 拥有可见修复的部分Actions形式化浏览器事件类把 DOM 选区真相与模型选区真相分离让原生历史、热键历史、delete、paste、composition 修复显式化确保修复路径同时更新模型与 DOM或用具名阻塞器有意延迟最早门禁bun test ./packages/slate-dom/test/bridge.ts --bail 1bun test ./packages/slate-dom/test/clipboard-boundary.ts --bail 1richtext 键盘 undo 行大文档 undo/redo/delete 行Phase 4slate-browser证明 harness 升级Ownerpackages/slate-browserPlaywright 集成测试Actions把受维护示例测试迁移到openExample(...)ready 契约有用时增加模型DOM 文本断言标准助手增加浏览器 user-agent/平台热键助手为打包 Chromium 可能漏掉的编辑 bug 增加连接 Chrome 证明配方保持移动传输描述符显式最早门禁bun --filter slate-browser testbun run test:slate-browser使用slate-browser/playwright的聚焦示例测试Phase 5slate-react消费提交脏度Ownerpackages/slate-reactActions移除紧急Editor.getSnapshot()读取让 selector 从提交元数据唤醒把活动文本读取路由到 live read API把壳/岛更新路由到脏顶层范围只给非紧急 selector 保留观察者快照车道最早门禁bun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1bun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1bun run bench:react:rerender-breadth:localREACT_HUGE_COMPARE_BLOCKS5000 REACT_HUGE_COMPARE_ITERATIONS5 REACT_HUGE_COMPARE_TYPE_OPS10 bun run bench:react:huge-document:legacy-compare:localPhase 6DOM 持有文本能力正式化Ownerpackages/slate-reactpackages/slate-dom若事件解释成为阻塞项Actions定义能力对象与资格结果包含显式退出原因证明自定义 render/decorations/projections/IME/placeholder/zero-width 回退证明 undo/redo/delete/paste 修复只对安全的纯文本保留直接 DOM 路径最早门禁大文档运行时浏览器行richtext 浏览器 undo 行自定义 render/projection 回退行IME 行5000 块 huge-doc 对比Phase 7Overlay 内核替换decorateOwnerpackages/slate-react示例与文档按需Actions引入类型化 overlay 源 API把 decorations 路由到源 API把 annotations/widgets/comments 路由到同一投影内核把decorate转成适配器迁移现有示例离开回调优先的 overlay 思路最早门禁projections/selection 契约overlay huge-doc 基准高亮文本/评审评论/注释示例Phase 8硬切割子节点计数分块运行时Ownerpackages/slate-react基准 harness示例文档Actions从产品运行时路径移除子节点计数分块只在遗留对比 harness 中保留 legacy 分块让语义岛/走廊成为唯一 v2 huge-doc 故事更新仍在把分块当作当前架构教授的示例最早门禁5000 块 legacy 对比huge-document overlay 基准大文档运行时浏览器测试示例对等台账更新Phase 9壳激活、选区与可访问性Ownerpackages/slate-reactpackages/slate-dom若 DOM 选区桥改变slate-browser证明行Actions让壳激活状态显式化只为用户可见选区发布选区操作证明键盘激活、焦点顺序、ARIA 状态、复制/粘贴、select-all 与读屏器安全标记最早门禁壳键盘激活行select-all 行rich/fragment 粘贴行可访问性聚焦 Playwright 行Phase 10遗留边界与公开 API 清理Ownerpackages/slatepackages/slate-reactdocsActions保留不污染运行时内部的薄适配器硬切割那些强迫遗留架构的旧 API只文档化当前 API删除断言旧内部结构的死兼容测试最早门禁包 typecheck/build包公开表面测试示例对等测试10. 当前下一 Owner 与驱动门禁起始点从 Phase 0 开始然后立即进入 Phase 1。第一个实现 owner 是packages/slate的提交记录与脏区。计划特别警告不要从删除 React 代码开始——那会在核心运行时契约存在之前就移除证据。默认快速门禁bun test ./packages/slate/test/transaction-contract.ts --bail 1 bun test ./packages/slate/test/snapshot-contract.ts --bail 1 bun test ./packages/slate/test/surface-contract.ts --bail 1 bun run bench:core:observation:compare:local核心提交上线后的 React/浏览器门禁bun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1 bun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1 bunx playwright test ./playwright/integration/examples/richtext.test.ts --projectchromium bunx playwright test ./playwright/integration/examples/large-document-runtime.test.ts --projectchromium REACT_HUGE_COMPARE_BLOCKS5000 REACT_HUGE_COMPARE_ITERATIONS5 REACT_HUGE_COMPARE_TYPE_OPS10 bun run bench:react:huge-document:legacy-compare:localslate-browser门禁bun --filter slate-browser test bun run test:slate-browser11. 完成标准与停止规则该车道只有满足以下全部条件才算完成子节点计数分块从 v2 产品运行时架构中消失decorate不再是主 overlay 路径核心发布显式提交记录脏区 API 稳定且有覆盖操作类元数据是一等公民实时 path/runtime-id 索引存在且有覆盖实时文本/节点读取是紧急渲染路径快照/索引维护在脏元数据允许时是增量的slate-react没有任何紧急路径依赖Editor.getSnapshot()DOM 持有文本是带退出证明的显式能力壳激活与选区分离slate-browser拥有浏览器证明脊柱5000 块 huge-doc 对比保持绿色浏览器编辑门禁同时证明模型与 DOM遗留兼容只存在于薄的公开边界剩余风险被显式接受或带理由推迟停止规则不要在 pivot、replan、有已知 owner 的红基准、与当前可运行 owner 无关的 typecheck 阻塞、docs 更新、基准存在性、部分性能收益上停止。只有在完成标准达成、或无法自主推进且已点名确切阻塞器、或用户明确要求暂停时才停止。记忆规则每个切片后都必须向本文件追加actions taken、commands run、artifact paths、evidence、hypothesis、decision、owner classification、changed files、rejected tactics、next action。不依赖聊天历史。12. 执行记录与基准证据Progress 摘要计划的 Progress 部分记录了同一天2026-04-21内连续完成的多轮执行是理解该架构「如何从计划走向实现」的第一手证据Phase 1 第一垂直切片引入EditorCommit现状盘点发现SnapshotChange已存在并携带 classes、dirty paths、touched runtime ids 与 selection/mark/children 标志但没有一等公民的EditorCommit没有Editor.getLastCommit(editor)订阅 API 仍是快照优先的(snapshot, change)getPathByRuntimeId仍是递归实现。动作新增EditorCommit、DirtyRegion、OperationClass类型把SnapshotChange变成更丰富的EditorCommit的别名新增实例/静态Editor.getLastCommit(editor)在无订阅者时也记录最后提交元数据保留快照优先订阅形状做兼容。证据transaction-contract.ts13 个测试通过surface-contract.ts9 个测试通过snapshot-contract.ts190 个测试通过bench:core:observation:compare:local通过但观察车道相对 legacy 仍有界延迟read children 2.91ms、nodes at root 2.03ms、positions first block 2.74ms核心 huge-doc 基准中 typing 慢start 3.57ms、middle 3.37ms、replace/insert fragment 快-5.19ms / -5.59ms。Phase 2 第一垂直切片实时 runtime id/path 索引假设runtime id/path 查找需要实时索引但文本提交不能在紧急路径上重建该索引。被否决的战术每次操作都失效/重建 runtime 索引——它带来硬性性能回归observation read children 均值跳到约 15mshuge-doc typing 跳到约 15ms。修复战术只在改变路径的结构性操作insert_node、remove_node、move_node、merge_node、split_node时失效索引避免在文本提交脏度中使用公开的索引化 runtime-id 查找。证据修复后 observation read children 4.81ms vs legacy 1.92ms、positions first block 4.43ms vs 2.28mshuge-doc start typing 4.20ms vs 0.71ms、middle typing 4.36ms vs 0.54ms、replace full doc 3.50ms vs 9.13ms、insert fragment 3.43ms vs 8.75ms。切割首批slate-reactruntime-id 快照热读动作useSlateNodeRef改用Editor.getPathByRuntimeIdEditableText改用Editor.getRuntimeId/Editor.getPathByRuntimeId/Editor.getLiveTextEditableTextBlocks改用实时读取LargeDocumentIslandShell预览改用实时 path/node 读取。剩余快照读取被限定在 observer 车道projection/widget stores、editable.tsx的显式选区读取。5000 块对比与基准 harness 公平性修复初始 5000 对比出现红色/噪声行middleBlockPromoteThenTypeMs、selectAllMs但聚焦探针显示产品路径廉价且 React commits 为 0。根因基准 harness 混用了过期的 act 语义与晚套件测量污染——select-all 在多个较重车道之后才被测量setup 后未 settle 导致排队 mount/RAF 工作泄漏进被测动作。修复优先React.act并回退react-dom/test-utils.actsetup 与 dispose 后增加 settle 点select-all 移到 ready 之后立即测量扩展active-typing-breakdown.tsx默认渲染器、仅元素渲染器、middle select-then-type、select-all 场景。修复后的 5000 块对比v2 vs chunk-off vs chunk-onready 15.96 / 308.41 / 326.27msselect-all 0.13 / 14.85 / 0.83msstart typing 16.39 / 165.14 / 36.96msstart selecttype 24.26 / 192.93 / 47.80msmiddle typing 18.06 / 206.80 / 35.76msmiddle selecttype 21.53 / 187.65 / 36.75msmiddle promotetype 21.04 / 180.08 / 34.41msreplace full doc 23.45 / 122.52 / 122.43msinsert fragment 28.92 / 120.89 / 111.76ms。结论红色行归类为基准归属v2 车道重新变绿。Phase 6DOM 持有文本同步能力正式化问题直接 DOM 同步仍编码为分散的布尔值与data-slate-dom-sync的缺席退出所有权太隐式。动作新增getDOMTextSyncCapability(...)带具名退出原因empty-text、projection、custom-leaf、custom-segment、custom-text保留data-slate-dom-synctrue启用表面对禁用的默认文本路径与应用自有renderText暴露data-slate-dom-sync-reason新增纯能力契约测试。证据dom-text-sync-contract.ts通过large-doc 包测试 14 个通过相关 Playwright 行 14 个通过5000 对比保持绿色。Phase 7类型化 overlay 源替换decorate第一步新增createSlateDecorationSource(decorate)适配器把遗留decorate(entry)回调转换为类型化投影源保留 decoration range 的 anchor/foci 为投影范围新增投影契约测试。三个示例逐级证明适配器search-highlighting.tsx简单文本节点回调→markdown-preview.tsxtext-node 专用、低风险→code-highlighting.tsx块级/祖先拥有的范围投影进嵌套 code-line 文本节点。关键约束遗留decorate(entry)回调期望实时节点身份Node.get(editor, path) nodenaive 的不可变快照节点适配会破坏此类回调。因此扩展createSlateDecorationSource(decorate, { editor })让适配器遍历实时编辑器节点并包含 root/editor 拥有的 decorations。被否决战术为默认 no-opdecorate总是创建投影适配器——会让 5000 块 typing 严重回归每次文本操作都遍历文档。修复路径只对显式自定义decorateprop启用适配器。最终Editable.decorate内部也变成投影适配器支撑useDecorateContext路由显式自定义decorate到内部createSlateProjectionStore再把投影切片转回DecoratedRange对象供遗留渲染树使用。Phase 8从当前slate-react运行时硬切割子节点计数分块动作移除ReactEditor.getChunkSize从useChildren移除 chunk-tree 逻辑从Editable包表面移除renderChunk/RenderChunkProps从withReact移除 chunk move-node 簿记删除src/chunking/**与components/chunk-tree.tsx删除分块专属包测试更新huge-document示例不再教授/依赖分块huge-document.test.ts断言零[data-slate-chunk]节点。保留huge-document-legacy-compare.mjs中的 legacy 分块基线继续存在它们针对../slate执行不是当前slate-react产品运行时。证据packages/slate-react/src、test、site/examples/ts/huge-document.tsx下已无getChunkSize/renderChunk/ChunkTree/getChunkTreeForNode/data-slate-chunk引用5000 对比中 ready 11.63ms vs chunk-on 288.13ms、start typing 15.15 vs 35.43ms、middle typing 18.68 vs 33.98msreplace/fragment 保持绿色select-all 与首次激活的均值噪声被接受为既有 tradeoff。Phase 9壳激活可访问性语义动作给不活动的大文档壳按钮加aria-expandedfalse包级证明 Enter 与 Space 激活都会有意提升壳并发布选区保留「仅聚焦不激活、不改动模型选区」的既有证明。既有 Phase 9 证明覆盖聚焦不激活不改选区键盘激活有意发布选区壳支撑 select-all 保持模型所有壳支撑 fragment 粘贴在完整与部分壳选区上均工作。Phase 10遗留边界清理收尾修复slate-dom声明别名阻塞移除源中捆绑声明不友好的类型别名SlateBaseEditor、SlateEditor、SlateAncestor随后slate-dom与slate-react的 typecheck 一起通过。剩余兼容表面分类Editor.getSnapshot()保留为 observer/devtools/test/非紧急表面Editable.decorate保留为公开兼容但内部走投影源适配器legacy 分块只存在于huge-document-legacy-compare.mjs生成的../slate对比夹具。最终结论本计划下的硬切割事务运行时架构车道完成select-all/首次激活偶发噪声在既有 tradeoff 下被接受聚焦探针显示 select-all 与提升均无 React commits。剩余工作归属更广的 release/example 对等而非本硬运行时架构车道。13. 在当前仓库中的对应落点该计划面向的运行时架构在仓库中的落点可以从当前源码确认packages/slate/src/interfaces/editor/editor-api.ts 是核心EditorAPI 的聚合入口其中已经可以看到getDirtyPaths这类脏路径 API 的存在——与计划中「核心拥有脏区元数据」的职责划分直接对应。仓库中同一目录还包含editor-transforms.ts、editor-type.ts、legacy-editor.ts等文件与计划「legacy 兼容只存在于薄公开边界」的收尾结论吻合。packages/slate/package.json 定义了platejs/slate包当前版本 53.3.10依赖slate0.126.2与slate-dom0.126.0其scripts提供build、lint、test、typecheck等命令可对应计划中的包级驱动门禁。计划 Phase 1/2 反复提到的核心契约测试transaction-contract、snapshot-contract、surface-contract与 packages/slate/src/create-editor.ts、packages/slate/src/index.ts 的模块边界互相印证编辑器创建、公开导出与提交/脏度契约同属packages/slate一个包。需要注意的是计划正文与执行记录中引用的部分路径如.tmp/slate-v2/packages/...、packages/slate-react属于执行时的工作区布局与目标架构描述以当前仓库为准时packages/slate是可直接查看的核心落点slate-dom依赖以 package.json 声明的版本形式存在。14. 总结这套架构的价值与阅读路径Slate v2 硬切割事务运行时架构的核心贡献可以概括为一句话把「一次编辑」从「改模型 猜渲染」重构为「一个事务 → 一个提交记录 → 精确的脏区/操作类/运行时 id → 渲染层按需消费」。它对富文本编辑器工程的启示在于真相分层模型、DOM、React 三层各有各的真相但只有模型是根DOM 与 React 的真相必须通过显式契约commit record、dirty region、capability、repair event派生。性能来自元数据而非快照大文档场景下快照重建是 O(文档) 的成本而脏区 实时索引把问题缩小到 O(受影响路径)。删除旧架构要分阶段且留证据Phase 8 的硬切割发生在 Phase 1–7 的新契约全部证明绿色之后且 legacy 基线被刻意保留在对比 harness 里——先建立新真相再移除旧真相。对希望深入源码的读者建议按以下顺序阅读当前仓库先读 packages/slate/src/interfaces/editor/editor-api.ts 了解核心 API 表面再看 packages/slate/src/create-editor.ts 与 packages/slate/src/index.ts 理解编辑器装配与导出边界最后对照本文第 5、6、9 节所描述的事务、提交、岛与分阶段门禁回溯验证计划与实现的对应关系。【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考