Slide 1

Slide 1 text

Webエディタライブラリ 「CodeMirror」から学ぶ Webアプリ開発のテクニック 2024.7.5 新規事業部 Zennチーム Igarashi

Slide 2

Slide 2 text

Xへの投稿の際は、 ハッシュタグ #devio2024 でお願いいたします。 2 お願い

Slide 3

Slide 3 text

Igarashi Ryosuke ● 2015/7⼊社 ● CX事業本部(旧モバイルアプリサービス 部)でバックエンド‧インフラを担当 ● 2021/6より新規事業部 Zennチーム ● フロントエンドもやってますが何もわから ない ⾃⼰紹介 3

Slide 4

Slide 4 text

はじめに 4

Slide 5

Slide 5 text

とは Zennは「知見を共有するエンジニアに対価を」 というコンセプトでつくられた 技術情報共有コミュニティです。 5

Slide 6

Slide 6 text

3種類の投稿形式で、その時々に合った粒度で知見を残すことができます ひとまず 雑にメモ したい あのテーマ で誰かと 議論したい 最近学んだ あの話を記事 にしよう 労力が かかった分 有料で販売 しよう あの話を まとめて 本にしよう 6

Slide 7

Slide 7 text

著者が金銭的な対価を受け取れる仕組み 知見をまとめて 有料の本として 販売してみよう 応援したい 著者には 有料のバッジ を贈ろう バッジを受け取った著者に 分配金が支払われます 7

Slide 8

Slide 8 text

8 8

Slide 9

Slide 9 text

catnose さんが個人プロジェクトとしてリリース 運営会社がクラスメソッド株式会社に 2020年9月 2021年6月 5人の小さなチームで運営中 現在 のこれまで 9 企業運営になってからも自分たちがワクワクすることに積極的に取り組むスタンスは変わって いません。ほぼすべての意思決定はチームメンバーだけで行われており、メンバー一人ひとり のアウトプットがサービスの質に直結します。

Slide 10

Slide 10 text

本編 10

Slide 11

Slide 11 text

最近のエディタ周りのアップデート 11

Slide 12

Slide 12 text

ZennのMarkdownエディタの作り⽅ アップデートで⾏ったことはほとんどすべて「Zenn Tech Blog」で公開しています。 12

Slide 13

Slide 13 text

お話すること CodeMirrorの実装からわたしが学んだこと‧興味深 かったこと伝えします。 🚀 パフォーマンス最適化 🚀 状態管理のアーキテクチャ 🚀 拡張性 13

Slide 14

Slide 14 text

CodeMirrorの実装からわたしが学んだこと‧興味深 かったこと伝えします。 🚀 パフォーマンス最適化 🚀 状態管理のアーキテクチャ 🚀 拡張性 収まりきらなかったので記事として書きます 󰢛 お話すること 14

Slide 15

Slide 15 text

注意‧免責事項 ● 本スライドの内容はCodeMirrorのドキュメント やソースコードを参考に作成していますが、正確 ではない可能性があります。 ● 本スライドの内容はCodeMirror v6に関する内容 です。v6はv5以前とは実装が全く異なりますので ご注意ください。 15

Slide 16

Slide 16 text

ZennのエディタとCodeMirror 16

Slide 17

Slide 17 text

ZennのMarkdownエディタ ZennのMarkdownエディタはCodeMirrorというライ ブラリをベースに、多数のカスタマイズを加えてい ます。 17

Slide 18

Slide 18 text

ZennのMarkdownエディタ 18

Slide 19

Slide 19 text

ZennのMarkdownエディタ 19 Markdown記法の デコレーション URLをペーストで自動 的にリンク生成 画像をD&Dでアップ ロード・リンク生成 ショートカットキーによる Markdown記法の挿入 (太字・斜体など) SlackライクなEmojiの 入力補完

Slide 20

Slide 20 text

CodeMirrorとは “CodeMirrorは、Web⽤のコードエディターコン ポーネントです。多くの編集機能をサポートするテ キスト⼊⼒フィールドを実装でき、さらなる拡張を 可能にする豊富なプログラミング インターフェイス を備えています。”(翻訳) 20 引用: https://codemirror.net/

Slide 21

Slide 21 text

Features 21 - Modularity - Speed - Bracket Closing - Linting - Flexible Styling - Theming - Collaborative Editing - Undo History - Multiple Selections - Internationalization ...and more - Accessibility - Mobile Support - Bidirectional Text - Syntax Highlighting - Line Numbers - Autocompletion - Code Folding - Search/Replace - Full Parsing - Extension Interface

Slide 22

Slide 22 text

Language Support 公式がサポートする⾔語。 この他に、コミュニティが作成した⾔語サポートも あります。 22

Slide 23

Slide 23 text

ちなみに   ProseMirrorという、Notionライクなブロック ベースのエディタライブラリもあります。 ラッパーライブラリとして や などが有名です。 作者はCodeMirrorとおなじ⽅です。 23

Slide 24

Slide 24 text

ブロックエディタのトレードオフ 良いところ ● プレビュー不要 ● リッチな表現をUIで実現できる ⼤変なところ ● 編集‧表⽰の2つのモードの実装が必要 ● 細かい挙動の調整 24

Slide 25

Slide 25 text

質問✋ 技術記事を書く時に使いたいエディタはどっち? (A)Markdownベースの「テキストエディター」 (B)Notionライクな「ブロックエディター」 25

Slide 26

Slide 26 text

🚀パフォーマンス最適化 26

Slide 27

Slide 27 text

基礎知識 27 このテキストエディタのHTMLはどのようになって いるでしょうか?

Slide 28

Slide 28 text

基礎知識 28 contenteditable=”true”により、 divやspanのテキストが編集可能に 1⾏⽬ 2⾏⽬ 3⾏⽬ class指定による ハイライトの装飾

Slide 29

Slide 29 text

仮想スクロール ⼤量のデータをブラウザにレンダリングする際に、可視範囲 のDOMだけを動的に⽣成することで、レンダリングにかかる 時間を⼩さくしてパフォーマンスを向上させるテクニック。 動的な変数をもとにレイアウト(描画範囲)を決定する。 ● エディタの⾼さ ● 1⾏あたりの⾼さ ● スクロール位置 ● その他 29

Slide 30

Slide 30 text

仮想スクロール 30 例えばこんなCSS div.outer { height: 500px; overflow: auto; } div.inner { height: 10000px; }

Slide 31

Slide 31 text

仮想スクロール トレードオフ ● DOMが⽣成されていない部分はブラウザ検索が 効かない(別途実装が必要) ● など 31

Slide 32

Slide 32 text

レイアウト計測はコストが⼤きい テキストの⽂法解析 ↓ テキストを構造化 ↓ テキストのデコレーションや様々な状態を適⽤ ↓ ようやくレイアウトが計測できる 32

Slide 33

Slide 33 text

レイアウト計測はコストが⼤きい 変数が変わるたびに1フレーム内で何度もレイアウ ト計測を実⾏してしまうとフレーム落ちが発⽣する 👉 requestAnimationFrameを使う 33

Slide 34

Slide 34 text

requestAnimationFrameとは CSSなどでは表現が難しいアニメーションを、 JavaScriptからブラウザのリフレッシュレートにあ わせてスムーズに描画するためのAPIです。 34

Slide 35

Slide 35 text

ブラウザのレンダリングサイクル ● ブラウザはMainスレッドでレ ンダリングを⾏う ● 初回は全部通りますが、2回 ⽬以降は差分更新 ● 余った時間でクライアント JavaScriptの実⾏も⾏う 35 https://web.dev/learn/performance/understanding-the-critical-path?hl=ja

Slide 36

Slide 36 text

フレーム落ちとは ● 処理時間が⻑いJavaScriptがあると、レンダリン グタイミングが数フレームに1回になる。 ● 50ms以上かかるタスクは分割したほうが良いと されています。 36 https://web.dev/articles/long-tasks-devtools?hl=ja

Slide 37

Slide 37 text

フレーム落ちとは ● requestAnimationFrameを使うことで、処理を フレームの先頭に先送りする。 37

Slide 38

Slide 38 text

requestAnimationFrameの例 アニメーションの場合、 コールバック関数の中で 再帰呼び出しをして、差 分時間から移動距離を算 出する 38 引用: https://developer.mozilla.org/ja/docs/Web/API/windo w/requestAnimationFrame 再帰的に呼び出し 呼び出された時間 開始からの経過時間 時間から移動距離を測る

Slide 39

Slide 39 text

requestAnimationFrameの例 39 フレームごとにrequestAnimationFrameの コールバックが実行される

Slide 40

Slide 40 text

CodeMirrorの場合 エディタの状態が更新された時 ● テキストのDOM更新は即座に⾏う。 ● レイアウト計測はrequestAnimationFrameで次 のフレームの先頭で⾏い、仮想スクロールを更新 40 引用: https://github.com/codemirror/view/blob/6.28.4/src/editorview.ts#L67-L72

Slide 41

Slide 41 text

ハイライトもコストが⼤きい テキストの⽂法解析 ↓ テキストを構造化 ↓ テキストの選択範囲や様々な状態を反映 41

Slide 42

Slide 42 text

ハイライトもコストが⼤きい これらをDOM更新と同じタイミングで実⾏するとコ ストが⼤きいのでフレーム落ちが発⽣する可能性が ある。 👉 setTimeout/requestIdleCallbackを使う 42

Slide 43

Slide 43 text

setTimeoutとは 指定した時間が経過した後にコールバックを実⾏す るAPIです。 ブラウザ環境においては、setTimeoutの待ち時間の 間、ブラウザの処理を実⾏することができる。 43

Slide 44

Slide 44 text

requestIdleCallbackとは ブラウザのスレッドがアイドル状態のときに実⾏さ れる関数をキューイングできます。優先度が低くコ ストが⼤きい処理をさせるのに有効です。 44

Slide 45

Slide 45 text

requestIdleCallbackとは 45 ただし、Safariはまだ⾮対応です。

Slide 46

Slide 46 text

CodeMirrorの場合 requestIdleCallbackが⾮対応環境 ● setTimeoutで500ms遅延 requestIdleCallbackが対応環境 ● setTimeoutで100ms遅延 ● requestIdleCallbackで0~400ms遅延 46

Slide 47

Slide 47 text

CodeMirrorの場合 47 IdleCallbackで解析 レイアウト 計測して レンダリン グ 大量のコード をペースト 100ms

Slide 48

Slide 48 text

まとめ 48 ● 仮想スクロールは⼤量のデータをパフォーマンス を落とすことなくレンダリングするテクニック。 ● レンダリングコストが⼤きい処理はブラウザに⽤ 意されたAPIを⽤いて遅延実⾏させることでフ レーム落ちを抑える。 ○ requestAnimationFrame ○ setTimeout ○ requestIdleCallback

Slide 49

Slide 49 text

おわりに 49

Slide 50

Slide 50 text

おわりに ● CodeMirrorの実装から学んだ、広く活⽤できそ うな知識‧テクニックをお話しました。 ● なにかのお役に⽴てれば幸いです。 ● 素晴らしいライブラリと作者に感謝します。 50

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

52