
Summary
この文書の要点
- 静的生成できるページとクライアント実行が必要な機能を分ける。
- Nginxのfallback設定で存在しないURLの扱いを明確にする。
- ビルド成果物はコンテナに固定し、配信時に環境依存の生成を行わない。
- 静的HTML、assets、画像でキャッシュ戦略を分ける。
どこが設計の難所か
React Routerのアプリを静的サイトとして配信する場合、開発サーバーでは動いても、ビルド後の直接アクセスやリロードで404になることがあります。キャッシュ設定を誤ると、更新後も古いHTMLが残ります。
静的配信ではサーバーでリクエストごとの処理はできません。フォーム送信、認証、動的データ取得が必要な部分は外部APIや別サービスに分ける必要があります。公開サイトならSEOメタデータもビルド時に確認したいところです。
React Router SSGは、公開時には静的ファイルとして扱えるため運用が軽くなります。一方で、ビルド時に取得したデータや環境変数がHTMLへ焼き込まれるため、いつ何を生成したかを管理しないと更新漏れが起きます。
境界をどう切るか
ページごとに静的生成対象を定義し、Nginxでは生成済みHTMLを優先し、必要な場合だけSPA fallbackを使います。HTMLは短いキャッシュ、ハッシュ付きJS/CSSは長いキャッシュに分けます。
設計では、ビルドフェーズと配信フェーズを明確に分けます。Docker imageには生成済みのbuild/clientを入れ、Nginxや軽量サーバーは静的配信だけを担います。API呼び出しやデータ生成は配信時に持ち込まない方が安定します。
実装で効く細部
Dockerfileではビルドステージと配信ステージを分け、生成された`build/client`だけをNginxへコピーします。Nginx設定では、`try_files`、圧縮、キャッシュヘッダー、404ページを明示します。
Dockerfileは、依存インストール、ビルド、配信のマルチステージに分けます。ハッシュ付きassetsは長期キャッシュ、HTMLとsitemapは短期またはno-cacheにし、404やSPA fallbackの挙動も明示します。
- ビルド時に使う環境変数とブラウザへ露出する環境変数を分ける。
- Nginx設定では、存在しない静的ファイルとアプリ内ルートのfallbackを区別する。
- sitemapやrobotsはビルド成果物に含め、デプロイ後に差し替えない。
壊れ方を観測する
検証では、トップページ、下層ページ、存在しないURL、リロード、OGPメタ、アセットキャッシュを確認します。コンテナを起動してcurlやPlaywrightでビルド成果物を直接見ることが重要です。
検証では、Docker imageをローカルで起動し、代表ページ、404、リダイレクト、画像、OGPメタタグを確認します。ファイルを直接開いた時ではなく、実際の配信サーバー経由で見ることが重要です。
捨てた選択肢とトレードオフ
SSGは高速で安定しますが、更新のたびにビルドと配信が必要です。頻繁に変わるデータを扱う場合は、静的生成とAPI取得を組み合わせるか、SSR構成を選ぶ判断になります。
SSGは高速で障害点が少ない一方、更新には再ビルドが必要です。リアルタイム性が高いページや認証が必要な画面には向きません。静的化する範囲とクライアント側で取得する範囲を分ける判断が必要です。
現場に残す判断軸
React Router SSGは、公開サイトを軽く運用する選択肢になります。静的生成の範囲、fallback、キャッシュを明確にすれば、Docker配信でも安定したサイト運用ができます。
静的サイト運用の良さは、配信時の処理を減らせることです。その代わり、ビルド成果物、キャッシュ、fallbackを設計対象にすることで、SSGの単純さを保てます。


