静的サイト生成 (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`をプロップとして受け取る
  return {
    props: {
      posts,
    },
  }
}

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

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

Next.jsでは、動的ルートを使用してページを作成できます。例えば、pages/posts/[id].js というファイルを作成して、id に基づいて単一のブログ投稿を表示できます。これにより、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から配信できるため、リクエストごとにサーバーがページをレンダリングするよりもはるかに高速だからです。

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

  • マーケティングページ
  • ブログ投稿やポートフォリオ
  • 電子商取引の商品一覧
  • ヘルプとドキュメント

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

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

このような場合は、以下のいずれかの方法を選択できます:

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

On this page