Skip to content
目录

插件系统内核:创建、解析、执行

1. 心智模型

Plate 插件不是“配置对象”,而是 可组合、可扩展、可重写的行为单元。一个插件最小需要 key,其余能力按需叠加:

  • options/selectors:状态与查询
  • api/transforms:能力暴露与状态变更
  • handlers/render/rules:事件与渲染行为
  • dependencies/priority:执行顺序控制

对应定义可在 packages/core/src/lib/plugin/BasePlugin.ts 看到。

2. 插件创建:从声明到可扩展实例

核心工厂是 createSlatePlugin,Plate React 场景再包一层 createPlatePlugin

  • createSlatePluginpackages/core/src/lib/plugin/createSlatePlugin.ts
  • createPlatePluginpackages/core/src/react/plugin/createPlatePlugin.ts

为什么这两个层级很关键?

  1. createSlatePlugin 负责基础插件能力(无 React 绑定)
  2. createPlatePlugin 通过 toPlatePlugin 增加 React 侧能力

这让“核心逻辑”和“框架集成”天然解耦,便于 SSR/静态环境和 React 场景共存。

3. 解析阶段:resolvePlugins 做了什么

插件真正生效是在解析阶段,入口是:

  • packages/core/src/internal/plugin/resolvePlugins.ts

该阶段做了 6 件事:

  1. 初始化 editor 缓存与 plugin registry
  2. flatten + resolve 嵌套插件
  3. 同 key 合并(后来的覆盖前面的)
  4. 先按 priority 排序,再按 dependencies 重排
  5. 计算快捷缓存(handlers/render/nodeProps/shortcuts)
  6. 创建每个插件的 options store(zustand-x)

这不是“简单数组遍历”,而是一个可复用的插件编译过程。

4. 顺序控制:priority + dependencies

源码里先按优先级降序,再 DFS 访问依赖(缺失依赖会 debug.warn),这能同时满足:

  • 全局优先级可控
  • 局部依赖可声明
  • 错误依赖可观测

这也是为什么可以说:Plate 的插件顺序不是“约定”,是“显式图结构 + 优先级”的混合模型。

5. 覆盖机制:可定制但可追踪

resolvePluginOverrides 支持 3 类覆盖:

  • 启用/禁用覆盖(override.enabled
  • 组件覆盖(按优先级决定生效)
  • 插件配置覆盖(override.plugins

这一套设计让业务方可以局部重写核心行为,同时不需要 fork 全插件。

6. 历史证据:动态插件与基类插件重构

  • PR #1882 显示动态插件问题会波及大面积包(当时 changeset 涉及 61 个包),说明插件编排是系统级问题,不是单点 bug。
  • PR #3526 “Base plugin” 超大规模重构(977 files),本质是把“基础插件能力”和“React 变体”边界进一步固化。

7. 回答模板

你可以这样回答“Plate 插件系统怎么工作的”:

  1. 创建:createSlatePlugin/createPlatePlugin 产出可扩展插件实例
  2. 解析:resolvePlugins flatten/merge/sort/dependency-order/store
  3. 执行:通过缓存管线把 handlers、rules、render、shortcuts 路由到 editor 生命周期
  4. 定制:overrideextend* 提供有边界的重写点

小结

Plate 插件系统的价值不只是“可扩展”,而是 可扩展 + 可预测 + 可治理。这三点一起,才能支撑几十个插件包长期演进。

MIT License.