アーキテクチャ
01. ページ表示をcoreの実装から追う
アプリケーションの定義からブラウザーでの表示まで、Effront の実装全体を読むための案内。
ページ表示には、再利用するアプリケーション定義、リクエストが所有するサービス、ブラウザーへ送るデータが関わります。 それぞれの寿命は異なります。Routesのコンパイルはサービスを取得せず、Flightの描画はサーバーのContextをクライアントへ引き渡しません。
定義・リクエスト・ブラウザーの入口を見つける
- 定義:既定の
src/entry.effront.tsxがアプリケーションをdefault exportします。 Viteはこれを@effront/core/application-entryとして公開します。application/definition.tsxのmakeApplicationはRoutesをコンパイルし、サービスのLayerを構築せずに保持します。 - リクエスト:ホストが定義を
@effront/core/httpへ接続します。workers.tsは、このネイティブなEffect HTTPの境界をFetchに適合させます。 ホスト共通のVite統合では、ホスト側が別の入口を選ばなければ、RSCエントリにsrc/entry.workers.tsを使います。 - ブラウザー:
client/entry.tsがBrowserRuntime.runMainを通じてbrowserMainを実行します。 アプリケーションのサーバーサービスをimportするのではなく、Flightからドキュメントをhydrateします。
リクエストからドキュメントの表示まで追う
createFetchHandler はWebハンドラーを再利用し、呼び出しごとに新しい WorkersRequestContext を渡します。
packages/core/src/workers.ts の抜粋 const handler = HttpEffect.toWebHandler(toHttpEffect(application));
return (request, env, executionContext) =>
handler(request, Context.make(WorkersRequestContext, { env, executionContext, request }));http.ts の toHttpEffect は評価ごとに新しいLayerのmemo mapを作り、現在のリクエストContextで ServerApplication.httpLayer(application) を構築します。 アプリケーションのLayerは、取得中にそのリクエストのホスト値を参照できます。 ハンドラーを再利用しても、アプリケーションサービスのインスタンスをリクエスト間で共有することにはなりません。
- 照合:
server/application.tsがコンパイル済みの描画先をEffect HTTPへ登録し、サービスとmiddlewareを結び付けます。 - 検証:パラメーター付きPageへのGETでは、照合したパラメーターを描画前にデコードします。 Schemaのデコード失敗は404になります。 POSTでは代わりにServer Functionを準備して実行します。
- 描画:
renderRouteTreeがルートツリーを作り、FlightRendererがReactのFlightストリームを生成します。 - 応答:
AcceptヘッダーがFlightMediaTypeと完全に一致すればFlightを選びます。 それ以外ではHtmlRendererがSSRエントリを読み込み、同じストリームをHTMLへ変換します。 - hydration:
client/application.tsが初期Flightペイロードを読み込み、ドキュメントをhydrateし、refreshとServer Functionの処理を登録します。 クライアントルーターを登録するのは、navigationModeが"Client"の場合だけです。
描画が終わる前に応答ヘッダーが届くことがあります。 Effect HTTPのWebハンドラーは、ストリーム本文の完了・失敗・キャンセルまでリクエストのScopeを維持します。 HEADでは本文を消費しないため、ハンドラーとネイティブホストがヘッダーを維持したままストリームを破棄し、Scopeを解放します。makeHttpEffect で借りたサービスはホストの所有物のままであり、ホストはそれを使うすべての応答本文が終わるまで維持する必要があります。 この所有権の境界は リクエスト処理 で説明します。
各段階を担当するコードを見つける
以下は packages/core/src からの相対パスです。
application/:定義のidentity、サービスの契約、ルートのコンパイル。http.tsとserver/application.ts:リクエストごとの取得、HTTPの振り分け、middleware、応答の選択。rsc/とserver/のレンダラー:ルートツリーの契約、Flightの生成、HTMLの描画。client/:hydration、遷移、refresh、Server Functionの呼び出し。
実行環境は統合パッケージが担当します。packages/vite/src/index.ts はReact/RSCプラグイン、アプリケーションのalias、ブラウザー・RSC・SSRのエントリを設定します。 CloudflareアダプターはRSCとその子SSR環境をworkerdで実行します。@effront/server は、分離したRSCとSSRのグラフをNode.jsまたはBunでホストします。
次に追う処理を選ぶ
- リクエストの前:アプリケーション定義 と ルートの組み立て は、再利用する定義が保持する内容を説明します。
- リクエストの処理中:リクエスト処理 と 描画 は、サービスの取得から応答本文までを結び付けます。
- hydrationの後:ナビゲーション と Server Functions は、新しいFlightデータと表示中のUIを調整します。