>_tech-draft
Vercelのアイコン
Vercel
動画公開日
タイトル

Hands On: How To Migrate To Next.js 16 and "Use Cache”

再生時間

37分

Next.jsキャッシュコンポーネント徹底解説:use cacheとcacheLifeで高速化

ポイント

  • Next.js 15 App Routerを利用中の開発者へ、新機能`cache components`を用いたアプリケーションのパフォーマンス最適化方法を解説します。
  • 従来のキャッシュ設定から`use cache`ディレクティブへの移行手順や、`cacheLife`関数での再検証設定を具体的なコード例で紹介。
  • これにより、アプリケーションの応答性を向上させ、ビルド時やサーバー側のレンダリングを最適化する知見が得られます。

はじめに

Next.jsアプリケーションのパフォーマンス最適化は、ユーザー体験を向上させる上で非常に重要です。本記事では、Next.js 15(App Routerのセグメント設定)を使用しているアプリケーションを、新しいcache componentsの機能に移行する方法について詳しく解説します。cache componentsは、Next.jsのキャッシングメカニズムをより明示的かつ柔軟にするための強力な機能であり、partial pre-renderingと新しいuse cacheディレクティブがその中心を担います。

本記事では、シンプルなブログアプリケーションを例に、cache componentsの有効化から、use cacheディレクティブの適用、そしてcacheLife関数によるキャッシュの再検証設定までを順を追って解説します。これらの知識を習得することで、アプリケーションの応答性を向上させ、より効率的なデータ取得と表示を実現できるようになります。

Next.jsのキャッシングを革新するcache componentsとは?

cache componentsは、Next.jsにおけるキャッシングの仕組みを刷新するために設計された一連の新機能です。これはUI上で直接目に見えるものではありませんが、開発者がキャッシング戦略をより細かく制御できるようになることで、アプリケーションのパフォーマンスを大きく向上させます。主な特徴は以下の通りです。

  • 明示的かつ柔軟なキャッシング:どのコンポーネントをいつ、どのようにキャッシュするかを開発者が明確に指示できます。
  • Partial Pre-rendering (PPR):ページの静的な部分を事前にレンダリングし、動的な部分だけをオンデマンドで生成することで、高速な初期表示と最新データの両立を図ります。
  • use cacheディレクティブ:特定のコンポーネントや関数をキャッシュ可能にするための新しいディレクティブです。

これらの機能により、Next.jsアプリケーションは、ビルド時やサーバー側でのデータ取得とレンダリングを最適化し、ユーザーに高速なページロードと最新のコンテンツを提供することが可能になります。

Next.jsアプリケーションの準備

cache componentsを利用するためには、まずNext.jsのバージョンを最新に更新し、関連する設定を有効にする必要があります。

1. Next.jsの最新バージョンへの更新

まず、プロジェクトのNext.jsを最新バージョンにアップデートします。これにより、cache componentsを含む最新の機能を利用できるようになります。

npm install next@latest

2. next.config.jsでのcache componentsの有効化

次に、next.config.jsファイルに設定を追加して、cache componentsを有効にします。これはexperimentalフラグの下に設定されます。

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    cacheComponents: true, // `cache components`をtrueに設定
  },
};

module.exports = nextConfig;

この設定を適用後、開発サーバーを再起動してください。

ホームページのマイグレーション

サンプルアプリケーションのホームページは、これまでexport const dynamic = 'force-static'export const revalidate = 60といったセグメント設定を使用して、静的なページとして動作していました。cache componentsを有効にすると、これらの設定が互換性がないというエラーが発生します。ここから、ホームページをcache componentsの仕組みに移行する手順を見ていきましょう。

1. 互換性のないセグメント設定の削除

cache componentsが有効な環境では、従来のdynamicrevalidateのようなルートセグメント設定は使用できません。これらを削除またはコメントアウトする必要があります。

// app/page.tsx (変更前)
export const dynamic = 'force-static';
export const revalidate = 60; // 60秒

export default function HomePage() {
  // ...ページのロジック
}

// app/page.tsx (変更後)
// export const dynamic = 'force-static'; // コメントアウトまたは削除
// export const revalidate = 60; // コメントアウトまたは削除

export default function HomePage() {
  // ...ページのロジック
}

この変更後、アプリケーションを再起動してページにアクセスすると、別のエラーが表示されるはずです。

2. uncached data was accessed outside of a suspense boundaryエラーへの対処とuse cacheディレクティブの適用

前述の設定を削除すると、「uncached data was accessed outside of a suspense boundary.」というエラーに直面する可能性があります。これは、キャッシュされていないデータがSuspense境界の外でアクセスされたことを意味します。この問題を解決するには、主に二つの方法があります。

  • 動的なデータの場合:コンポーネントをSuspense境界でラップする。
  • 静的なデータの場合use cacheディレクティブを使用する。

今回のホームページは元々静的なページとして設計されていたため、use cacheディレクティブを適用するのが適切です。use cacheディレクティブをファイルの先頭、またはエクスポートされるメインコンポーネントの内部に記述することで、そのコンポーネントがビルド時に実行され、その出力が静的なページとしてキャッシュされるようになります。

// app/page.tsx
'use cache'; // ファイルのトップ、またはコンポーネント定義内

export default function HomePage() {
  // ...ページのロジック
  return (
    <div>
      <h1>ホーム</h1>
      {/* ここで記事の統計や特集記事などを表示 */}
    </div>
  );
}

'use cache';を追加して保存し、ページをリロードすると、エラーが解消され、再び静的なページとして機能するようになります。

キャッシュの再検証をcacheLifeで制御する

ホームページのマイグレーションでdynamicrevalidateの設定を削除しましたが、元のアプリケーションではrevalidate: 60(1分間隔での再検証)が設定されていました。cache componentsでは、この再検証の仕組みをnext/cacheから提供されるcacheLife関数で実現します。

cacheLife関数は、キャッシュのプロファイルを受け取ります。これは文字列で定義済みのプロファイルを指定することも、オブジェクト形式で詳細な設定をインラインで記述することも可能です。

cacheLifeの利用方法

まず、next/cacheからcacheLifeをインポートします。

// app/page.tsx
'use cache';
import { cacheLife } from 'next/cache';

cacheLife('minute'); // 'minute'プロファイルを使用

export default function HomePage() {
  // ...
}

または、インラインで設定を記述することも可能です。

// app/page.tsx
'use cache';
import { cacheLife } from 'next/cache';

cacheLife({ stale: 60, revalidate: 60, expire: 3600 }); // 例: staleを60秒、revalidateを60秒、expireを3600秒 (1時間)に設定

export default function HomePage() {
  // ...
}

cacheLifeが受け取るプロファイルの詳細

cacheLife関数で設定できる主要なプロパティには、stalerevalidateexpireがあります。

  • stale (例: 5分): この期間中、ブラウザはサーバーにキャッシュの新鮮さを確認することなく、既存のキャッシュを使用します。つまり、この期間中はユーザーにサーバーへの問い合わせなしでページが表示され、高いパフォーマンスが期待できます。

  • revalidate (例: 1分): ページが最初に生成されてから、すべてのユーザーが同じ出力を受け取る期間です。この期間が過ぎると、新しいリクエストが来た際に、サーバーはバックグラウンドで新しいコンテンツの再生成を試みます。しかし、再生成が完了するまでは、古いキャッシュがユーザーに提供されます。これにより、常にユーザー体験を損なうことなく最新のコンテンツへの更新が可能です。

  • expire (例: 1時間): キャッシュエントリが「期限切れ」と見なされるまでの時間です。この時間が経過すると、Next.jsはそのキャッシュを無効と判断し、次にリクエストがあった際に、動的レンダリング(つまり、ページを完全に最初から生成すること)に切り替わります。結果が生成されるまではユーザーに何も表示されない可能性があります。これは、非常に古い情報が表示されることを防ぐための安全策です。

これらの設定を適切に組み合わせることで、アプリケーションの要件に応じた最適なキャッシュ戦略を実現できます。

ブログページのマイグレーション(動的データと静的データの分離)

次に、ブログページのマイグレーションについて考えます。ブログページは、選択されたカテゴリに基づいて投稿リストが動的に変化します。ここでの課題は、カテゴリリストやページレイアウトなどの静的な要素はキャッシュしつつ、実際の投稿リストは動的に保つ方法を見つけることです。

例えば、カテゴリデータは頻繁に変わらないため静的にキャッシュし、ユーザーの検索パラメータ(search params)によって取得するブログ投稿データは動的に扱う必要があります。これは、cache componentsの強力な機能であるpartial pre-renderingを活用し、動的な部分と静的な部分を適切に分離してキャッシング戦略を立てることで実現可能です。この詳細な実装については、今後の記事やドキュメントでさらに深掘りしていくことになります。

まとめ

本記事では、Next.jsアプリケーションをcache componentsの仕組みに移行する具体的な手順について解説しました。cache componentsを有効にし、use cacheディレクティブを使用して静的ページを効率的にキャッシュする方法、そしてcacheLife関数でキャッシュの再検証ポリシーを詳細に制御する方法を学びました。

cache componentsは、Next.jsアプリケーションのパフォーマンスを大幅に向上させる可能性を秘めています。特に、stale-while-revalidateのような高度なキャッシュ戦略を簡潔に実装できる点は大きなメリットです。本記事で紹介した内容を参考に、ご自身のNext.jsアプリケーションの最適化にぜひお役立てください。

参考動画