部分プリレンダリング (Partial Prerendering)

これまでに、静的レンダリングと動的レンダリング、そしてデータに依存する動的コンテンツをストリーミングする方法について学びました。この章では、部分プリレンダリング (PPR) を使って、同じルート内で静的レンダリング、動的レンダリング、ストリーミングを組み合わせる方法を学びましょう。

部分プリレンダリング (Partial Prerendering) は Next.js 14 で導入された実験的機能です。このページの内容は機能の安定化に伴って更新される可能性があります。PPR は Next.js のカナリーリリース (next@canary) でのみ利用可能で、安定版の Next.js では利用できません。現時点では、部分プリレンダリングを本番環境で使用することは推奨していません。

Next.js のカナリーリリースをインストールするには、次のコマンドを実行します:

pnpm install next@canary

静的ルート vs. 動的ルート

現在構築されているほとんどのウェブアプリでは、アプリケーション全体または特定のルートに対して、静的レンダリングか動的レンダリングのいずれかを選択します。Next.js では、ルート内で動的関数(データベースのクエリなど)を呼び出すと、そのルート全体が動的になります。

しかし、ほとんどのルートは完全に静的または動的ではありません。例えば、eコマースサイトを考えてみましょう。商品情報ページの大部分は静的にレンダリングしたいが、ユーザーのカートやおすすめ商品は動的に取得したい場合があります。これにより、ユーザーにパーソナライズされたコンテンツを表示できます。

ダッシュボードページに戻って、どのコンポーネントが静的で、どのコンポーネントが動的だと考えますか?

準備ができたら、以下のボタンをクリックしてダッシュボードルートをどのように分割するか確認してください:

部分プリレンダリング (Partial Prerendering) とは?

Next.js 14 では、部分プリレンダリング (Partial Prerendering) の実験的バージョンが導入されました。これは、同じルート内で静的レンダリングと動的レンダリングの利点を組み合わせることができる新しいレンダリングモデルです。例えば:

部分プリレンダリングされた商品ページ。静的ナビゲーションと商品情報、動的カートとおすすめ商品が表示されている

ユーザーがルートにアクセスすると:

  • ナビゲーションバーや商品情報を含む静的ルートシェルが提供され、高速な初期読み込みが保証されます。
  • シェルには、カートやおすすめ商品などの動的コンテンツが非同期で読み込まれる「穴」が残されています。
  • 非同期の「穴」は並列でストリーミングされるため、ページ全体の読み込み時間が短縮されます。

部分プリレンダリングの仕組み

部分プリレンダリングは、React の Suspense(前の章で学びました)を使用して、アプリケーションの一部のレンダリングを条件が満たされるまで(例: データが読み込まれるまで)延期します。

Suspense のフォールバックは、静的コンテンツとともに初期 HTML ファイルに埋め込まれます。ビルド時(または再検証時)に、静的コンテンツはプリレンダリングされて静的シェルが作成されます。動的コンテンツのレンダリングは、ユーザーがルートをリクエストするまで延期されます。

コンポーネントを Suspense でラップしても、コンポーネント自体が動的になるわけではありません。Suspense は静的コードと動的コードの境界として使用されます。

ダッシュボードルートで PPR を実装する方法を見てみましょう。

部分プリレンダリングの実装

Next.js アプリで PPR を有効にするには、next.config.ts ファイルに ppr オプションを追加します:

next.config.ts
import type { NextConfig } from 'next';
 
const nextConfig: NextConfig = {
  experimental: {
    ppr: 'incremental'
  }
};
 
export default nextConfig;

'incremental' 値は、特定のルートに対して PPR を採用できるようにします。

次に、ダッシュボードレイアウトに experimental_ppr セグメント設定オプションを追加します:

/app/dashboard/layout.tsx
import SideNav from '@/app/ui/dashboard/sidenav';
 
export const experimental_ppr = true;
 
// ...

これだけです。開発環境ではアプリケーションに違いが見られないかもしれませんが、本番環境ではパフォーマンスの向上に気づくはずです。Next.js はルートの静的部分をプリレンダリングし、動的部分はユーザーがリクエストするまで延期します。

部分プリレンダリングの素晴らしい点は、それを使用するためにコードを変更する必要がないことです。ルートの動的部分を Suspense でラップしている限り、Next.js はルートのどの部分が静的でどの部分が動的かを認識します。

私たちは、PPR がウェブアプリケーションのデフォルトのレンダリングモデルになる可能性があると考えています。静的サイトと動的レンダリングの両方の利点を組み合わせることができるからです。ただし、これはまだ実験的です。将来的に安定化し、Next.js での構築のデフォルトの方法にしたいと考えています。

これらの変更を元に戻し、次の章に進むことができます。

まとめ

これまでに、アプリケーションのデータ取得を最適化するためにいくつかのことを行ってきました:

  1. アプリケーションコードと同じリージョンにデータベースを作成し、サーバーとデータベース間の遅延を減らしました。
  2. React サーバーコンポーネントでサーバー上でデータを取得しました。これにより、高負荷なデータ取得とロジックをサーバー上に保ち、クライアントサイドの JavaScript バンドルを減らし、データベースの秘密がクライアントに公開されるのを防ぎます。
  3. SQL を使用して必要なデータのみを取得し、各リクエストで転送されるデータ量とメモリ内でデータを変換するために必要な JavaScript の量を減らしました。
  4. JavaScript でデータ取得を並列化しました(意味がある場合に限ります)。
  5. ストリーミングを実装して、遅いデータリクエストがページ全体をブロックするのを防ぎ、すべてが読み込まれるのを待たずにユーザーが UI との対話を開始できるようにしました。
  6. データ取得を必要なコンポーネントに移動し、ルートのどの部分を動的にすべきかを分離しました。

次の章では、データ取得時に実装が必要になる可能性のある2つの一般的なパターン、検索とページネーションについて見ていきます。