コンテンツへスキップ

静的サイト生成 (SSG)

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

Next.jsでは、**データの有無にかかわらず**、ページを静的に生成できます。それぞれのケースを見てみましょう。

データなしの静的生成

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

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

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

データを含む静的生成

一部のページでは、事前にレンダリングするために外部データの取得が必要です。2つのシナリオがあり、どちらか一方、または両方が当てはまる場合があります。いずれの場合も、Next.jsが提供するこれらの関数を使用できます。

  1. ページの**コンテンツ**が外部データに依存する: `getStaticProps`を使用します。
  2. ページの**パス**が外部データに依存する: `getStaticPaths`を使用します(通常は`getStaticProps`に加えて)。

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

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

// TODO: Need to fetch `posts` (by calling some API endpoint)
//       before this page can be pre-rendered.
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

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

export default function Blog({ posts }) {
  // Render posts...
}
 
// This function gets called at build time
export async function getStaticProps() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  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できます。この関数はビルド時に呼び出され、事前にレンダリングするパスを指定できます。

// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))
 
  // We'll pre-render only these paths at build time.
  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}

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

export default function Post({ post }) {
  // Render post...
}
 
export async function getStaticPaths() {
  // ...
}
 
// This also gets called at build time
export async function getStaticProps({ params }) {
  // params contains the post `id`.
  // If the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()
 
  // Pass post data to the page via props
  return { props: { post } }
}

getStaticPathsの動作の詳細については、データフェッチングのドキュメントをご覧ください。

静的生成をいつ使用するべきですか?

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

静的生成は、次のような多くのタイプのページに使用できます。

  • マーケティングページ
  • ブログ記事とポートフォリオ
  • eコマースの商品一覧
  • ヘルプとドキュメント

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

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

このような場合は、次のいずれかを実行できます。

  • クライアントサイドのデータフェッチを使用した静的生成:ページの一部を事前にレンダリングせずにスキップし、クライアントサイドのJavaScriptを使用してそれらを埋め込むことができます。このアプローチの詳細については、データフェッチングのドキュメントをご覧ください。
  • サーバーサイドレンダリングを使用する:Next.jsは、各リクエストでページを事前にレンダリングします。ページをCDNでキャッシュできないため速度は遅くなりますが、事前にレンダリングされたページは常に最新の状態になります。このアプローチについては、以下で説明します。