$30 off During Our Annual Pro Sale. View Details »

Technologies for developing editors / Webエディタ開発を支える技術

did0es
January 19, 2023

Technologies for developing editors / Webエディタ開発を支える技術

MuddyWeb #4 19:00 - 19:20「Webエディタ開発を支える技術」の資料です。

株式会社CAMがOSSとして開発を行っているpde.js( https://github.com/cam-inc/pde.js )について、生まれた背景や内部実装、これを用いたWebエディタ開発などのmuddyな部分をお話します。

Speaker: Hirai Shuta( @did0es: https://twitter.com/did0es )
Event URL: https://cyberagent.connpass.com/event/270629/

did0es

January 19, 2023
Tweet

More Decks by did0es

Other Decks in Technology

Transcript

  1. Webエディタ開発を
    支える技術
    Muddy Web #4
    Speaker: Hirai Shuta
    2023 / 01.19

    View Slide

  2. 平井 柊太(ひらい しゅうた)
    2022年度 新卒入社
    株式会社CAM Webフロントエンドエンジニア
    Twitter: did0es / GitHub: shuta13

    View Slide

  3. はじめに

    View Slide

  4. お話すること
    ● 何を解決するのか
    ● どのように解決するのか
    ● 振り返り
    ● 今後の展望
    ● まとめ

    View Slide

  5. エディタ

    View Slide

  6. エディタ
    →コンピュータ上で各種オブジェクトを編集する
     ソフトウェア

    View Slide

  7. Webエディタ

    View Slide

  8. Webエディタ
    →Webブラウザで使用するエディタ

    View Slide

  9. VSCode
    エディタの例

    View Slide

  10. VSCode Wordpress
    (Gutenberg)
    エディタの例

    View Slide

  11. VSCode Wordpress
    (Gutenberg)
    Notion
    エディタの例

    View Slide

  12. VSCode Wordpress
    (Gutenberg)
    Notion

    View Slide

  13. VSCode Wordpress
    (Gutenberg)
    Notion
    テキストエディタ ブロックエディタ

    View Slide

  14. これらのようなブロックエディタを実装するお話です。
    Wordpress
    (Gutenberg)
    Notion

    View Slide

  15. 使用技術の紹介
    Editor.js

    View Slide

  16. Editor.jsとは
    ● 豊富なプラグイン
    ● 独自のプラグインも実装可能
    ● (ある程度)クリーンデータ
    ● UIライブラリ非依存

    View Slide

  17. Editor.jsとは
    ● 豊富なプラグイン
    ● 独自のプラグインも実装可能
    ● (ある程度)クリーンデータ
    ● UIライブラリ非依存
    機能性・拡張性の高いブロックエディタを
    UIライブラリ無しで実装できるライブラリ

    View Slide

  18. Editor.jsとは
    ● 豊富なプラグイン
    ● 独自のプラグインも実装可能
    ● (ある程度)クリーンデータ
    ● UIライブラリ非依存
    機能性・拡張性の高いブロックエディタを
    UIライブラリ無しで実装できるライブラリ

    View Slide

  19. Editor.jsプラグイン

    View Slide

  20. Editor.jsプラグイン
    赤枠内全て

    View Slide

  21. Editor.jsプラグインの名称と機能
    Block Tool Inline Tool Block Tune

    View Slide

  22. Editor.jsプラグインの名称と機能
    Block Tool
    →ブロック作成機能
    Inline Tool
    →テキスト編集機能
    Block Tune
    →ブロック編集機能

    View Slide

  23. 何を解決するのか

    View Slide

  24. Editor.jsプラグイン実装

    View Slide

  25. Editor.jsプラグイン実装
    1.特定のメソッドを含む
    Classを作成

    View Slide

  26. Editor.jsプラグイン実装
    2.Editor.jsにClassを
    渡す
    1.特定のメソッドを含む
    Classを作成

    View Slide

  27. Block ToolのメソッドとUI

    View Slide

  28. Block ToolのメソッドとUI

    View Slide

  29. Block ToolのメソッドとUI

    View Slide

  30. プラグイン実装に潜む課題

    View Slide

  31. DOMツリー

    JSON(JSのObject)

    プラグイン実装に潜む課題

    View Slide

  32. DOMツリー
    →命令的なUIの記述
    JSON(JSのObject)
    →宣言的なUIの記述
    プラグイン実装に潜む課題

    View Slide

  33. プラグイン実装に潜む課題
    DOMツリー
    →命令的なUIの記述
    JSON(JSのObject)
    →宣言的なUIの記述
    UIを宣言的に書きたい

    View Slide

  34. Editor.jsプラグイン実装の課題と問題
    ● 書き方にばらつきがある
    ○ 宣言的な記述と命令的な記述が混在している
    ● 命令的な記述はコードの維持が難しい
    ○ 可読性が下がりがち
    ○ コードの実行順から UI の状態を推測しづらい
    ○ データ変更のタイミングが分かりづらい
    ● データの管理が難しい
    ○ エディタはデータの入出力が多い
    ○ HTMLのデータ属性にこのデータを詰め込みたくない(...ですよね?)

    View Slide

  35. 課題と問題に対する解決アプローチ
    ● 書き方にばらつきがある
    ○ 宣言的な記述と命令的な記述が混在している
    ● 命令的な記述はコードの維持が難しい
    ○ 可読性が下がりがち
    ○ コードの実行順から UI の状態を推測しづらい
    ○ データ変更のタイミングが分かりづらい
    ● データの管理が難しい
    ○ エディタはデータの入出力が多い
    ○ HTMLのデータ属性にこのデータを詰め込みたくない(...ですよね?)

    View Slide

  36. 課題と問題に対する解決アプローチ
    ● 書き方にばらつきがある
    ○ 宣言的な記述と命令的な記述が混在している
    ● 命令的な記述はコードの維持が難しい
    ○ 可読性が下がりがち
    ○ コードの実行順から UI の状態を推測しづらい
    ○ データ変更のタイミングが分かりづらい
    ● データの管理が難しい
    ○ エディタはデータの入出力が多い
    ○ HTMLのデータ属性にこのデータを詰め込みたくない(...ですよね?)
    宣言的に書けるような
    記法を提供する
    データ管理向けの
    仕組みを提供する

    View Slide

  37. どのように解決するのか

    View Slide

  38. ゴール1. Editor.jsプラグインを宣言的に実装できる
    ゴール2. プラグインのデータ(状態)管理ができる
    ゴール3. 本来のインターフェースとかけ離れていない

    View Slide

  39. Editor.jsとは
    ● 豊富なプラグイン
    ● 独自のプラグインも実装可能
    ● (ある程度)クリーンデータ
    ● UIライブラリ非依存

    View Slide

  40. Editor.jsとは
    ● 豊富なプラグイン
    ● 独自のプラグインも実装可能
    ● (ある程度)クリーンデータ
    ● UIライブラリ非依存
    これらの特性も活かすように実装する

    View Slide

  41. 理想(プラグイン実装時)

    View Slide

  42. 理想(プラグイン実装時)

    View Slide

  43. 理想(プラグイン実装時)

    View Slide

  44. 理想(プラグイン実装時)(+α)

    View Slide

  45. 理想(プラグイン使用時)

    View Slide

  46. ゴール1. Editor.jsプラグインを宣言的に実装できる
    ゴール2. プラグインのデータ(状態)管理ができる
    ゴール3. 本来のインターフェースとかけ離れていない

    View Slide

  47. 実装したもの
    =

    View Slide

  48. 実装したもの
    = Reactに依存しない、Reactっぽく書ける
     Editor.jsプラグイン実装向けライブラリ

    View Slide

  49. View Slide

  50. Editor.jsとは
    ● 豊富なプラグイン
    ● 独自のプラグインも実装可能
    ● (ある程度)クリーンデータ
    ● UIライブラリ非依存

    View Slide

  51. Editor.jsとは
    ● 豊富なプラグイン
    ● 独自のプラグインも実装可能
    ● (ある程度)クリーンデータ
    ● UIライブラリ非依存
    特にこの特性を潰したくなかった

    View Slide

  52. View Slide

  53. 手順
    ● JSX Factoryの定義
    ● 差分検出処理の導入
    ● 状態管理を実現する

    View Slide

  54. JSX Factoryとは
    JSXをJSに変換すると生成される
    関数のこと。
    @babel/preset-reactを用いて
    変換すると右の画像のようになる。
    React.createElementの部分が
    JSX Factoryに該当する。

    View Slide

  55. 独自のJSX Factoryを使う
    コンパイラの設定を変えると
    独自(=React.createElement以外)の
    JSX Factoryを使える。
    babelであればpragmaを
    typescriptであればjsxFactoryを
    それぞれ設定する。
    ファイル内に/* @jsx */コメントを
    書くことでも設定可能。

    View Slide

  56. 独自のJSX Factoryを使う

    View Slide

  57. 独自のJSX Factoryを使う
    /* @jsx myJsxFactory */

    View Slide

  58. 独自のJSX Factoryを使う
    /* @jsx myJsxFactory */

    View Slide

  59. 独自のJSX Factoryを使う
    /* @jsx myJsxFactory */
    myJsxFactoryを実装すれば
    任意の処理を適用しながらJSX要素を探索できる

    View Slide

  60. (当資料における)差分検出処理とは
    2つの木の前後を比較し差分を取る
    処理のこと
    (木 = JSX要素ツリー)
    JSX FactoryではJSX要素ツリーを
    差分を検出しやすい形に変換して返す。
    (差分を検出しやすい形 = JSON)
    ※イメージ

    View Slide

  61. 差分検出処理を導入するにあたっての課題
    当初はReactと同じ方法(react-reconciler)
    で差分を検出する予定だった。
    ...が、react-reconcilerはreactに依存する。
    react依存の部分を剥がし、差分検出処理のみ
    スタンドアロンで利用出来るように試みた。
    ...が、コード量が膨大で誰も把握・メンテ
    できないことを懸念し、他の方法を模索した。

    View Slide

  62. Preactで代用して解決
    Preactの差分検出の仕組みを
    移植(書き換え)することで解決した。
    Preactの差分検出は1000行[※]程度の
    ミニマルなコードで記述されている。
    (※ ライブラリ作成当初。参考)
    Reactよりもコードの全容が把握しやすく
    メンテできる。

    View Slide

  63. とりあえずJSXで書けるようになった

    View Slide

  64. 状態管理
    PreactのHooksを参考に実装。
    useStateやuseReducerで状態を作成し
    更新用関数を取得する。
    useWatchやuseMountで副作用を管理する。

    View Slide

  65. https://github.com/cam-inc/pde.js
    完成したもの

    View Slide

  66. View Slide

  67. Playground
    CodeSandboxで色々試してみてください。

    View Slide

  68. Docs
    https://cam-inc.github.io/pde.js

    View Slide

  69. ライセンス
    ● pde.js: Apache-2.0 License
    ○ ライセンス
    ○ Editor.jsのサブセットとして、Editor.jsのライセンスに倣った
    ● Preact: MIT License
    ○ Preactをインストールしないので、自前で記載が必要。
    ○ Preactのオリジナルのライセンス文と、そのリンクをコメントで挿入。
    ○ sourcemapとして書き出して配信。

    View Slide

  70. 振り返り

    View Slide

  71. まとめ・所感
    ● Webエディタ開発で感じた課題を技術で解決した
    ○ 宣言的なUIの記述でEditor.jsプラグインを書けるようになった
    ○ ただ、未だ型やEditor.jsと接続する部分でバグが多い
    ● PreactやReactの差分検出処理に対する理解を深められた
    ○ JSX要素ツリーの比較
    ○ Hooks
    ● 先人と技術へのリスペクトを忘れない
    ○ Editor.jsやPreactを作った先人に感謝

    View Slide

  72. 今後の展望

    View Slide

  73. Coming Soon...
    Slate.js + Reactによる
    更に質の高いブロックエディタ実装向けライブラリ(OSS)を開発中

    View Slide

  74. おわりに

    View Slide

  75. https://cam-inc.co.jp/p/techblog/710053497071993899
    今回お話した内容はこちらからもご覧になれます

    View Slide

  76. https://github.com/cam-inc/pde.js
    ご興味あればコントリビュートお待ちしております!

    View Slide

  77. ご清聴ありがとうございました。

    View Slide

  78. Webエディタ開発を
    支える技術
    Muddy Web #4
    Speaker: Hirai Shuta
    2023 / 01.19

    View Slide