🐡
y-durableobjects で共同編集エディタを作る
はじめに
の紹介記事です。Lexical と yjs の cloudflare workers 実装である、y-durableobjects を組み合わせて共同編集エディタを作ります。
使用するライブラリ
共同編集エディタを作る
デモサイト。こういうのが作れます。
こちらのリポジトリにサンプルコードがあります。
Lexical で共同編集可能なエディタを作る
Lexical の公式ドキュメントには、共同編集可能なエディタを作るためのサンプルコードがあるのでそれに従って実装します。
ws://localhost:8787
になっている部分は wrangler dev
によって開かれる port に合わせて適宜変更してください。
import { LexicalComposer } from "@lexical/react/LexicalComposer";
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
import { PlainTextPlugin } from "@lexical/react/LexicalPlainTextPlugin";
import { CollaborationPlugin } from "@lexical/react/LexicalCollaborationPlugin";
import { Doc } from "Yjs";
import { WebsocketProvider } from "y-websocket";
import type { FC, ComponentProps } from "react";
import type { Provider } from "@lexical/Yjs";
import type { InitialConfigType } from "@lexical/react/LexicalComposer";
type ProviderFactory = ComponentProps<typeof CollaborationPlugin>["providerFactory"];
const providerFactory: ProviderFactory = (id, map) => {
const doc = new Doc();
map.set(id, doc);
const provider = new WebsocketProvider(new URL("/editor", "ws://localhost:8787").href, id, doc);
// 公式通りやると型エラーになるのでキャスト
return provider as unknown as Provider;
};
const initialConfig: InitialConfigType = {
editorState: null,
namespace: "Demo",
nodes: [],
onError: (error: Error) => {
throw error;
},
};
type Props = {
id: string;
};
const Editor: FC<Props> = ({ id }) => {
return (
<LexicalComposer initialConfig={initialConfig}>
<PlainTextPlugin
contentEditable={<ContentEditable className="editor" />}
placeholder={<div>Enter some text...</div>}
/>
<CollaborationPlugin id={id} username={crypto.randomUUID()} providerFactory={providerFactory} shouldBootstrap />
</LexicalComposer>
);
};
export default Editor;
共同編集サーバー
共同編集サーバーは、y-durableobjects
を使って実装します。y-durableobjects
は hono
と組み合わせて使うことを想定しているため、hono
と組み合わせて使います。
import { Hono } from "hono";
import { cors } from "hono/cors";
import { YDurableObjects, yRoute } from "y-durableobjects";
const app = new Hono();
app.use("*", cors());
const route = app.route(
"/editor",
yRoute((env) => env.Y_DURABLE_OBJECTS),
);
export default route;
export { YDurableObjects };
DurableObjects を使用するので wrangler.toml
に以下のように設定します。
[durable_objects]
bindings = [
{ name = "Y_DURABLE_OBJECTS", class_name = "YDurableObjects" }
]
Hono の Bindings に Y_DURABLE_OBJECTS
を追加しておきましょう。
type Bindings = {
Y_DURABLE_OBJECTS: DurableObjectNamespace;
};
declare module "hono" {
interface Env {
Bindings: Bindings;
}
}
あとは vite dev
と wrangler dev
を実行して、vite のサーバーにアクセスすると共同編集エディタが使えるようになります。
おわりに
CloudflareWorkers で簡単に共同編集エディタを作ることができました。Lexical 以外のエディタでも Yjs が使用できれば応用できると思います。ぜひ試してみてください。
Discussion