Editor 模型与 api/tf 分层设计
1. 先说结论
Plate 在近几次核心演进里,把编辑器方法系统性分离为:
editor.api:查询/判定/只读能力editor.tf(或editor.transforms):状态变更能力
这不是“命名美化”,而是为了可维护和可扩展的接口治理。
2. 证据:迁移文档对动机写得很直白
docs/migration/v48.mdx 在 @udecode/plate-core@42.0.0 明确解释:
- 顶层挂太多方法会污染 editor 接口
- Slate 本身 transform 分散在多处,认知成本高
- 重组到
api/tf后,便于未来 transform middleware、override 机制
文档原话核心意思:这是 DX 和未来扩展能力的结构性优化。
3. 源码落地
在 withSlate 中,editor 初始化时会注入:
editor.getApieditor.getTransformseditor.getPlugineditor.getOption/setOption/setOptions
路径:packages/core/src/lib/editor/withSlate.ts
PlateEditor 类型也同步体现这个结构:
packages/core/src/react/editor/PlateEditor.ts
4. 这个分层如何提升插件开发体验
4.1 override 更清晰
当你写:
overrideEditor(({ tf: { deleteForward }, api: { isInline } }) => ...)
你能一眼分辨“读”与“写”的边界,避免把查询和变更混在一个对象上。
4.2 类型系统更稳定
插件通过 PluginConfig<key, options, api, transforms, selectors> 分别声明能力域,类型推导更精准。
4.3 中间件化空间更大
Transform 可单独扩展、拦截、包裹,这是后续优化链路(例如规则管线、AI 变更批处理)的基础。
5. 典型延伸追问:为什么不直接沿用 Slate 顶层方法?
推荐回答:
- Slate 顶层方式历史兼容强,但规模化插件系统里可读性下降
- Plate 通过
api/tf显式表达职责,降低大型项目认知负担 - 保留向后兼容的同时,逐步把“新能力”放到分层接口,属于演进式重构
6. 与插件规则系统的关系
rules(break/delete/merge/selection)最终很多会落到 transforms 执行。tf 分层让这些策略可替换、可组合,而不是散落在编辑器顶层魔法方法里。
小结
api/tf 分层是 Plate 的核心设计支点之一:它把“编辑器能力”从“历史对象结构”升级为“可长期演进的模块化接口”。