title: 静的生成 category: Router order: 10
import Link from "../../../../components/Link.jsx";
静的生成
ページを静的としてマークすると、ファイルシステムベースのルーターがそのページを@lazarv/react-serverのエクスポートに追加します。
ページを静的としてマークするには、ページの一致するパスに.static.{js,mjs,ts,mts,json}拡張子のファイルを作成し、そのルートで使用可能なパラメータの配列、パラメータの配列を返す関数、またはパラメータを逐次yieldする非同期ジェネレーター関数をデフォルトエクスポートします。関数は非同期関数にすることもできます。
パラメータのないページの場合は、デフォルトでtrueをエクスポートします。
export default true;
ページを静的としてマークする最も簡単な方法は、trueを定義した.static.jsonファイルを作成することです。
true
<Link name="dynamic-routes"> ## 動的ルート </Link>警告: パラメータを持つルートでは
trueを値として使用できません。使用可能なパラメータの配列、またはパラメータの配列を返す関数を定義する必要があります。パラメータを持つルートでtrueを使用すると、ビルドが失敗します。
動的ルートの場合、/users/:idにページがある場合、/users/[id].static.tsに以下の内容のファイルを作成できます:
export default [{ id: 1 }, { id: 2 }, { id: 3 }];
ルートパラメータの配列、またはルートパラメータの配列を返す非同期関数をエクスポートできます。
export default async () => [{ id: 1 }, { id: 2 }, { id: 3 }];
関数はビルド時に実行され、その結果が静的ページの生成に使用されます。
<Link name="streaming-static-paths"> ## 静的パスのストリーミング </Link>非常に多くのパスを持つルート(CMSから取得したページネーション付きコンテンツ、大規模データベースから読み込むslug、レンダリング開始前にリスト全体をメモリに展開するのが無駄になるあらゆるケース)では、デフォルトエクスポートをasync function*(非同期ジェネレーター)として宣言し、パラメータ記述子を逐次yieldできます。総数に関わらずピークメモリは1記述子のまま、最初のyieldと同時にレンダリングを開始できます。
export default async function* () {
let cursor = null;
do {
const { items, next } = await fetchUsers(cursor);
for (const user of items) {
yield { id: user.id };
}
cursor = next;
} while (cursor);
}
{ ...params }記述子(上記のようにルートのパラメータテンプレートにマッピングされます)または{ path: "/explicit/path" }記述子を完全な制御のためにyieldできます。完全に同期的なソースには同期function*ジェネレーターも同様に動作します。
<Link name="static-json-data"> ## 静的JSONデータ </Link>注意: 検出は関数の種類で行われます。デフォルトエクスポートとして
async function*(またはfunction*)を直接記述してください。通常の関数を返すラッパーは配列契約にフォールバックします。
.static.json拡張子のファイルを作成することで、静的ページに静的JSONデータを使用できます。
たとえば、/users/:idにページがある場合、/users/[id].static.jsonに以下の内容のファイルを作成できます:
[{ "id": 1 }, { "id": 2 }, { "id": 3 }]
<Link name="override-static-paths"> ## 静的パスのオーバーライド </Link>注意: 静的ルートはページコンポーネントとは独立して定義しています。これはルーティングとページレンダリングの関心事を分離するためです。この方法により、ルーターはビルド時にページコンポーネントを定義するコードをインポートする必要がなくなります。これは、ページコンポーネントの依存関係ツリーが大きい場合や、コードに副作用がある場合に便利です。
@lazarv/react-serverの設定ファイルでexport()関数を定義することで、すべての静的パスをオーバーライドできます。この関数はすべての静的パスの配列とともに呼び出され、デフォルトの静的パスをオーバーライドする新しいパスの配列を返すことができます。この例では、すべての静的パスから/enプレフィックスを削除しています。
export default {
export(paths) {
return paths.map(({ path }) => ({
path: path.replace(/^\/en/, ""),
}));
},
};
この関数を使用して、新しい静的パスを追加したり、一部のパスを削除したりすることもできます。
export default {
export(paths) {
return [
...paths,
{ path: "/new-page" },
];
},
};
export default {
export(paths) {
return paths.filter(({ path }) => path !== "/en");
},
};
<Link name="streaming-export">
## エクスポートパスソースのストリーミング
</Link>通常の関数形式のexportは配列を受け取ります。ファイルシステムルーターが解決したすべてのパスを一度に受け取る形です。ほとんどのアプリではこれで十分ですが、非常に大規模なエクスポート(数万ページ、CMSから取得するページネーションされたコンテンツ、動的に生成されるパスなど)では、レンダリング開始前にリスト全体をメモリ上に展開するのは効率的ではありません。ピークメモリがパス数に比例して増大し、最後のパスが収集されるまで最初のレンダリングを開始できないからです。
exportをasync function*(非同期ジェネレーター)として宣言すると、ストリーミングモードに切り替わります。ジェネレーターはファイルシステムルーターとexportPathsが生成するライブなAsyncIterableを受け取り、レンダラーにパスを1つずつyieldできます。レンダラーはワーカーが空いたときにのみパスをプルするため、ジェネレーターはエクスポートのちょうど1ステップ先を進む形になります。ピークメモリは総パス数に関係なくO(パス記述子1つ分)に保たれ、最初にyieldされたパスからレンダリングが開始されます。並列レンダリングのために--export-concurrencyと組み合わせると効果的です。
export default {
async *export(paths) {
// ファイルシステムルーターが解決したパスをそのまま流す。
for await (const p of paths) {
yield p;
}
// その後、追加のパスを遅延的にyieldする。例: CMSからページ単位で取得、
// 大規模なDBクエリから計算、ファイルから読み込み、など。
let cursor = null;
do {
const { items, next } = await fetchPage(cursor);
for (const item of items) {
yield { path: `/posts/${item.slug}` };
}
cursor = next;
} while (cursor);
},
};
<Link name="static-export-api-routes"> ## APIルートの静的エクスポート </Link>注意: 検出は関数の種別で行われます。
exportの値としてasync function*(またはfunction*)を直接書く必要があります。通常の関数を返すラッパー(メモ化、デコレーターなど)を介すると、レガシーな配列変換契約にフォールバックします。通常の関数形式は変更されておらず、「配列を渡してくれれば、変換した配列を返す」という用途には引き続きこちらが適しています。
APIルートを静的ルートとしてエクスポートすることもできます。これを行うには、静的パスをpath、filename、method、headersプロパティを持つオブジェクトとして定義します。pathはルートパス、filenameは静的ファイルのファイル名、methodはリクエストのHTTPメソッド、headersはリクエストのヘッダーを持つオブジェクトです。methodとheadersはオプションです。
export default {
export() {
return [
{
path: "/sitemap.xml",
filename: "sitemap.xml",
method: "GET",
headers: {
accept: "application/xml",
},
},
];
},
}
<Link name="remote">
## マイクロフロントエンドルートの静的エクスポート
</Link>マイクロフロントエンドルートを静的としてエクスポートすることもできます。これを行うには、静的パスをpathとremoteプロパティを持つオブジェクトとして定義します。pathはルートパス、remoteはそのルートがマイクロフロントエンドルートであり、ビルド時にリモートレスポンスペイロードを生成する必要があることを示すフラグです。マイクロフロントエンドの静的エクスポートを使用することで、ビルド時にマイクロフロントエンドのコンテンツを事前レンダリングし、アプリケーションのパフォーマンスを向上させることができます。
export default {
export() {
return [
{
path: "/",
remote: true,
}
];
},
};
<Link name="static-export-outlets">
## アウトレットの静的エクスポート
</Link>アウトレットを静的としてエクスポートすることもできます。これを行うには、静的パスをpathとoutletプロパティを持つオブジェクトとして定義します。pathはルートパス、outletはアウトレットの名前です。アウトレットの静的エクスポートを使用することで、ビルド時にアウトレットのコンテンツを事前レンダリングし、アプリケーションのパフォーマンスを向上させることができます。エクスポートされたアウトレットはRSCコンポーネントとしてレンダリングされます。エクスポートされたアウトレットへのクライアントサイドナビゲーションでは、サーバーにリクエストを送信する代わりに、静的なアウトレットコンテンツが使用されます。
export default {
export() {
return [{ path: "/photos/1", outlet: "modal" }];
},
};
<Link name="disable-static-export-for-rsc-routes">
## RSCルートの静的エクスポートを無効化
</Link>rscプロパティをfalseに設定することで、RSCルートの静的エクスポートを無効にできます。これは、ページがRSCルートであるが、ビルド時に事前レンダリングしたくない場合や、そのルートのRSCペイロードを使用する予定がない場合に便利です。これにより、ビルド時にRSCペイロードが生成されなくなり、ルートは通常のHTMLページとしてのみレンダリングされ、デプロイメントサイズが削減されます。
export default {
export() {
return [{ path: "/photos/1", rsc: false }];
},
};