🕋

BlockSuiteを試す

2024/01/13に公開

BlockSuiteとは?

BlockSuite | Content Editing Toolkit

BlockSuite は、共同編集アプリケーションを作成するためのツールキットを提供します。

ドキュメント×ホワイトボード×データベースが統合されたワークスペース AFFiNE で使用されている共同編集部分のライブラリになります。

Editor中心に展開しない独自の Document-Centric という以下のようなアプローチをとっています。

各エディターがその内部状態を統合的に管理せず、ドキュメント(エディターのデータ層) はエディターから完全に独立して維持され絵ディッターはアタッチするだけの機能に留める

ドキュメントは共同編集を実現すべくCRDTの基盤の上に構築されています。

Document-Centric 部分を試してみたいのですが、まずは今回は動かせるようにしたいと思うので、

プリセットとして提供されている以下の DocEditorEdgelessEditor を動かせるまでを試してみたいと思います。

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.jsonscripts > 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が起動します。

image1.gif

シンプルな EdgelessEditor を試す

先程修正した App.tsxDocEditorEdgelessEditor に変更します。

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;

image2.gif

これだけで↑の様なCanvas上でBlockEditorが使えるEditorが表示されます。

Discussion