Plate Slate v2 硬切割:slate-markdown 与 slate-table 包的去留决策与能力归属重构
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
本文围绕 Plate 仓库中 Slate v2 重写的一条关键决策记录展开:将slate-markdown与slate-table两个原始 Slate 包从 Slate 侧彻底移除,把 Markdown 语法策略与表格功能策略重新划归到 Plate 或应用/示例代码层。读完本文,你可以理解这次"硬切割"(Hard Cut)背后的架构动机、四项具体决策、进度与验证命令,以及当前仓库中 Markdown/表格能力实际落位的包结构,从而掌握 Slate(无主见的底层内核)与 Plate(有主见的功能层)之间的边界划分方法。
背景:为什么要对 Markdown 与表格包做硬切割
Slate v2 是 Plate 团队对 Slate 内核的一次重写(仓库docs/plans/目录下存在大量以slate-v2命名的规划文档,如 Slate v2 相关规划)。在重写过程中,团队面临一个典型的分层问题:Markdown 的解析/序列化规则、表格的行为策略(GFM 表格、单元格选择 UX)本质上属于"产品化、有主见"的能力,而 Slate 的定位是一个"无主见"(unopinionated)的富文本内核。
决策文档 Slate v2 Markdown/Table Package Hard Cut 给出的目标非常明确:
Remove raw Slate
slate-markdownandslate-tablepackage surfaces. Markdown syntax policy and table feature policy belong in Plate or app/example code, not in unopinionated Slate.
即:从原始 Slate 中移除slate-markdown和slate-table的包表面(package surface),因为 Markdown 语法策略和表格功能策略应属于 Plate 或应用/示例代码,而不属于无主见的 Slate。
从源码结构看,这类"能力下沉/上移"的边界判断在内核重写中是反复出现的主题——仓库docs/plans/下围绕 Slate v2 的包命名规范化、roadmap 收束、包表面回收(如slate-v2-roadmap-package-name-normalization、slate-v2-instance-surface-recovery等系列规划)都在做同一件事:把内核的 API 表面收敛到纯基础设施。
四项核心决策
决策文档的Decisions一节列出了四条边界规则,它们共同定义了切割后各方的职责:
- 原始 Slate 只保留基座 API(substrate APIs):schema、transforms、selections、normalization、clipboard/input hooks,以及 layout 原语。这些是"数据模型 + DOM 桥接 + 操作"层面的通用能力,与具体产品特性无关。
- Plate 拥有 Markdown 能力包:parse / serialize / input-rule 包全部归属 Plate。
- Plate 拥有表格能力:table maps、commands、cell-selection UX 与 GFM 表格行为归 Plate 所有。
- Slate 示例可以保留本地 fixture:示例代码中允许保留本地测试数据来证明通用基座行为,但不依赖被移除的包。
slate-layout必须消费应用侧提供的通用几何信息:对"表格类内容"的布局计算,slate-layout不得再依赖原始 Slate 的 table 包,而是消费由应用提供的通用几何数据。
第 4、5 条尤其值得注意:它们不是简单的"删包",而是回答了"删完之后谁消费这些几何/布局数据"的问题——布局层退化为对应用侧几何信息的消费方,这是典型的"内核去业务化"手法:内核不假设存在表格,布局层通过通用接口拿到表格所需的行列几何。
当前仓库状态印证:能力落位在哪里
本决策是在 Slate v2 重写分支(验证命令运行于.tmp/slate-v2临时检出,见下文验证一节)中执行的。当前主仓库的包结构正好呈现了切割后的稳态结果:
内核侧:packages/slate
@platejs/slate 的包入口 packages/slate/src/index.ts 的导出结构与文档所述"基座 API"完全对应:
export * from './create-editor'; export * from './slate-dom'; export * from './types'; export * from './interfaces/index'; export * from './slate-history/index'; export * from './utils/index';从源码结构看,interfaces(类型契约)、slate-dom(DOM 桥接)、slate-history(撤销/重做)、utils(路径、选区等工具)构成了决策中提到的 schema/transforms/selections/normalization 等基座能力的载体,其中不含任何 Markdown 或表格专属模块。其 package.json 也印证了"薄内核"定位:运行时依赖仅为slate(0.126.2)、slate-dom(0.126.0)、lodash等,版本号为 53.3.10。
功能侧:packages/markdown
@platejs/markdown("Markdown serializer plugin for Plate",v53.3.12)正是决策中"Plate owns Markdown parse/serialize/input-rule packages"的落地位置。其依赖清单直接反映了 Plate 侧 Markdown 能力的技术栈选型:
remark-parse/remark-stringify/unified:CommonMark 解析与序列化管线;marked(^15.0.12):轻量解析路径;remark-mdx/mdast-util-mdx/mdast-util-math:MDX 与数学扩展;unist-util-visit:AST 遍历。
更关键的是测试文件本身就证明"GFM 表格行为在 Plate 侧被验证":packages/markdown/src/lib/table.spec.ts 与同目录下的gfmSurface.spec.ts、commonmarkSurface.spec.ts、taskList.spec.ts等按表面(surface)组织的规格测试,覆盖了 GFM 表格在 Markdown 解析/序列化链路中的行为。也就是说,表格的"语法策略"(如何解析/产出 GFM 表格 Markdown)确实留在了 Plate 的 Markdown 包内,与决策一致。
功能侧:packages/table
@platejs/table("Table plugin for Plate",v53.0.9)承载决策中"Plate owns table maps, commands, cell-selection UX"的运行时能力:它同时暴露核心入口.与 React 入口./react,并依赖@platejs/resizable提供表格相关的交互增强。表格的 maps(数据结构映射)、命令与单元格选择 UX 由此独立于 Slate 内核存在。
切割结果确认:slate-markdown/slate-table不在仓库中
当前仓库packages/目录下的包清单中不存在slate-markdown与slate-table,与决策文档 Progress 中"Deletepackages/slate-markdown/ Deletepackages/slate-table"的勾选结果一致。需要注意的适用前提是:这两次删除与验证都发生在 Slate v2 重写的工作线(.tmp/slate-v2检出)上,主仓库(plate-2工作区)自始以 Plate 包(@platejs/markdown、@platejs/table)作为这些能力的载体。
进度清单(Progress)
决策文档将执行过程记录为逐项勾选的清单,全部完成:
- Confirm package surfaces exist(确认两个包表面确实存在)
- Delete
packages/slate-markdown - Delete
packages/slate-table - Remove TypeScript/workspace references(清理 TS 与 workspace 引用)
- Rewrite docs and plan references(重写相关文档与规划引用)
- Run focused verification(执行聚焦验证)
其中"Remove TypeScript/workspace references"一步在多包工作区中尤为关键:删除包目录本身只完成一半,还必须同步清理tsconfig的 references 与 workspace 成员声明,否则类型检查与构建会残留对已删包的引用。
验证命令与结果(Verification)
决策文档记录了聚焦验证的命令与环境,这里完整继承并补充执行环境说明:
| 命令 | 执行环境 | 结果 |
|---|---|---|
bun typecheck:packages | .tmp/slate-v2(Slate v2 重写检出) | 通过 |
bun typecheck:root | .tmp/slate-v2 | 通过 |
bun lint:fix | .tmp/slate-v2 | 通过,无修改 |
bun test:bun | .tmp/slate-v2 | 通过:1157 pass / 95 skip |
pnpm lint:fix | plate-2(主工作区) | 通过,无修改 |
验证策略体现了一个跨仓库切分项目的典型做法:删除动作发生在 Slate v2 检出,因此类型检查、lint 与全量 Bun 测试(1157 通过、95 跳过)都在.tmp/slate-v2中执行;同时用pnpm lint:fix在主工作区plate-2做一次无副作用的 lint 确认,确保主仓库引用未受牵连。lint:fix报告"no fixes applied"是删除类变更的强信号——说明没有遗留的未使用导入或格式残骸需要自动修复。
小结:内核去业务化的三条可复用经验
结合本文档与当前仓库的包结构,这次硬切割给出了三条对内核/功能分层项目都有参考价值的经验:
- 策略与基座分离:语法策略(Markdown 规则、GFM 表格行为)与产品 UX(单元格选择)上移到功能层(packages/markdown、packages/table),内核(packages/slate)只保留 schema、transforms、selections、normalization 等通用基座。
- 删除要删透:包目录、TS/workspace 引用、文档引用三类位置全部清理,并以全仓 typecheck + lint + 测试套件作为验收门槛。
- 为"删掉之后"指定消费者:
slate-layout通过消费应用侧提供的通用几何信息替代对 table 包的依赖,避免布局原语重新耦合回业务数据结构。
相关深入材料可参考 决策原文、内核包 packages/slate/README.md 以及仓库docs/plans/下其他 Slate v2 系列规划文档。
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考