アーキテクチャ

01. ページ表示をcoreの実装から追う

アプリケーションの定義からブラウザーでの表示まで、Effront の実装全体を読むための案内。

ページ表示には、再利用するアプリケーション定義、リクエストが所有するサービス、ブラウザーへ送るデータが関わります。 それぞれの寿命は異なります。Routesのコンパイルはサービスを取得せず、Flightの描画はサーバーのContextをクライアントへ引き渡しません。

定義・リクエスト・ブラウザーの入口を見つける

  1. 定義:既定の src/entry.effront.tsx がアプリケーションをdefault exportします。 Viteはこれを @effront/core/application-entry として公開します。application/definition.tsx の makeApplication はRoutesをコンパイルし、サービスのLayerを構築せずに保持します。
  2. リクエスト:ホストが定義を @effront/core/http へ接続します。workers.ts は、このネイティブなEffect HTTPの境界をFetchに適合させます。 ホスト共通のVite統合では、ホスト側が別の入口を選ばなければ、RSCエントリに src/entry.workers.ts を使います。
  3. ブラウザー: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は、取得中にそのリクエストのホスト値を参照できます。 ハンドラーを再利用しても、アプリケーションサービスのインスタンスをリクエスト間で共有することにはなりません。

  1. 照合:server/application.ts がコンパイル済みの描画先をEffect HTTPへ登録し、サービスとmiddlewareを結び付けます。
  2. 検証:パラメーター付きPageへのGETでは、照合したパラメーターを描画前にデコードします。 Schemaのデコード失敗は404になります。 POSTでは代わりにServer Functionを準備して実行します。
  3. 描画:renderRouteTree がルートツリーを作り、FlightRenderer がReactのFlightストリームを生成します。
  4. 応答:Accept ヘッダーが FlightMediaType と完全に一致すればFlightを選びます。 それ以外では HtmlRenderer がSSRエントリを読み込み、同じストリームをHTMLへ変換します。
  5. 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でホストします。

次に追う処理を選ぶ