10 分钟从 0 实现多人协同编辑 ProseMirror + Yjs

4,583 阅读4分钟

大家好,我是双越老师,也是 wangEditor 富文本编辑器作者。

近期我正在致力于开发一个 Node 全栈 AIGC 知识库项目 划水AI ,包括文档管理、AI 写作、协同编辑等功能。真实上线,持续维护,有兴趣的同学欢迎点进去看看~

开始

今天我将带你花 10 分钟实现一个基础的 富文本编辑器 + 协同编辑功能,使用 ProseMirror + Yjs 实现,效果动图如下:

Kapture 2024-08-23 at 16.36.50.gif

你只需要跟随本文的步骤来操作,很快就能实现协同编辑的功能和效果。源码链接放在文章末尾。

使用 vite 创建项目

使用 vite 可快速创建项目,我使用 vanilla 模板,即原生 js ,不使用 Vue React 等框架

npm create vite@latest collab-client -- --template vanilla

创建完成以后,把它内置的代码清理一下,只保留一个空白 html 页面即可。其中要有一个 <div id="editor"></div> 以承载编辑器。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Collaborative Editor Demo</title>
  </head>
  <body>
    <div id="editor"></div> <!-- 这个必须有 !!! -->
    <script type="module" src="/js/main.js"></script> <!-- main.js 空着即可 -->
  </body>
</html>

创建 ProseMirror 编辑器

PromeMirror 是一款非常优秀的编辑器,开发和维护很多年了,社区非常流行。而且开源免费。

ProseMirror 设计非常精巧复杂,初学需要了解很多新概念,文档内容也比较多。但现在你只是想体验一个 demo 不用看这么详细,跟着我的步骤操作即可。

第一,安装必要的 npm 插件

npm i prosemirror-state prosemirror-view prosemirror-example-setup

第二,新建文件 js/schema.js 用于定义 PromeMirror Schema 。所谓 Schema 就是用于规范 ProseMirror 内容的结构,例如内容可包含 <p> <h1> <h2> 等,不能包含 <div> ,再例如 <p> 的下级只能是 inline 元素,不能是 <table> 等……

因为 HTML 结构太灵活了,如果不做限制,会导致编辑器内部结构混乱,没法高效的进行富文本编辑和写作。现代富文本编辑器都有了类似的机制,来限制内容和数据格式。

大概就是这个意思,你现在不用详细了解,直接把我的代码拷贝过来,粘贴到你的 js/schema.js 文件中即可 github.com/wangfupeng1…

第三,新建文件 style/style.css 定义一些编辑器相关的样式,直接拷贝我的代码 github.com/wangfupeng1…

第四,修改 js/main.js 代码

import { EditorState } from 'prosemirror-state'
import { schema } from './schema'
import { EditorView } from 'prosemirror-view'
import { exampleSetup } from 'prosemirror-example-setup' // 官方示例,集成了一些基础的插件和功能,例如 Bold Heading 等
import '../style/style.css'

const editor = document.querySelector('#editor')

const prosemirrorView = new EditorView(editor, {
  state: EditorState.create({
    schema,
    plugins: exampleSetup({ schema }), // array
  }),
})

好了,在控制台执行 npm run dev 本地运行,浏览器打开网址,即可看到一个基础的编辑器已经创建完成。

image.png

接入 Yjs 协同编辑功能

Yjs 是 nodejs 社区中一个非常流行的协同编辑服务工具,它基于 CRDT 算法,支持很多流行的编辑器。当然它也支持 ProseMirror 而且支持的很好。

还是基于之前的代码。首先,安装必要的 npm 插件

npm i yjs y-websocket y-prosemirror prosemirror-keymap

然后把 js/main.js 文件修改为如下内容,主要是增加 Yjs 协同编辑相关的代码

import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
import { ySyncPlugin, yCursorPlugin, yUndoPlugin, undo, redo } from 'y-prosemirror'
import { EditorState } from 'prosemirror-state'
import { schema } from './schema'
import { EditorView } from 'prosemirror-view'
import { exampleSetup } from 'prosemirror-example-setup'
import { keymap } from 'prosemirror-keymap'
import '../style/style.css'

const ydoc = new Y.Doc()
const serverUrl = 'wss://demos.yjs.dev'
const provider = new WebsocketProvider(serverUrl, 'my-room', ydoc)
const type = ydoc.getXmlFragment('prosemirror')

const editor = document.querySelector('#editor')

const prosemirrorView = new EditorView(editor, {
  state: EditorState.create({
    schema,
    plugins: [
      ySyncPlugin(type),
      yCursorPlugin(provider.awareness),
      yUndoPlugin(),
      keymap({
        'Mod-z': undo,
        'Mod-y': redo,
        'Mod-Shift-z': redo,
      }),
    ].concat(exampleSetup({ schema })),
  }),
})

多人协同编辑,需要使用 websocket 和服务端进行通讯,在 Yjs 官网 demo 中,它提供了一个线上 websocket server

const serverUrl = 'wss://demos.yjs.dev'

但我在本地运行会连接失败。也许它服务端做了屏蔽,这个我们不得而知,总之是不行

image.png

自己创建 WebSocket Server

既然它给出的 websocket url 不能用,那我们自己在本地启动一个 websocket server —— 即便是在工作中,我们也需要有能力搭建自己的服务,而不是依赖于第三方的服务,那就太被动了。

参考 y-websocket 的文档 github.com/yjs/y-webso… ,可通过 cli 启动服务。新建一个命令行窗口,定位到项目目录,执行如下命令:

HOST=localhost PORT=1234 npx y-websocket

然后修改 js/main.j 文件,改为自己本地的服务地址

// const serverUrl = 'wss://demos.yjs.dev'
const serverUrl = 'ws://localhost:1234'

重启 vite 服务,然后刷新页面,就可以协同编辑了。用多个浏览器访问,就能看到协同编辑的效果。

image.png

最后

这只是一个基础的示例,让你短时间体验 Yjs 的能力。真实项目中的多人协同编辑还有很多需要做的,例如

  • 存储文档数据,数据格式的转换(Yjs 存储的是二进制数据)
  • 显示在线用户,显示连接状态
  • 协同编辑服务部署上线,监控,报警
  • 编辑器更加复杂的功能,支持多种富文本格式
  • 更多...

想要了解或学习这些知识,可以关注我的 划水AI 项目,它有真实上线的多人协同编辑功能。

本文源代码链接 github.com/wangfupeng1… 。我是双越老师,持续分享技术干货,欢迎关注我~