BlockSuiteを試す
BlockSuiteとは?
BlockSuite | Content Editing Toolkit
BlockSuite は、共同編集アプリケーションを作成するためのツールキットを提供します。
ドキュメント×ホワイトボード×データベースが統合されたワークスペース AFFiNE で使用されている共同編集部分のライブラリになります。
Editor中心に展開しない独自の Document-Centric という以下のようなアプローチをとっています。
各エディターがその内部状態を統合的に管理せず、ドキュメント(エディターのデータ層) はエディターから完全に独立して維持され絵ディッターはアタッチするだけの機能に留める
ドキュメントは共同編集を実現すべくCRDTの基盤の上に構築されています。
Document-Centric 部分を試してみたいのですが、まずは今回は動かせるようにしたいと思うので、
プリセットとして提供されている以下の DocEditor
と EdgelessEditor
を動かせるまでを試してみたいと思います。
DocEditor
このエディター プリセットは、ドラッグ ハンドル、スラッシュ メニュー、フォーマット ツールバー、その他の組み込みの強力なウィジェットを組み合わせた、ブロックベースのリッチ テキスト編集に優れています。
EdgelessEditor
このエディター プリセットは、ホワイトボードのグラフィックスの編集機能に優れています。 キャンバスベースのグラフィックスと DOM ベースのブロック ツリーを組み合わせます。 これにより、創造的なグラフィック デザインと構造化されたドキュメント編集のどちらも簡単になり、幅広いユーザーのニーズとワークフローに対応できます。
サクッと環境構築
DevContainer
の環境でNode環境作成します。
-
.devcontainer/Dockerfile
FROM node:20.10.0-bullseye-slim LABEL maintainer="Slowhand0309" ARG username=vscode ARG useruid=1001 ARG usergid=${useruid} RUN set -ex \ && apt-get update \ && apt-get install -y \ git \ sudo \ --no-install-recommends \ && groupadd --gid ${usergid} ${username} \ && useradd -s /bin/bash --uid ${useruid} --gid ${usergid} -m ${username} \ && echo ${username} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${username} \ && chmod 0440 /etc/sudoers.d/${username} USER ${username}
-
.devcontainer/docker-compose.yml
version: '3.8' volumes: modules_data: services: blocksuite: build: . image: slowhand/blocksuite container_name: "blocksuite" volumes: - ..:/usr/src - modules_data:/usr/src/node_modules command: /bin/sh -c "while sleep 1000; do :; done" ports: - '5173:5173' working_dir: /usr/src
-
.devcontainer/devcontainer.json (細かい設定はお好みで)
{ "name": "BlockSuite remote container dev", "dockerComposeFile": ["docker-compose.yml"], "service": "blocksuite", "workspaceFolder": "/usr/src", "customizations": { "vscode": { "extensions": [ "formulahendry.auto-rename-tag", "ms-vscode.vscode-typescript-tslint-plugin", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "yoavbls.pretty-ts-errors" ], "settings": { "editor.tabSize": 2, "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "files.insertFinalNewline": true, "files.trimFinalNewlines": true } } }, "postAttachCommand": ".devcontainer/postAttach.sh", "remoteUser": "vscode" }
-
.devcontainer/postAttach.sh
#!/bin/sh cd `dirname $0` cd .. sudo chown -R vscode node_modules # yarn install # yarn dev
DevContainerをVSCode上で起動し、コンテナ内に入ってViteで環境構築していきます。
$ yarn create vite
yarn create v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Installed "create-vite@5.1.0" with binaries:
- create-vite
- cva
✔ Project name: … .
✔ Current directory is not empty. Please choose how to proceed: › Ignore files and continue
✔ Select a framework: › React
✔ Select a variant: › TypeScript + SWC
Scaffolding project in /usr/src...
Done. Now run:
yarn
yarn dev
Docker用に package.json
の scripts
> dev
を以下に修正します。
"dev": "vite --host 0.0.0.0",
早速起動してみます。
yarn
yarn dev
上記コマンドを実施し、http://localhost:5173/ にアクセスして表示されていればOKです。
必要なパッケージインストール
yarn add @blocksuite/presets@nightly @blocksuite/store@nightly yjs
BlockSuiteは共同編集部分にCRDT実装のyjsを使っているのでそちらもインストールします。
DocEditor
を試す
シンプルな import "@blocksuite/presets/themes/affine.css";
import { createEmptyPage, DocEditor } from "@blocksuite/presets";
import { useEffect, useRef } from "react";
function App() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
(async () => {
const page = await createEmptyPage().init();
const editor = new DocEditor();
editor.page = page;
ref.current?.appendChild(editor);
})();
}, []);
return (
<div
ref={ref}
style={{ width: "100vw", height: "100vh", background: "white" }}
></div>
);
}
export default App;
↑に修正し yarn dev
で起動させると以下の様なシンプルなBlock Editorが起動します。
EdgelessEditor
を試す
シンプルな 先程修正した App.tsx
の DocEditor
を EdgelessEditor
に変更します。
import "@blocksuite/presets/themes/affine.css";
import { createEmptyPage, EdgelessEditor } from "@blocksuite/presets";
import { useEffect, useRef } from "react";
function App() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
(async () => {
const page = await createEmptyPage().init();
const editor = new EdgelessEditor();
editor.page = page;
ref.current?.appendChild(editor);
})();
}, []);
return (
<div
ref={ref}
style={{ width: "100vw", height: "100vh", background: "white" }}
></div>
);
}
export default App;
これだけで↑の様なCanvas上でBlockEditorが使えるEditorが表示されます。
Discussion