zfb を動かす 3 つの方法
1 つの Request/Response アプリケーションと 3 つの実行形態 — ビルド時に静的 HTML へプリレンダリングする、リクエスト時に Cloudflare Workers で配信する、別のプログラムの内側でローカルコンテンツサーバーとして動かす。
このページで扱う内容
zfb はあなたのページを、単一のコントラクト — Request/Response ハンドラ — を持つ 1 つの アプリケーションにコンパイルし、その同じアプリケーションを 3 つの方法で動かします。静的 HTML へのプリレンダリング、Cloudflare Workers での配信、そして別のプログラムの内側での ローカルコンテンツサーバーとしての起動です。
そもそも zfb がプロジェクトに合うかどうかは zfb を選ぶ を、 ビルド時のパイプラインの詳細は アーキテクチャ概要 を、 本番の SSR が実際にどう見えるかは Worker 上の SSR を読んでください。
1 つのアプリケーションコントラクト
生成されるアプリケーションは Request/Response ハンドラを公開します。ビルドを実行すると、 esbuild はあなたの TSX ページ・レイアウト・コンポーネントを、Cloudflare Workers モジュールの 形をした単一のワーカーバンドルにコンパイルします。
export default {
fetch(request: Request, env: Env, ctx: ExecutionContext): Response { ... }
};ページコンポーネントが自分で fetch を実装することはありません。それらは通常の関数のままで、 ハンドラを担うのは周囲のバンドルです。そのハンドラがコントラクトのすべてであり、3 つの実行形態が 共通して持つものです。
このコントラクトを固定していることが、3 つの形を 3 つの製品ではなく 1 つの製品にしています。 同じバンドルが、ビルド時には合成リクエストで、リクエスト時には実際のリクエストで駆動されます。 両者を行き来してもアプリケーション側は何も変わりません。
1 つのアプリケーションコントラクト
export default { fetch(request, env, ctx) }
|
+------------------------+------------------------+
| | |
組み込み V8 workerd zfb dev
ビルド時 リクエスト時 別のプロセスの内側
| | |
dist/ の静的 HTML prerender = false の ループバックポート上の
SSR レスポンス ライブページ実行形態 1 静的ビルド
zfb build はワーカーバンドルを組み込み V8 アイソレートにロードし、ページ URL ごとに 1 つの 合成リクエストで駆動します。各レスポンスはプレーンな .html ファイルとして dist/ に 書き出され、ビルドが終わるとアイソレートは破棄されます。
出来上がるのはファイルのディレクトリです。それは Cloudflare Workers Static Assets の デプロイにそのまま投入できます。管理すべきサーバーランタイムも、設定すべきサーバーレス関数も、 アダプター層もありません。ビルドされた dist/ がデプロイの成果物そのものです。
このドキュメントサイトがその例です。いま読んでいるすべてのページはビルド時にレンダリングされ、 ファイルとして配信されています。
実行形態 2 Cloudflare Workers 上の SSR
リクエストごとに実行しなければならないルート — データベースの読み取り、セッションクッキーの 確認、POST の処理 — は、1 つのエクスポートでプリレンダリングから抜けます。
export const prerender = false;@takazudo/zfb-adapter-cloudflare を設定すると、zfb build は 2 つのファイルを出力します。 小さな生成スタブである dist/ と、実体のアプリケーションバンドルである dist/ です。スタブは (env, ctx, request) を保持する AsyncLocalStorage の スコープを開き、実際に受け取ったリクエストを env.ASSETS 経由の静的アセットサーバーか、 内側のバンドルのどちらかにディスパッチします。ページの内側では getCloudflareContext() が そのスコープを読むので、Cloudflare のバインディングは prop-drilling なしに任意のレイアウトや ヘルパーへ届きます。
バンドルを実行するエンジンは変わります — 組み込み V8 ではなく workerd です — が、 アプリケーションは変わりません。
制限ははっきり書いておく価値があります。
アダプターは Cloudflare だけです。 zfb が提供するのは
@takazudo/zfb-adapter-cloudflareのみで、他にはありません。検証済みのデプロイ先は Workers Static Assets です。 Cloudflare Pages のアドバンスト モードはこのアダプターについて未検証なので、ここに書かれていることはそのサポートを主張する ものではありません。
デプロイされる Worker には、インクリメンタル静的再生成(ISR)も React Server Components も、リクエスト時のミドルウェア層もありません。 ルートはビルド時にプリレンダリングされるか、 リクエストごとに処理されるかのどちらかで、その中間はありません。
メンタルモデルは Worker 上の SSR を、実際のセットアップ — wrangler.toml、compatibility_flags、D1 のクエリ — は SSR と Cloudflare バインディング を 読んでください。
実行形態 3 ローカルコンテンツサーバー
3 つめの形は、何もデプロイしません。ホストプログラムが zfb バイナリを子プロセスとして起動し、 ループバックポートにバインドした zfb dev を走らせて、自分の UI をそのポートに向けます。
これを現実的にしているのは、プロセスが小さいままであることです。plugins: [] の config は Node のプラグインホストを一切起動しません。標準の組み込み V8 ビルドでは、config 自体も バイナリに同梱された V8 アイソレートがインプロセスで評価します。スリムビルドはその評価器を コンパイル対象から外し、代わりに node のサブプロセスで config を評価するため、 PATH 上の node を必要とします。
あとはホストがファイルを書くことでコンテンツを駆動します。プログラムの他の部分がコンテンツ ツリーへ MDX を生成し、zfb dev のコンテンツウォッチャーがその変更を拾って、影響を受ける ページをホットリロードします。
CCResDoc がその実例です。ローカルのファイルを MDX に 変える Rust のジェネレーターとウォッチャーを Tauri のシェルで包んだもので、起動時に設定で 選ばれたループバックポート上でネイティブの zfb バイナリを起動します。起動は非同期なので、 その後は実際のページ — GET /docs/ — を、レスポンスが成功しかつ期待するシェルを含むまで ポーリングします。素の 200 を準備完了と見なしたりはしません。
この形は意図的にサポートされています。同時に用途は狭いので、これが何ではないかもはっきり させておきます。
本番の HTTP サーバーではありません。
zfb devは開発サーバーであり、ここでは 1 台の マシンのプロセスツリー内のループバックで使われています。認証も認可もありません。 サーバーがレンダリングできるものは、ローカルのどのクライアント からでも読めます。
インプロセスのライブラリ API ではありません。 ホストが持つのは子プロセスと 1 つの ポートです。サーバーを自分のプロセスの内側に置きたい Rust ホストは
zfb-serverビルダーを 使えます — ライブラリとして組み込む を参照 — が、それは 別の経路であり、クレートは crates.io に公開されておらず、CCResDoc がやっていることでも ありません。
主張はコントラクトであって Rust ではない理由
Rust はここで実際の仕事をしています。ファイルスキャン、依存グラフ、ビルドの オーケストレーション、インクリメンタルリビルド、V8 のホスティングを高速にし、 インストールすべきランタイムツールチェーンなしに、エンジン全体を 1 つのバイナリとして 配布できるようにしています。
しかし Rust は主張ではありません。それはエンジンが速い理由であり、配布の形でもありますが、 3 つの形をひとつにまとめているものではありません。まとめているのはコントラクトです。 アプリケーションが Request/Response ハンドラであってそれ以上ではないからこそ、ビルド時の ホスト、本番のホスト、そしてローカルコンテンツサーバーは、名前を共有するだけの 3 つの別製品 ではなく、1 つのものを駆動する 3 つのドライバーになります。
次に読むもの
zfb を選ぶ — この形のツールがあなたのプロジェクトに合うかどうか。
アーキテクチャ概要 — ビルド時とブラウザの分離、そして ビルド時パイプラインの全体。
Worker 上の SSR — 本番での 2 層のワーカー出力とリクエストの ディスパッチ。
エンジンとフレームワーク — zfb がコミットする 6 つの プリミティブと、エンジンの外側にあるもの。