Note
これはclaude codeが作成したドキュメントです。 間違いが含まれている可能性があることに留意してください
LustreはGleam言語で実装された、Erlang/JavaScriptの両ターゲットで動作する、型安全なWebフレームワークです。このドキュメントでは、Lustreのレンダリングアーキテクチャとプロセスについて詳しく解説します。
/src/lustre.gleam- アプリケーションコンストラクタを提供するメインエントリーポイント(element,simple,application,component)/src/lustre/element.gleam- HTML要素を作成するための公開API/src/lustre/vdom/vnode.gleam- Virtual DOMノードの定義/src/lustre/vdom/diff.gleam- Virtual DOM差分検出アルゴリズム/src/lustre/vdom/patch.gleam- パッチデータ構造/src/lustre/vdom/reconciler.ffi.mjs- DOM調整処理(JavaScript実装)
view(model) -> Element(msg)- ユーザー定義のビュー関数。Virtual DOMを生成diff(cache, old, new) -> Diff(msg)- 2つのVirtual DOMツリーを比較Reconciler.push(patch, memos)- 実際のDOMにパッチを適用
Lustreは複数のノードタイプを持つ洗練されたVirtual DOM(VDOM)実装を提供します。
/src/lustre/vdom/vnode.gleamより:
pub type Element(msg) {
Fragment(kind, key, children, keyed_children)
Element(kind, key, namespace, tag, attributes, children, keyed_children, self_closing, void)
Text(kind, key, content)
UnsafeInnerHtml(kind, key, namespace, tag, attributes, inner_html)
Map(kind, key, mapper, child) // メッセージマッピング用
Memo(kind, key, dependencies, view) // メモ化用
}- Keyedチルドレン: キー付き要素による効率的なリスト更新(
MutableMapに保存) - メモ化:
Memoノードは依存関係の参照等価性を使用して高コストな計算をキャッシュ - メッセージマッピング:
Mapノードはコンポーネント合成のための独立したイベントサブツリーを作成 - 文字列レンダリング: SSR用に
to_string()とto_string_tree()でHTML文字列へのレンダリングが可能
Lustreは複数のコンポーネントタイプをサポートします。
- シンプルなビュー関数 -
Element(msg)を返す通常のGleam関数 - ステートフルコンポーネント -
init,update,viewを持つ完全なMVUアプリケーション - Webコンポーネント - Shadow DOMを使用するカスタムエレメント
- サーバーコンポーネント - サーバー上で実行し、パッチをクライアントにストリーミング
/src/lustre/component.gleamより、コンポーネントは以下で設定可能:
- 属性オブザーバー(
on_attribute_change) - プロパティオブザーバー(
on_property_change) - コンテキストプロバイダー/コンシューマー(
on_context_change) - Shadow DOM設定(
open_shadow_root,adopt_styles) - フォーム関連付け(
form_associated) - コンテンツプロジェクション用スロット(
default_slot,named_slot)
/src/lustre/runtime/client/より:
Runtimeインスタンスを作成- マウント時に既存DOMを仮想化
requestAnimationFrameで更新ループを実行- パッチを同期または一括で適用
constructor → mount → #render → diff → reconcile → paint
synchronous- 更新中に即座に実行before_paint- ブラウザペイント前のマイクロタスクで実行after_paint- ブラウザペイント後に実行
element.to_string()またはelement.to_document_string()を呼び出し- HTML文字列を直接生成
- ランタイム不要
- Erlang/Node/Deno上で実行
- サーバーサイドでVDOM状態を維持
- 各更新で差分検出
- WebSocket経由でJSONパッチを接続クライアントに送信
- クライアントは最小限のランタイムでパッチを適用
/src/lustre/runtime/transport.gleamより:
Mount- 初期VDOMと設定Reconcile- 適用するパッチEventFired- クライアントからのユーザーインタラクションAttributeChanged/PropertyChanged- クライアントからContextProvided- コンテキストインジェクション
/src/lustre/vdom/diff.gleamより、diff()関数は洗練された調整アルゴリズムを実装:
- 子要素リストを順番に比較
- キー付き子要素を特別な移動処理で扱う
- 最小限の変更セットを生成
/src/lustre/vdom/patch.gleamより:
pub type Change(msg) {
ReplaceText(content)
ReplaceInnerHtml(inner_html)
Update(added, removed) // 属性
Move(key, before) // キー付き子要素
Replace(index, with) // ノード置換
Remove(index) // ノード削除
Insert(children, before) // ノード挿入
}アルゴリズムが追跡するもの:
moved- 再配置されたキーmoved_offset- 移動を考慮したオフセットremoved- 削除された子要素の数
これにより、最小限のDOM操作で効率的なリスト調整が可能。
Patch(
index: Int, // 子要素のインデックス
removed: Int, // 削除する子要素数
changes: List(Change), // このノードへの操作
children: List(Patch) // 再帰的なパッチ
)/src/lustre/vdom/reconciler.ffi.mjsより、reconcilerは:
- DOMと並行してメタデータツリーを維持
- イベントハンドラー、スロットル、デバウンサーを保存
- パッチツリーを深さ優先で走査
- 正確性のため変更を逆順で適用
- 利用可能な場合
moveBeforeAPIを使用(新しいDOM機能) - デバウンス/スロットルタイマーを管理
[ユーザーアクション]
↓
[エフェクトディスパッチ] または [イベント発火]
↓
[update(model, msg)] → #(new_model, Effect(msg))
↓
[view(new_model)] → Element(msg)
↓
[diff(cache, old_vdom, new_vdom)] → Diff
↓
[パッチをJSONにエンコード](サーバーコンポーネントのみ)
↓
[Reconciler.push(patch, memos)]
↓
[パッチツリーを走査、変更を適用]
↓
[DOM更新]
↓
[before_paintエフェクト] → queueMicrotask
↓
[ブラウザペイント]
↓
[after_paintエフェクト] → requestAnimationFrame
- イベントはShadow DOMを通じてバブルアップ
- Reconcilerがメタデータノードでキャプチャ
- パス経由でハンドラーを検索(例:
"0\t1\tbutton\nclick") - 設定されている場合、デバウンス/スロットルを適用
- イベントデータをデコード
- update関数にメッセージをディスパッチ
/src/lustre/vdom/cache.gleamより、キャッシュは以下を維持:
- イベントハンドラーツリー(Map分離あり)
- メモ化されたVDOMノード
- ディスパッチされたイベントパス(制御された入力用)
- 依存関係比較用の古いメモ
<input>, <select>, <textarea>の特別な処理:
- どのパスがイベントをディスパッチしたかを追跡
- ユーザーが操作した場合、属性更新を強制
- カーソルジャンプと値の上書きを防止
- ユニバーサルコンポーネント: 同じコードがクライアント/サーバー/スタンドアロンで動作
- 効率的なキー付き差分検出: 動的リストのDOM操作を最小化
- メモ化: 参照等価性チェックで高コストな再レンダリングをスキップ
- エフェクトバッチング: ブラウザペイントサイクル周辺のスマートスケジューリング
- イベント分離: Mapノードが安定したイベントサブツリーを作成
- サーバーコンポーネント: 最小限のクライアントランタイムでWebSocket経由の更新ストリーミング
- 型安全性: GleamのタイプシステムによるErlangとJavaScriptターゲット全体での強力な型付け
このアーキテクチャは、開発者の使いやすさとErlang・JavaScriptターゲット全体での型安全性を維持しながら、優れたパフォーマンスを提供します。
- リポジトリ: https://github.com/lustre-labs/lustre
- バージョン: v5.5.2
- 調査日: 2026-01-24