Open4

CRDTとYjs

でゅらたたたんでゅらたたたん

CRDTとYjsについて調べてみた

検索すればそこそこ情報がでてくるので詳細には書かない。
自分の脳内メモリに入るだけの情報を一旦メモする。
用語が正確でない可能性あり。

CRDTとは

ざっくりいうと、FigmaやNotionなどリアルタイム共同編集を行う際に使われるアルゴリズム。
共同編集では当たり前だが複数人が同時に同一のデータを触ると操作のコンフリクトが起きてしまい、正しいデータはどれ?問題が起きるが、これを定められたルールで自動で解決してくれる。
普段エンジニアはGitに触れているがGitはコンフリクトを検知して、自動ではマージしてくれない時があるが、こいつは自動で(勝手に)やってくれるということになる。

尚、データを読むことにおいては各クライアント間である一瞬ではデータの整合が取れていないかもしれないが、時間が経てば各クライアントの編集内容は解決されたデータになるという手法にもなる。
そのためオフライン編集があった場合でも、解決できる。

でゅらたたたんでゅらたたたん

種類

CRDTには2種類あり、操作ベースのCRDT(CmRDT)と、状態ベースのCRDT(CvRDT) がある。
現在主流なのは 状態ベースのCvRDT のほう。

CvRDTはローカルで更新されたデータそのものを別クライアント(レプリカ)に送信し、データの収束を実現する。

でゅらたたたんでゅらたたたん

Yjs

yjsはCvRDTの改善版(※1)を使って共同編集を実現するJavaScriptライブラリとなる。

上記公式リポジトリのReadmeが詳しいのと、(公式?doc)[https://docs.yjs.dev/] がわかりやすかった。docのほうは、「WIPなので、リポジトリのReadme見てね」って書いてあるが、概要理解にはよかった。

ざっくり理解したこと

YjsはCRDTの部分のみ実装してあり、データの永続先がどことか、ネットワーク(プロトコル)どうするとか、どういうデータを共同編集対象にするかは抽象化してあるようで可換にしてある。しゅごい。

共同編集対象がエディタの場合は、デフォルトで連携できるエディタの種類がいくつかあるので、そこから選べばよさそう。たとえばQuill など。

オフラインサポートも y-indexeddb を含めて、Service Worker を組み込むだけで、ネットワーク アクセスがなくても Web サイトにアクセスできるようになるらしい。

小さめのサンプル実装


import * as Y from 'yjs'
import { WebrtcProvider } from 'y-webrtc'
import { QuillBinding } from 'y-quill'
import Quill from 'quill'
import QuillCursors from 'quill-cursors'

Quill.register('modules/cursors', QuillCursors)

const quill = new Quill(document.querySelector('#editor'), {
  modules: {
    cursors: true,
    toolbar: [なんか設定]
  },
  placeholder: 'Start collaborating...',
  theme: 'snow' // 'bubble' is also great
})

// ここから
// A Yjs document holds the shared data
const ydoc = new Y.Doc()

// 他のエディタ(クライアント)と同期するためのプロバイダー
const provider = new WebrtcProvider('quill-demo-room', ydoc)

// 共有データタイプを決める
const ytext = ydoc.getText('quill')
//quill editor と Yjs をバインドする
const binding = new QuillBinding(ytext, quill, provider.awareness)

// ここまでかな

// Remove the selection when the iframe is blurred
window.addEventListener('blur', () => { quill.blur() })

※1: どうも普通にCRDTをJsで実装すると、全ての文字に固有ID振ったりなんだのでメモリを爆食いするらしいが、Yjsはいろいろ改良をして実用レベルにもっていってる模様。