/note/tech

Octane — React's programming model, compiled

要約:

■ 1. Octaneの概要

  • Octaneとは:
    • Reactのプログラミングモデルをコンパイルする後継フレームワーク
    • Infernoの後継であり、パフォーマンス最優先という目標を引き継ぐ
    • Reactのhooks、Suspense、actionsを事前コンパイルする
    • 仮想DOMを持たない
    • hooksのルールを持たない
    • 依存配列を手動管理する必要がなく、コンパイラがコードの参照先を解析する

■ 2. 主な特徴

  • hooksのルール撤廃:
    • 依存配列とhooksのルールが不要
    • コンパイラがeffect、memo、callbackが実際に使用する値を追跡する
    • hooksを条件分岐や早期returnの内側に置ける
  • 非同期処理の改善:
    • 独立したuse()呼び出しは、木構造を降りながら順番にサスペンドするのではなく同時に開始する
    • ネストしたfetchは早期にウォームアップされる
    • ストリーミングSSRは各バウンダリを準備でき次第送信する
  • 仮想DOMの不使用:
    • テンプレートはクローンされたノードと直接的なDOM書き込みにコンパイルされる
    • keyed @forリストは最小限のノード移動で済む
    • 通常の.tsxはそのまま動作し、.tsrxへコンポーネント単位で段階的に移行できる
  • 従来モデルとの親和性:
    • hooks、memo、context、portals、transitions、actions、controlled forms、Suspenseは期待通りに動作する
    • イベントはネイティブであり、refsは単なるpropsとして扱われる
    • 53種類のファーストパーティ製バインディングが既存ライブラリをカバーする
  • 目指す体験:
    • 速さはアプリの感じ方であるべきで、新しい思考法を強いるものではないとする立場

■ 3. Octaneへ移行する理由

  • Octaneコンポーネントの正体:
    • 既存のReactコンポーネントと同じく、hooks・props・contextを使うただの関数
    • Reactを知っていればOctaneも理解できる
    • 状態の所在やデータフローに関する既存の知識がそのまま通用する
  • 移行方法:
    • アプリ全体を書き直す必要はない
    • 既存のTSXを保持しつつ、コンポーネントを一つずつTSRXへ移行できる
    • コンポーネントの形が移行の前後で変わらないため、AIエージェントによる移行も、新しいリアクティブモデルへの再設計なしに可能

■ 4. signalsを採用しない理由

  • signalsに対する評価:
    • signals自体は優れた手段であり、適合する場面ではOctaneアプリ内でも使用可能
    • ただしsignalsを基盤とするフレームワークは、アプリ全体の状態表現・読み取り方法をsignals流に統一してしまう
  • Octaneの設計方針:
    • コンポーネントを上から下へ読める、ただの関数のまま保つ
    • 追加の作業はコンパイラ側が担い、コード側に負担をかけない

■ 5. 静かに失敗する落とし穴

  • 事前コンパイルゆえの特性:
    • Octaneは事前コンパイルのため、設定ミスは通常エラーにならず、動作が徐々に劣化する形で現れる
  • 具体的な落とし穴:
    • 1つのツリー内にランタイムが2つ存在すると、hooksとcontextが静かに壊れる
      • フックの状態はランタイムインスタンスごとにキー管理されているため
    • 素のtscは.tsrxファイルを正しく扱えず誤動作する
    • declare module '*.tsrx'のシムを使うと、自分のコンポーネントの型がanyになる
  • 対策:
    • octane doctorというコマンドが、これらの問題に対応する20項目のチェックを提供する

■ 6. OctaneCompatによる段階的移行

  • 既存React 19アプリへの導入:
    • 単一のコンポーネントを追加するだけで、コンパイル済みのOctane islandsを既存アプリに組み込める
    • イベントはネイティブかつdelegatedのまま扱われる
    • islandsは通常のuse()で実際のReact contextを読み取れる
    • サーバー側でレンダリングされ、クライアント側でhydrateされる
  • 移行の進め方:
    • コンポーネント単位で移行でき、書き直しや一斉切り替えは不要
  • 対応範囲の限界:
    • React Server Componentsだけは非対応
    • hooks、Suspense、context、SSRなどそれ以外の機能はすべて引き継がれる