プリレンダリング
プリレンダリングを使用すると、ページをランタイムではなくビルド時にレンダリングすることで、静的コンテンツのページロードを高速化できます。
設定
プリレンダリングは、react-router.config.ts の prerender 設定によって有効になります。
最もシンプルな設定はブーリアンの true で、これは routes.ts に基づいてアプリケーションのすべての静的パスをプリレンダリングします。
import type { Config } from "@react-router/dev/config";
export default {
prerender: true,
} satisfies Config;ブーリアンの true は、パラメータ値が不明なため、動的パス (例: /blog/:slug) は含まれません。
動的な値を含む特定のパスを設定するには、パスの配列を指定できます。
import type { Config } from "@react-router/dev/config";
let slugs = getPostSlugs();
export default {
prerender: [
"/",
"/blog",
...slugs.map((s) => `/blog/${s}`),
],
} satisfies Config;パスを決定するためにより複雑な、または非同期のロジックを実行する必要がある場合は、パスの配列を返す関数を提供することもできます。この関数は、アプリケーション内のすべての静的パスを手動で追加することを避けるために使用できる getStaticPaths メソッドを提供します。
import type { Config } from "@react-router/dev/config";
export default {
async prerender({ getStaticPaths }) {
let slugs = await getPostSlugsFromCMS();
return [
...getStaticPaths(), // "/" and "/blog"
...slugs.map((s) => `/blog/${s}`),
];
},
} satisfies Config;Concurrency (unstable)
デフォルトでは、ページは一度に1つのパスでプリレンダリングされます。並行して複数のパスをプリレンダリングするように concurrency を有効にすることで、多くの場合、ビルド時間を短縮できます。アプリに最適なパフォーマンスを提供する値で実験する必要があります。
concurrency を指定するには、prerender 設定を prerender.paths フィールドに移動し、prerender.unstable_concurrency で concurrency を指定できます。
import type { Config } from "@react-router/dev/config";
let slugs = getPostSlugs();
export default {
prerender: {
paths: [
"/",
"/blog",
...slugs.map((s) => `/blog/${s}`),
],
unstable_concurrency: 4,
},
} satisfies Config;ランタイムサーバーの有無によるプリレンダリング
プリレンダリングは、ssr 設定値に基づいて次の2つの方法で使用できます。
ssr:true(デフォルト値) を使用したランタイム SSR サーバーと連携ssr:falseを使用して静的ファイルサーバーにデプロイ
ssr:true を使用したプリレンダリング
ssr:true を使用してプリレンダリングする場合、ランタイムサーバーは引き続き存在しますが、応答時間を短縮するために特定のパスをプリレンダリングすることを選択していることを示します。
import type { Config } from "@react-router/dev/config";
export default {
// 省略可能 - デフォルトは true
ssr: true,
prerender: ["/", "/blog", "/blog/popular-post"],
} satisfies Config;データローディングとプリレンダリング
プリレンダリングのための特別なアプリケーション API はありません。プリレンダリングされるルートは、サーバーレンダリングと同じルート loader 関数を使用します。
export async function loader({ request, params }) {
let post = await getPost(params.slug);
return post;
}
export function Post({ loaderData }) {
return <div>{loaderData.title}</div>;
}デプロイされたサーバー上のルートへのリクエストの代わりに、ビルドは new Request() を作成し、サーバーと同じようにアプリを通して実行します。
サーバーレンダリングの場合、プリレンダリングされていないパスへのリクエストは、通常どおりサーバーレンダリングされます。
静的ファイル出力
レンダリングされた結果は、build/client ディレクトリに書き出されます。各パスに対して 2 つのファイルが表示されます。
- 初期ドキュメントリクエスト用の
[url].htmlHTML ファイル - クライアント側のナビゲーションブラウザリクエスト用の
[url].dataファイル
ビルドの出力には、プリレンダリングされたファイルが示されます。
> react-router build
vite v5.2.11 building for production...
...
vite v5.2.11 building SSR bundle for production...
...
Prerender: Generated build/client/index.html
Prerender: Generated build/client/blog.data
Prerender: Generated build/client/blog/index.html
Prerender: Generated build/client/blog/my-first-post.data
Prerender: Generated build/client/blog/my-first-post/index.html
...開発中、プリレンダリングはレンダリングされた結果をパブリックディレクトリに保存しません。これは react-router build でのみ発生します。
ssr:false を使用したプリレンダリング
上記の例では、ランタイムサーバーをデプロイしているが、一部の静的ページをプリレンダリングしてサーバーへのアクセスを回避し、ロードを高速化することを前提としています。
ランタイム SSR を無効にし、静的ファイルサーバーから提供されるようにプリレンダリングを構成するには、ssr:false 構成フラグを設定します。
import type { Config } from "@react-router/dev/config";
export default {
ssr: false, // ランタイムサーバーレンダリングを無効にする
prerender: true, // すべての静的ルートをプリレンダリングする
} satisfies Config;prerender 構成なしで ssr:false を指定すると、React Router はそれを SPA モード と呼びます。SPA モードでは、アプリケーションパスの いずれか をハイドレートできる単一の HTML ファイルをレンダリングします。これは、root ルートのみを HTML ファイルにレンダリングし、ハイドレーション中にブラウザの URL に基づいてロードする子ルートを決定するためです。つまり、ルートルートで loader を使用できますが、他のルートでは使用できません。これは、ブラウザでのハイドレーションまでどのルートをロードするかわからないためです。
ssr:false でパスをプリレンダリングする場合、それらのパスに一致するすべてのルートをプリレンダリングするため、一致するルートはローダーを持つ_ことができます_。ssr:false が設定されている場合、actions または headers 関数をルートに含めることはできません。これは、それらを実行するランタイムサーバーがないためです。
SPA フォールバックを使用したプリレンダリング
ssr:false が必要だが、ルートの すべて をプリレンダリングしたくない場合も問題ありません。プリレンダリングのパフォーマンス/SEO の利点が必要なパスもあれば、SPA で問題ないページもあるかもしれません。
構成オプションの組み合わせを使用してこれを行うこともできます。prerender 構成をプリレンダリングするパスに制限するだけで、React Router は他のパスをハイドレートするために提供できる「SPA フォールバック」HTML ファイルも出力します (SPA モード と同じアプローチを使用)。
これは、次のいずれかのパスに書き込まれます。
build/client/index.html-/パスがプリレンダリングされていない場合build/client/__spa-fallback.html-/パスがプリレンダリングされている場合
import type { Config } from "@react-router/dev/config";
export default {
ssr: false,
// SPA フォールバックは build/client/index.html に書き込まれます
prerender: ["/about-us"],
// SPA フォールバックは build/client/__spa-fallback.html に書き込まれます
prerender: ["/", "/about-us"],
} satisfies Config;デプロイサーバーを構成して、それ以外の場合は 404 になるパスに対してこのファイルを提供できます。一部のホストはデフォルトでこれを行いますが、そうでないホストもあります。例として、ホストはこれを実行するために _redirects ファイルをサポートする場合があります。
# `/` ルートをプリレンダリングしなかった場合
/* /index.html 200
# `/` ルートをプリレンダリングした場合
/* /__spa-fallback.html 200
アプリの有効なルートで 404 が発生する場合は、ホストを構成する必要がある可能性があります。
sirv-cli ツールでこれを行う方法の別の例を次に示します。
# `/` ルートをプリレンダリングしなかった場合
sirv-cli build/client --single index.html
# `/` ルートをプリレンダリングした場合
sirv-cli build/client --single __spa-fallback.html無効なエクスポート
ssr:false でプリレンダリングする場合、React Router はビルド時に無効なエクスポートがある場合にエラーを発生させ、見落としやすい一部の間違いを防ぎます。
headers/action関数は、それらを実行するランタイムサーバーがないため、すべてのルートで禁止されていますprerender構成なしでssr:false(SPA モード) を使用する場合、loaderはルートルートでのみ許可されますprerender構成でssr:falseを使用する場合、loaderはprerenderパスによって一致するすべてのルートで許可されます- 子ルートを持つプリレンダリングされたルートで
loaderを使用している場合は、次のいずれかの方法で、実行時に親loaderDataを適切に決定できることを確認する必要があります。- すべての子ルートをプリレンダリングして、各子ルートパスのビルド時に親
loaderを呼び出して.dataファイルにレンダリングできるようにするか、 - プリレンダリングされていない子パスに対して実行時に呼び出すことができる親で
clientLoaderを使用します
- すべての子ルートをプリレンダリングして、各子ルートパスのビルド時に親
- 子ルートを持つプリレンダリングされたルートで