Skip to content
目录

协同编辑(Yjs)设计与一致性策略

1. 总体设计

Plate 的协同不是“外部补丁”,而是插件化接入:

  • 基础插件:BaseYjsPlugin
  • 编辑器增强:withPlateYjs
  • provider 适配:hocuspocus / webrtc 等

关键路径:

  • packages/yjs/src/lib/BaseYjsPlugin.ts
  • packages/yjs/src/lib/withPlateYjs.ts

2. 初始化流程(高频)

BaseYjsPluginapi.init 大致流程:

  1. 校验 provider 配置
  2. 实例化 provider 并绑定 connect/disconnect/sync 回调
  3. 可选自动连接,等待首次 sync(带 timeout)
  4. 判断远端 shared type 是否已有内容
  5. 仅在远端为空时灌入初始值(避免覆盖远端状态)
  6. 连接 YjsEditor,再走 editor init + onReady

这个顺序非常关键:先同步,再决定是否写入初始内容,避免“本地初始值覆盖远端文档”。

3. 一致性与可恢复性策略

3.1 空文档才写初始值

sharedRoot.length === 0 才会应用初始内容,这是一致性底线。

3.2 provider 统一生命周期管理

插件 API 提供:

  • connect
  • disconnect
  • destroy

并且针对 provider 类型有细节考虑(例如 awareness 清理时机)。

3.3 错误回调统一出口

provider 创建/连接中的错误统一走 onError,方便应用层监控。

4. 扩展性设计点

  • provider 既支持“配置对象”,也支持“实例注入”
  • 支持 custom shared type,不强制固定 Yjs 文档键
  • 协同绑定顺序可控(核心 Yjs -> cursors -> history)

这让企业场景(自建服务、混合 provider、特殊同步策略)更容易接入。

5. 思考题:为什么协同也要插件化?

建议回答:

  1. 协同与编辑核心耦合深(selection/history/transform),不能仅靠外围订阅
  2. 插件化能复用 editor 生命周期与类型系统
  3. 可以按需启用,避免把协同成本强塞给单机场景

小结

Plate 的 Yjs 设计体现的是“协同即一等公民能力”:它不只是能连上服务,而是对初始化时序、一致性边界、provider 生命周期都做了工程化封装。

MIT License.