ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Slate v2 大规模文档历史基准 lane 的硬切决策:如何识别并删除结构性无效的 compare 行

Slate v2 大规模文档历史基准 lane 的硬切决策:如何识别并删除结构性无效的 compare 行 Slate v2 大规模文档历史基准 lane 的硬切决策如何识别并删除结构性无效的 compare 行【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate导读本文以 Plate 仓库中 docs/plans/2026-04-15-slate-v2-huge-document-history-lane-cut.md 为核心完整还原 Slate v2 性能工程中一次典型的基准 lane 硬切hard cut案例浏览器端 huge-document 历史对比 lane 被证明在构造上就无效无法通过补 UI、修 harness 挽救最终被删除并让唯一诚实的 history 对比 owner 接管真相。读完本文你将掌握对比类基准 lane 的合法性判定方法、修复 vs 删除的决策框架以及一次干净硬切涉及的三层改动面package.json 命令面、死代码脚本、线上控制文档与验证流程。一、背景replacement lane 与历史对比债务从何而来在 Slate v2 的基准体系中存在两类 lanereplacement lane替换对比 lane如bench:replacement:huge-document:local、bench:replacement:huge-document:overlays:local用于度量 Slate v2当前实现在 huge-document 场景下的用户流表现并与 legacy Slate 的对应示例对比支撑替换replacement主张。compare lane纯对比 lane如bench:history:compare:local直接在无头headless环境下把当前实现与 legacy 的 undo/redo 成本做同赛道测量。本次事件的主角是bench:replacement:huge-document:history:local——一条同时挂着 replacement 与 history 双重身份的浏览器 lane。它一度被当作普通基准债务跟踪即假设问题只是 harness 管线没接好、补个按钮或修个选择器就能恢复。原计划文档的 Goal 写得非常明确Resolve the bogus browser huge-document history compare debt by deciding whether the lane is fixable or should be deleted.即这条 lane 到底是可修复还是应该被删除必须先做出判定而不是任由一条假行长期挂在记分板上。二、复现失败的第一现场是一条找不到的 DOM 选择器文档中记录的失败原语是expect(locator(#huge-document-undo)).toBeVisible()pnpm bench:replacement:huge-document:history:local在浏览器端启动后试图定位 legacy huge-document 示例中的撤销按钮#huge-document-undo随即失败。这条报错本身看起来像普通 harness 问题——locator 找不到元素第一时间会想到是不是选择器写错了、页面没加载完、或者按钮 id 变了。但原计划文档在 Findings 中立刻给出了两个更深层的观察legacy 侧没有 undo/redo 控件。legacy 的site/examples/ts/huge-document.tsx根本没有暴露撤销/重做按钮所以即使把 locator 改对也没有可点击的目标更糟legacy huge-document 甚至不是用withHistory(...)创建的。也就是说 legacy 的 huge-document 示例根本不是一个带操作历史的编辑器。第二点是决定性证据这不是缺按钮问题而是被对比的 legacy surface 本身没有实现该行为。UI 层没有控件只是症状模型层没有历史能力才是根因。三、根因compare 行必须先证明 legacy surface 存在仓库中另一份配套工作流文档 docs/solutions/workflow-issues/2026-04-15-benchmark-compare-rows-must-prove-the-legacy-surface-exists.md 对根因做了系统归纳一条 benchmark compare 行被当成普通债务跟踪但 legacy surface 实际上并不支持被测行为lane 因缺失控件而失败是因为被当作对比目标的 legacy surface根本不是 history 编辑器根因被归为missing_workflow_step缺失工作流步骤即在把 compare 行挂账为债务之前没有先验证 legacy 目标是否真实存在。这里可以提炼出一条可复用的判定规则对比类基准行的合法性取决于 legacy 侧是否真实暴露了被测行为。判定需要同时检查两个层面检查层面检查内容本次案例的结论UI 表面legacy 示例是否暴露被测交互的控件按钮、输入框等无 undo/redo 控件模型形态legacy 编辑器是否以正确的插件/包装创建如withHistory仅withReact(...)未用withHistory(...)缺少控件可能是症状而模型形态不对才是根因。只修 UI 层面等于在错误层次上解决问题。四、决策为什么选择硬切而不是挂账为后续债务原计划文档明确给出了决策理由the kept honest owner already exists:pnpm bench:history:compare:local也就是说在删除这条假行之前真正诚实的 history 对比 owner 已经存在——无头headless赛道bench:history:compare:local一直负责测量withHistory(createEditor())的 undo/redo 成本。因此删除浏览器假行不会留下history 对比无主的空白。同时keeping the browser huge-document history lane as follow-up debt would keep a structurally invalid compare row alive把假行保留为后续债务等于让一条结构性无效的 compare 行继续存活在记分板上。它的存在会带来两个危害污染性能叙事pollutes the perf story外人看到该行就会以为huge-document 的 history 对比尚未完成而事实是它永远无法完成——legacy 侧不存在可对比的行为诱导更多错误工作invites more bad benchmark work后人可能为了救活这条 lane 而发明一个新的 legacy surface比如给 legacy 示例补一个假的 history 包装只为保住一个基准名字。所以正确决策不是再给它一次机会而是硬切hard cut如果 legacy surface 从未暴露该行为就没有什么可对比的删除是唯一诚实的选项。配套方案文档的原话是If the legacy target is not the same feature class at all, cut the row. Do not invent a new legacy surface just to save a benchmark name.五、执行一次干净硬切的三层改动面原计划文档把本次 cut 归纳为三个动作移除命令面从package.json中删除bench:replacement:huge-document:history:local脚本删除死代码删除 lane 脚本scripts/benchmarks/browser/replacement/huge-document-history.mjs重写线上控制文档重写 live perf 判定文档使pnpm bench:history:compare:local成为 history 对比真相的唯一 owner。这三点缺一不可它们分别对应命令不可再跑代码不可再执行文档不可再误导三个层面。删掉脚本却留着 package.json 命令lane 依然可被触发删了命令却留着文档读者依然会把假行当作待办。在当前仓库中可以找到这次 cut 留下的幸存者证据在 benchmarks/targets/slate-v2.json 中history-comparetarget 被定义为{ id: history-compare, family: history, kind: compare, owner: slate-v2, question: Does Slate v2 match legacy Slate for undo/redo typing and fragment history?, command: HISTORY_BENCH_LEGACY_REPO../../../slate bun run bench:history:compare:local, metric: history_compare_worst_p95_ratio, direction: lower, artifacts: [ { path: .tmp/slate-v2/tmp/slate-history-compare-benchmark.json, required: true } ] }注意这里的运行环境cwd是.tmp/slate-v2并通过HISTORY_BENCH_LEGACY_REPO../../../slate环境变量指向 legacy Slate 仓库产物落到tmp/slate-history-compare-benchmark.json。这与配套文档 docs/slate-v2-draft/true-slate-rc-proof-ledger.md 中对bench:history:compare:local的定位一致——它度量的是带withHistory(createEditor())的 undo/redo 成本且直接与 legacy Slate 在 large-document 默认编辑器赛道上对比。同样记录了该 target 的还有 benchmarks/targets/history/slate-v2-latest.json。六、验证幸存 owner 的同一轮重跑数据硬切之后原计划文档记录了 fresh same-turn同一轮次内重跑的幸存 owner 结果场景耗时typing undo键入撤销20.27mstyping redo键入重做17.7msfragment undo片段撤销31.77msfragment redo片段重做29.11ms同一组数字也出现在 docs/slate-v2-draft/true-slate-rc-proof-ledger.md 的 perf gate 记录中并附带说明5,000-block 的 history 对比与 legacy 相比仍有差距但处于 RC 可接受的区间内该 lane 在假行被切掉后成为 history 对比真相的唯一诚实 owner。进度部分还记录了完整的验证命令链pnpm lint:fix——确保删除脚本后代码风格与静态检查仍然通过pnpm bench:history:compare:local——确保幸存 owner 可独立运行并产出数据。这两步共同构成硬切后的回归验证删除不能破坏既有工具链同时被保留的 owner 必须能立刻顶上空位。七、机制佐证withHistory 在源码中如何工作为什么legacy 没用 withHistory 创建是致命缺陷可以从当前仓库的源码实现理解 history 能力从何而来。packages/slate/src/slate-history/with-history.ts 中的withHistory插件实现如下export const withHistory T extends Editor(editor: T) { const e editor as Editor LegacyEditorMethods; const { apply } e; e.history { redos: [], undos: [] }; e.redo () { const { history } e; const { redos } history; if (redos.length 0) { const batch redos.at(-1)!; e.tf.withoutSaving(() { e.tf.withoutNormalizing(() { for (const op of batch.operations) { e.apply(op); } }); }); // ...选择恢复与堆栈维护 } }; e.undo () { const { history } e; const { undos } history; if (undos.length 0) { // 逆操作 选择恢复 堆栈维护 } }; };从源码结构可以清晰看到undo/redo这两个方法、e.history { redos: [], undos: [] }这个数据结构全部由withHistory注入到编辑器实例上。一个没有经过withHistory包装的编辑器从根上就没有撤销/重做堆栈任何 UI 按钮都无从触发历史行为。这印证了原计划文档的结论——legacy huge-document 示例无法承担 history 对比职责不是 harness 的锅而是编辑器构造方式决定了它没有这个能力。仓库中对withHistory的配套测试还散落在 packages/slate/src/slate-history/with-history.spec.tsx 与 packages/slate/src/slate-history/history.spec.tsx以及类型测试 packages/slate/type-tests/history.ts 中可以作为进一步阅读的入口。八、当前仓库中的 huge-document 现状cut 之后的画面硬切掉的只是 history 这一条 lanehuge-document 的整体基准体系并未受损。当前仓库仍保留着功能完整的 huge-document 示例 apps/www/src/registry/examples/huge-document-demo.tsx从其中可以读出巨大的配置面默认块数DEFAULT_HUGE_DOCUMENT_BLOCKS 10_000可选档位覆盖2 / 1_000 / 2_500 / 5_000 / 7_500 / 10_000 / 15_000 / 20_000 / 25_000 / 30_000 / 40_000 / 50_000 / 100_000 / 200_000共 14 档分块chunking开关与chunkSize档位3 / 10 / 100 / 1000contentVisibilityMode支持none / element / chunk三种模式mountedEngines可设为both / plate / slate支持双引擎同屏对比。同时 docs/slate-v2-draft/replacement-gates-scoreboard.md 中记录着仍然存活的 replacement huge-document 门禁bench:replacement:huge-document:local稳定负载为 1000 blocks、5 次迭代以及 ready / type / select-all / paste 四类用户流与 legacy 的对比数据。换句话说被切掉的只是history 对比这一个本不该存在的行其余 huge-document 基准照常运转这正是切假行、保真行的预期效果。九、方法论沉淀如何在你的基准体系里复现这套决策将本次案例沉淀为可复用的四步流程复现并分级先确认失败是 harness 管线问题还是 surface 能力问题。判断信号是——去掉选择器/等待/重试问题后legacy 目标上是否真的存在可交互的行为载体按钮、输入、快捷键。检查两个层面UI 表面控件是否存在 模型形态编辑器是否以正确插件创建。两者缺一即判定为legacy surface 不支持该行为。寻找诚实 owner删除之前确认同一性能主张已有或可建立其他合法度量通道。本案中bench:history:compare:local就是现成的替代因此 cut 无风险如果没有替代应优先建立替代而不是保留假行。三层同步硬切并回归package.json 命令面 死 lane 脚本 线上控制文档三者一起处理随后跑lint:fix与幸存 owner 的完整重跑把新数据写回文档作为唯一的真相来源。十、结论bench:replacement:huge-document:history:local的硬切本质上是一次基准数据卫生操作它证明了一条对比行只有在被测行为真实存在于 legacy surface时才具有合法性。以#huge-document-undo选择器为线索一路追溯到 legacy 示例缺少 undo/redo 控件、再追溯到编辑器未经过withHistory包装最终判定该行在构造上无效——既不修 UI也不挂账而是干净删除并让无头赛道bench:history:compare:local成为 history 对比真相的唯一 owner。这一案例为基准体系治理提供了两条直接可用的经验挂账之前先证明 legacy surface 存在每个性能主张只保留一个诚实 owner。【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表