React Server Components(RSC)ストリーミングSSRとCloudflare Edge SSRアーキテクチャ実践パターン

React Server Components(RSC)ストリーミングSSRとCloudflare Edge SSRアーキテクチャ実践パターン
モダンなウェブフロントエンドアーキテクチャは、クライアントサイドレンダリング(CSR)からサーバーサイドレンダリング(SSR)、そして現在では React Server Components(RSC) と ストリーミングSSR(Streaming SSR) の時代へと進化しました。
従来のSSRには、サーバーでページ全体のHTML生成が完了するまでブラウザが何も描写できないというTTFB(Time to First Byte)のボトルネックが存在しました。RSCとストリーミングSSRを活用すると、サーバー側の処理が完了したHTMLチャンクから順次ブラウザへリアルタイムにストリーミング送信できます。
ここに Cloudflare Workers のようなエッジ(Edge)ランタイムを組み合わせることで、ユーザーに最も近いPoP(Point of Presence)からコールドスタートほぼゼロでストリーミングレンダリングを開始できます。本記事では、このアーキテクチャの原理と実装の実践パターンを詳しく解説します。
1. 従来のSSR vs RSCストリーミングSSRの比較
従来のSSRとRSCベースのストリーミングSSRの主な違いは、データ取得およびHTML配信パイプラインにあります。
| 区分 | 従来のSSR | RSC + ストリーミングSSR |
|---|---|---|
| レンダリング単位 | ページ全体 (All-or-Nothing) | Suspense境界に基づくチャンク単位 |
| TTFB (Time to First Byte) | 全てのDBクエリが完了するまで待機(遅い) | シェルHTMLを即座に返し、超高速なTTFBを実現 |
| バンドルサイズ | サーバー描画コンポーネントのJSライブラリもクライアントへ送信 | サーバー専用コンポーネントのコードはクライアントバンドルから完全除外 |
| ハイドレーション | DOM全体のハイドレーションが必要 | 必要なクライアントコンポーネントのみ選択的(Selective)ハイドレーション |
2. SuspenseとReact DOM Server Streaming API
React 18/19の renderToReadableStream APIを使用すると、Node.jsのバッファリングなしにWeb Standard StreamベースでHTMLチャンクを順次送信できます。
実践コード:RSCストリーミングパイプライン
以下は、React Server ComponentsとSuspenseを組み合わせてストリーミングSSRを実現する例です。
// Server Component: 非同期データ取得を行う重いコンポーネント
async function SlowRecommendedProducts() {
// 1.5秒かかるデータ取得
const products = await fetchProductsFromDB();
return (
<div className="recommendations">
{products.map((p) => (
<ProductCard key={p.id} product={p} />
))}
</div>
);
}
// Main Page Component
export default function ProductDetailPage({ params }: { params: { id: string } }) {
return (
<main className="product-page">
{/* シェル領域: 即座にストリーミング送信 */}
<ProductHeader id={params.id} />
{/* 重い領域: フォールバックUIを先に送り、完了次第HTMLを置き換えストリーミング */}
<React.Suspense fallback={<ProductSkeleton />}>
<SlowRecommendedProducts />
</React.Suspense>
</main>
);
}
3. Cloudflare Workers Edge SSR パイプライン
Cloudflare WorkersはV8 Isolate上で動作し、重いNode.jsのオーバーヘッドなしに世界300拠点以上のエッジデータセンターでSSRを実行します。
[User Browser]
│ 1. HTTP Request
▼
[Cloudflare Edge Worker (V8 Isolate)]
│ 2. Fast Shell HTML Stream (0~10ms)
├──────────────────────────────────────────► [Browser Render Shell]
│ 3. Async Fetch DB/Cache (D1 / Hyperdrive)
│ 4. Stream Suspense Chunks via HTTP/2
└──────────────────────────────────────────► [Browser Replace Skeleton]
Worker Entry Point の実装例
import { renderToReadableStream } from 'react-dom/server';
import App from './App';
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// React 18/19 Web Stream API を利用してエッジでストリーミング描画
const stream = await renderToReadableStream(<App url={url.pathname} />, {
onError(error) {
console.error('Streaming SSR Error:', error);
},
});
// HTTP/2のDATAフレームストリーミングで即座に応答を返却
return new Response(stream, {
headers: {
'content-type': 'text/html; charset=utf-8',
'cache-control': 'no-transform',
},
});
},
};
4. 実践最適化のコツ:エッジキャッシュと選択的ハイドレーション
- Static Shell のエッジキャッシュ: ヘッダーやレイアウトなどの静的シェルはCloudflare Workers KVやCache APIで1次キャッシュし、動的RSCデータのみをストリーミングします。
- エッジDBコネクション統合 (Hyperdrive / D1): エッジからメインDB(PostgreSQL等)へのアクセス時のレイテンシを抑えるため、Cloudflare Hyperdriveを活用します。
- Client Component の最小化:
'use client'指示子は、インタラクション(onClickやuseState)が必要な最末端のノードのみに限定して使用します。
まとめ
RSCストリーミングSSRとCloudflare Edgeの組み合わせは、Webパフォーマンスを極限まで高める最新のアーキテクチャです。
[!NOTE]
- Suspense境界を適切に設定し、ページシェルが即座に返答するように設計してください。
- Node.js固有のAPIではなく
renderToReadableStreamを活用し、エッジランタイムでの互換性を確保しましょう。- Cloudflare Workersでユーザーに一番近いPoPから描画ストリーミングを行い、体感TTFBを最小化します。
このパターンを導入することで、クライアントJSバンドルサイズを縮小しながら、全世界のユーザーに高速でスムーズな体験を提供できます。