Plate 架构宪法 north-star 七条法则解读:可复用富文本编辑器 API 设计的权责、分层与性能边界
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
本篇技术指南围绕 Plate 仓库内 north-star 技能的宪法层文档 laws.md 展开,系统解读其中定义的七条架构法则(所有权、分层、显式性、运行时边界、性能、规范语义、公共契约),并结合仓库中packages/core的插件原语、packages/*各特性包的组织方式以及 plate-plugin-creator 的执行规则,说明这套法则如何落地到真实的插件开发与公共 API 设计实践中。读完本文,你将掌握判断"一段可复用代码该由谁拥有、属于哪一层、是否需要性能约束"的完整决策框架,以及 north-star 与执行型技能之间的分工与路由规则。
一、laws.md 在 Plate 架构体系中的位置
Plate 是一个以插件化为核心架构的富文本编辑器框架(源码分布于 packages/core 与 40 余个特性包中)。为了约束如此庞大多包生态的公共 API 演进,仓库维护了一套名为north-star的"宪法层"技能体系,其定义同时存在于 .agents/skills/north-star/SKILL.md 与 .agents/rules/north-star.mdc 两处。north-star 的定位是"可复用架构与公共 API 设计的最高决策层"(upstream decision layer),它不负责具体插件的编写,而是负责:
- 可复用架构教义(reusable architecture doctrine)
- 公共 API 形态决策(public API shape decisions)
- 运行时/服务边界模式(runtime/service-boundary patterns)
- 分层与所有权法则(layering / ownership law)
- 性能与可扩展性法则(performance/scalability law)
- 反模式目录(anti-pattern catalog)
north-star 的文档体系被明确划分为两层:
| 层级 | 文件 | 职责 |
|---|---|---|
| 宪法层 | laws.md | 七条最高法则,本文核心 |
| 宪法层 | decision-ladder.md | 按顺序执行的 6 步决策阶梯 |
| 宪法层 | performance-selection-rules.md | 性能/可扩展性取舍协议 |
| 宪法层 | update-policy.md | 宪法自身的维护与再确认契约 |
| 模式层 | pattern-catalog.md | 各领域推荐的模式目录 |
| 模式层 | anti-patterns.md | 十一项明令禁止的反模式 |
laws.md 处于该体系的最高层:其余文档(决策阶梯、性能选择、模式目录、反模式目录)都是对七条法则的操作化展开。因此理解 laws.md 是理解整个 north-star 体系乃至 Plate 插件架构的入口。
二、法则 1:所有权法则(Ownership Law)——公共 API 必须有明确的拥有者
Public APIs need explicit owners.(公共 API 需要明确的拥有者。)
法则原文将拥有者划分为三个层次:
- Core(核心)拥有共享原语与编排(shared primitives and orchestration)
- Feature packages(特性包)拥有特性语义(feature semantics)
- Local kits(本地套件)拥有本地便捷糖(local sugar and convenience)
法则强调:"不要因为短期代码路径便利就模糊这些边界"(Do not blur these because the short-term code path is convenient)。这是一条职责隔离法则:同样一段被多包复用的逻辑,到底抽到 core、留在特性包、还是仅作为应用本地便利,必须按语义归属而非文件相似度来决定。
从仓库源码结构看,这条法则直接塑造了包的组织形态:
- 共享原语集中在 packages/core/src/lib/plugin(如 createSlatePlugin.ts)——core 负责插件注册、编排与共享状态访问等平台级职责;
- 特性语义留在各自包内,例如
packages/comment、packages/code-block、packages/link、packages/list等,每个特性包独立拥有其节点类型、转换与规则; - plate-plugin-creator 中的 Repo Surfaces 表给出了更细的落地约定:
packages/*/src/lib放语义基础插件与转换,packages/*/src/react放 React/Plate 包装层,packages/core/type-tests作为插件契约的真相源。
与之对应的反模式出现在 anti-patterns.md:"Core APIs owning feature semantics"(核心 API 拥有特性语义)被明令禁止。换句话说,core 永远不应把某个具体业务特性(如链接校验、方程插入、代码块插入)的实现塞进自己的公共 API。
三、法则 2:分层法则(Layering Law)——每个可复用表面必须自报所属层
Every reusable surface must say what layer it belongs to.(每个可复用表面都必须声明自己属于哪一层。)
法则规定了五个可选的层:
- constitutional doctrine(宪法教义)——最高层的架构原则,即 north-star 自身;
- shared runtime primitive(共享运行时原语)——与业务无关的平台级能力,归 core 所有;
- feature semantic contract(特性语义契约)——某个业务特性对外承诺的行为契约,归对应特性包所有;
- execution helper(执行辅助)——服务于实现细节的辅助代码,通常放入
internal/; - local convenience(本地便捷)——仅服务某个应用/套件的便捷封装。
法则的裁决标准非常直接:"If you cannot name the layer, the API is not ready.(如果你说不出它属于哪一层,这个 API 就还没准备好。)"换言之,分层命名不是文档收尾工作,而是 API 设计的前置门槛。
这条法则与 decision-ladder.md 的第 4 步直接联动:决策阶梯要求在设计任何可复用表面时"Pick one"(从中选一个层),如果无法选定或模棱两可,就必须向上路由到 north-star 裁决。
在实现层面,分层还体现为可见性的物理隔离:plate-plugin-creator 规定"任何不属于预期公共契约的辅助函数、matcher、回退分支都应放在internal/目录下",并默认优先使用internal/,除非用户确实需要导入该文件。这就是"execution helper"层在文件系统上的落地。
四、法则 3:显式性法则(Explicitness Law)——最好的 DX 不是隐藏的 DX
The best DX is not hidden DX.(最好的开发者体验不是被隐藏起来的体验。)
法则提出了四条可检验的显式性要求:
- activation should be explicit(激活应当是显式的)——功能不应因安装包而悄悄生效;
- naming should be readable(命名应当可读);
- ownership should be visible(所有权应当可见)——调用者能看出这段能力由谁负责;
- the common path should be discoverable from the call site(常见路径应当从调用点即可发现)——最常用的用法不能埋在文档或源码深处。
这条法则在 pattern-catalog.md 的 Config Patterns 一节有更细的展开:偏好"显式、可复制的配置"(explicit, copyable config),在拥有者作用域内使用简短本地名称,并通过拥有者表面激活,而不是通过隐藏宿主激活;同时明确避免三类反模式:标点符号式键名(punctuation keys)、重复拥有者的冗长名称、以及"仅凭安装就触发的隐藏默认值"(hidden defaults triggered by install alone)。对应的反模式条目是 anti-patterns.md 中的 "Hidden defaults that activate behavior just because a package is installed"。
可以这样理解:显式性法则本质上是把"魔法"限定在可预期、可审查的范围内——共享的KEYS契约(见 packages/utils/src/lib/plate-keys.ts)是显式命名的一个实例,它让跨包引用不再依赖随机字符串字面量,从而让所有权与引用关系在调用点即可见。
五、法则 4:运行时边界法则(Runtime Boundary Law)——运行时关注点必须是显式接缝
Runtime/service concerns should be explicit seams, not side effects leaking out of plugin code.(运行时/服务关注点应当是显式接缝,而不是从插件代码中泄漏出去的副作用。)
法则明确列举了五类必须显式建模的运行时关注点:
- caches(缓存)
- projections(投影/派生视图)
- diagnostics(诊断)
- protocol boundaries(协议边界)
- layout/measurement services(布局/测量服务)
其核心主张是:这些关注点不能以隐式副作用的形式藏在插件代码里,而应被设计成清晰的边界(seam),让运行时与服务能力成为可替换、可测试、可观测的显式组件。
pattern-catalog.md 的 Runtime / Service Patterns 一节给出了正向模式:
- 显式服务边界(explicit service boundaries);
- 用投影代替临时重算(projections instead of ad hoc recomputation)——避免在热路径上从零重算大型派生状态;
- 协议化诊断/分析器/服务(protocolized diagnostics/analyzers/services);
- 把布局与测量作为独立的架构关注点(layout and measurement as separate architectural concerns)。
对应的反模式是:"将服务直接缠进渲染/插件胶水"(tangling services directly into rendering/plugin glue),以及在热路径上反复从零重算大型派生状态。这条法则对富文本编辑器尤为重要——光标移动、输入、选区变化都是极高频率事件,任何缓存、投影、测量逻辑若不显式接缝化,很容易成为性能黑洞或难以定位的隐式状态来源。
六、法则 5:性能法则(Performance Law)——性能是设计约束,不是事后的清理任务
Performance and scalability are design constraints, not later cleanup tasks.(性能与可扩展性是设计约束,而不是事后的清理任务。)
法则原文指出,如果一个"看起来更好看"的 API 在热路径上引入了额外成本,那么这些成本本身就是 API 决策的一部分,必须在设计阶段评估。法则列出的五项成本维度:
- hot-path work(热路径额外工作)
- dispatch cost(分发成本)
- allocation churn(分配抖动)
- merge ambiguity(合并歧义)
- invalidation complexity(失效复杂性)
performance-selection-rules.md 将这条法则操作化为优先级排序与决策序列:
优先级:
- 性能/可扩展性优先于美观的 API 形态(performance/scalability beats aesthetic API elegance);
- 显式所有权/分层优先于便利(explicit ownership/layering beats convenience);
- 规范语义保持包属(canonical semantics stay package-owned);
- 便捷糖保持本地,除非真正规范化(sugar stays local unless it becomes genuinely canonical)。
决策序列(5 步):
- 该表面是否处于热路径或可扩展性边界?
- 更漂亮的形态是否引入了 eager work、dispatch cost、allocation churn、merge ambiguity 或 invalidation complexity?
- 是否能用 lazy/contextual derivation、owner-scoped defaults、更窄的高层 builder 保留同样的 DX?
- 若可以,保留低成本的核心形态,把人体工学上移;
- 若不可以,仍然保留低成本/可扩展形态,并显式记录 DX 代价。
值得强调的是第 5 步的立场:即使无法两全,也要坚持低成本形态并把 DX 权衡显式写进文档,而不是反过来。对应反模式是 anti-patterns.md 中的 ""Pretty" APIs that quietly add hot-path runtime work"(悄悄增加热路径运行时工作的"漂亮"API)。Plate 作为编辑器框架,其插件 API 会在每次按键、每次渲染中反复执行,因此这条法则直接决定了resolve()/apply()等高频函数的形态设计。
七、法则 6:规范语义法则(Canonical Semantics Law)——规范语义归特性包所有
Canonical feature semantics belong with the owning feature package.(规范特性语义归属于拥有该特性的包。)
法则的完整表述包含两个半句:
- 规范特性语义归属拥有它的特性包——一个特性(如链接、代码块、列表)的权威行为定义必须留在该特性包内;
- 偏好型糖保持本地,直到它真正成为规范(Preference-heavy sugar belongs local until it becomes genuinely canonical)——那些充满个人偏好、尚未被广泛认可的便捷封装,只应作为本地代码存在,不应过早提升为公共契约。
这条法则与"所有权法则""分层法则"相互咬合:它回答了"一段语义逻辑抽到哪里"的最终判据——看它是规范语义(canonical semantics)还是偏好糖(preference-heavy sugar)。
pattern-catalog.md 的 Plugin / Extension Patterns 一节给出对应偏好:包内拥有规范语义(package-owned canonical semantics)、每个特性显式归属、为常见扩展工作提供本地化辅助、在"不隐藏工作"的前提下允许 owner-scoped 默认值;同时避免"跨特性的全局语义大口袋"(one global bag of cross-feature semantics)和"把应用本地糖伪装成规范"(making app-local sugar look canonical)。
north-star SKILL.md 中的Matcher Extraction Heuristic(匹配器抽取启发式)是该法则最具操作性的落地工具:当扫描一个可复用 API 家族时,优先检查重复的resolve()与apply()主体,再决定是否新增包级包装。默认姿态是:
- 多个包重复同样的匹配前奏(matching prelude)→ 这是 core 原语的抽取压力;
- 多个包重复同样的特性动作(feature action)→ 通常仍属于拥有它的包。
应抽入 core 的逻辑多为与特性无关的编辑状态检查:触发门控(trigger gating)、折叠选区门控、块起始/光标前文本/相邻字符查找、分隔符/前缀/正则匹配、range 或 payload 构造等;应保留在特性包的多为语义转换:节点创建、mark 切换、列表变换、链接校验/插入、方程插入、代码块插入等。结论被明确为:core 拥有匹配原语与共享输入状态访问,特性包拥有语义 apply 行为——"不要因为文件看起来相似就把包语义压平进 core,也不要因为动作代码很显眼就漏掉真正的 core 原语。"
八、法则 7:公共契约法则(Public Contract Law)——作者侧保留类型丰富度,存储边界放宽泛型
Keep authoring-time type richness where it helps the author. Widen at runtime storage boundaries when exact generics no longer matter.(在作者侧保留对作者有帮助的类型丰富度;当精确泛型不再有意义时,在运行时存储边界放宽。)
法则补充了关键约束:"Do not force runtime containers to pretend they preserve more type precision than they actually need.(不要强迫运行时容器假装保留了它们实际不需要的更高类型精度。)"
这是一条务实的两段式原则:
- authoring-time(作者编写时):API 面向插件作者的签名应当保留丰富、精确的泛型与类型信息,让作者获得完整体验(自动补全、类型推导、契约检查);
- runtime storage boundaries(运行时存储边界):当数据被写入共享的运行时容器(如节点存储、状态树、跨包消息)时,精确泛型往往不再有意义,此时应放宽类型,避免为了维护虚假的精确性而引入无谓的运行时包装与转换开销。
对应反模式是 anti-patterns.md 中的 "Runtime containers forced to preserve useless generic precision"(运行时容器被迫保留无用的泛型精度)。这条法则与 plate-plugin-creator 的类型规则一致:优先依赖createSlatePlugin/createTSlatePlugin的推断,只在显式契约控制能带来真实收益时才使用createT*显式泛型工具,而不是默认堆砌显式标注("Use inference before ceremony")。
九、法则的落地:从宪法到执行的工作流与再确认契约
laws.md 的七条法则本身不直接产生代码,它们通过 north-star 的完整工作流驱动仓库的每一次公共 API 变更。整合 SKILL.md 的 Workflow 与 decision-ladder.md,标准流程为:
- 运行 决策阶梯(是否可复用 → 是否应用本地便利 → 模式是否已定 → 层是否清晰 → 性能是否约束形态 → 是否需要再确认);
- 先决定拥有者与层;
- 在 模式目录 中查找首选模式家族;
- 扫描重复的
resolve()/apply()形态,在祝福新的公共辅助函数之前先分离匹配逻辑与特性语义; - 在认可"更漂亮的 API"之前运行 性能选择协议;
- 检查 反模式目录;
- 若引入或实质性变更可复用公共模式,遵循 更新策略;
- 模式选定后,将实现机制交接给 plate-plugin-creator 或其他执行型技能。
再确认契约(Reaffirmation Contract)
宪法并非一劳永逸。update-policy.md 规定:任何引入或实质性变更可复用公共 API、运行时边界、builder/factory 模式或扩展契约的 lane,必须在提交中携带以下二者之一:
north-star updatednorth-star reaffirmed: <section-name>
再确认不是隐式的,必须指名所依据的章节以保证可审查性,例如north-star reaffirmed: laws、north-star reaffirmed: decision-ladder、north-star reaffirmed: performance-selection-rules。若一次变更新增或修改了可复用架构/公共模式教义却没有更新或再确认 north-star,则该 lane 视为不完整(review smell)。
二元审查清单(Binary Review Checklist)
north-star 的每条 lane 最终通过五个是非问题把关:
- 拥有者是否已命名?(Is the owner named?)
- 层是否已命名?(Is the layer named?)
- 可复用 vs 本地是否已裁决?(Is reusable vs local decided?)
- 管辖的 north-star 章节是否已指名?(Is the governing
north-starsection named?) - 热路径相关时是否应用了性能协议?(Was the performance protocol applied when hot-path relevant?)
与执行型技能的分工
laws.md 的法则是"上游宪法",而 plate-plugin-creator 是"下游执行伙伴"。二者的所有者地图为:
| 拥有者 | 范围 |
|---|---|
north-star | 教义、API 形态、运行时边界、性能法则 |
plate-plugin-creator | 插件机制、类型、包装层、文件摆放 |
执行技能明确被禁止重复长篇 north-star 法则("Do not restate long-formnorth-starlaw, precedence, or anti-pattern prose here"),只保留路由闸门、短派生态度清单与执行机制。若plate-plugin-creator开始累积长篇幅架构法则、优先级论述或反模式目录,则应将内容移回 north-star(update-policy.md 的 review smell 条款)。同时,decision-ladder.md 与 SKILL.md 都强调:若模式已定、任务只是实现机制,则直接交接给执行技能,避免重复走宪法流程。
十、结语:法则与仓库现状的相互印证
把七条法则与仓库实际组织方式对照,可以清晰地看到教义与实现的同构性:packages/core/src/lib/plugin下的 createSlatePlugin.ts 是"共享运行时原语"(法则 2)与"core 所有权"(法则 1)的实例;40 余个特性包各自持有语义契约(法则 6);packages/utils/src/lib/plate-keys.ts 的共享键是显式性(法则 3)的实例;internal/目录约定落实了执行辅助层与公共契约的物理隔离;性能选择协议把"性能是设计约束"(法则 5)变成了每个 API 上线的必经关卡;而 authoring-time 类型丰富度与运行时边界放宽的并存(法则 7),则体现为 core 作者原语与packages/core/type-tests契约测试之间的默契配合。
对任何为 Plate 贡献可复用能力(新插件、新 builder、新运行时边界)的开发者而言,laws.md 七条法则提供了五问自检的底层依据——谁拥有、属于哪层、是否显式、边界是否清晰、代价是否已付。这五问也正是 north-star 体系区别于一般"代码风格规范"的地方:它把架构决策当作有宪法依据、有执行路由、有再确认契约的持续工程实践。
【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考