静的サイト生成 (SSG)

使用例

ページで静的生成 (Static Generation) を使用する場合、ページのHTMLはビルド時に生成されます。つまり、本番環境では next build を実行したときにページHTMLが生成されます。このHTMLは各リクエストで再利用され、CDNによってキャッシュされる可能性があります。

Next.jsでは、データあり/なしでページを静的に生成できます。それぞれのケースを見ていきましょう。

データなしの静的生成

デフォルトでは、Next.jsはデータを取得せずに静的生成を使用してページを事前レンダリングします。以下はその例です:

function About() {
  return <div>About</div>
}

export default About

このページは事前レンダリングするために外部データを取得する必要がないことに注意してください。このような場合、Next.jsはビルド時にページごとに単一のHTMLファイルを生成します。

データありの静的生成

一部のページでは、事前レンダリングのために外部データを取得する必要があります。2つのシナリオがあり、1つまたは両方が適用される場合があります。それぞれの場合、Next.jsが提供する以下の関数を使用できます:

  1. ページのコンテンツが外部データに依存する場合: getStaticProps を使用
  2. ページのパスが外部データに依存する場合: getStaticPaths を使用(通常は getStaticProps と併用)

シナリオ1: ページコンテンツが外部データに依存する場合

: ブログページがCMS(コンテンツ管理システム)からブログ投稿のリストを取得する必要がある場合

// TODO: このページを事前レンダリングする前に
//       何らかのAPIエンドポイントを呼び出して `posts` を取得する必要がある
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

このデータを事前レンダリング時に取得するために、Next.jsでは同じファイルから getStaticProps という async 関数を export できます。この関数はビルド時に呼び出され、取得したデータを事前レンダリング時のページの props に渡せます。

export default function Blog({ posts }) {
  // 投稿をレンダリング...
}

// この関数はビルド時に呼び出される
export async function getStaticProps() {
  // 外部APIエンドポイントを呼び出して投稿を取得
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // { props: { posts } } を返すことで、Blogコンポーネントは
  // ビルド時に `posts` をpropとして受け取る
  return {
    props: {
      posts,
    },
  }
}

getStaticProps の動作について詳しくは、データ取得のドキュメントを参照してください。

シナリオ2: ページパスが外部データに依存する場合

Next.jsでは、動的ルートを使用してページを作成できます。例えば、id に基づいて単一のブログ投稿を表示するために pages/posts/[id].js というファイルを作成できます。これにより、posts/1 にアクセスしたときに id: 1 のブログ投稿を表示できます。

動的ルーティングについて詳しくは、動的ルーティングのドキュメントを参照してください。

ただし、ビルド時にどの id を事前レンダリングするかは外部データに依存する可能性があります。

: データベースに1つのブログ投稿(id: 1)しか追加していないとします。この場合、ビルド時に posts/1 のみを事前レンダリングしたいでしょう。

後で id: 2 の2番目の投稿を追加した場合、posts/2 も事前レンダリングしたいでしょう。

つまり、事前レンダリングするページパスは外部データに依存します。これを処理するために、Next.jsでは動的ページ(この場合は pages/posts/[id].js)から getStaticPaths という async 関数を export できます。この関数はビルド時に呼び出され、事前レンダリングするパスを指定できます。

// この関数はビルド時に呼び出される
export async function getStaticPaths() {
  // 外部APIエンドポイントを呼び出して投稿を取得
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 投稿に基づいて事前レンダリングするパスを取得
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // ビルド時にこれらのパスのみを事前レンダリング
  // { fallback: false } は他のルートが404になることを意味する
  return { paths, fallback: false }
}

また、pages/posts/[id].js では、この id の投稿データを取得してページを事前レンダリングするために getStaticProps をエクスポートする必要があります:

export default function Post({ post }) {
  // 投稿をレンダリング...
}

export async function getStaticPaths() {
  // ...
}

// これもビルド時に呼び出される
export async function getStaticProps({ params }) {
  // params には投稿の `id` が含まれる
  // ルートが /posts/1 の場合、params.id は 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  // 投稿データをprops経由でページに渡す
  return { props: { post } }
}

getStaticPaths の動作について詳しくは、データ取得のドキュメントを参照してください。

静的生成を使用すべきタイミング

可能な限り静的生成(データあり/なし)を使用することをお勧めします。なぜなら、ページを一度ビルドしてCDNから配信できるため、サーバーがリクエストごとにページをレンダリングするよりもはるかに高速だからです。

静的生成は以下のような多くの種類のページに使用できます:

  • マーケティングページ
  • ブログ投稿やポートフォリオ
  • Eコマースの商品リスト
  • ヘルプとドキュメント

「このページをユーザーのリクエストに先立って事前レンダリングできるか?」と自問してください。答えが「はい」なら、静的生成を選択すべきです。

一方、ユーザーのリクエストに先立ってページを事前レンダリングできない場合、静的生成は適していません。ページに頻繁に更新されるデータが表示され、ページコンテンツがリクエストごとに変更される場合などです。

このような場合は、以下のいずれかを行えます:

  • クライアントサイドデータ取得を伴う静的生成: ページの一部を事前レンダリングせず、クライアントサイドのJavaScriptを使用してそれらを埋められます。このアプローチについて詳しくは、データ取得のドキュメントを参照してください。
  • サーバーサイドレンダリング (SSR) を使用: Next.jsはリクエストごとにページを事前レンダリングします。CDNによるキャッシュができないため遅くなりますが、事前レンダリングされたページは常に最新の状態になります。このアプローチについては後述します。