コンテンツにスキップ

静的サイト生成 (SSG)

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

Next.jsでは、データを**使用してもしなくても**静的ページを生成できます。それぞれのケースを見ていきましょう。

データなしの静的生成

デフォルトでは、Next.jsはデータをフェッチせずに静的生成を使用してページをプリレンダリングします。以下に例を示します。

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

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

データありの静的生成

一部のページでは、プリレンダリングのために外部データをフェッチする必要があります。2つのシナリオがあり、そのうちの1つまたは両方が該当する場合があります。それぞれのケースで、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では、同じファイルから`getStaticProps`という`async`関数を`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では、**ダイナミックルーティング**を持つページを作成できます。たとえば、`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`できます。この関数はビルド時に呼び出され、プリレンダリングしたいパスを指定できます。

// 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`では、この`id`を持つ投稿に関するデータをフェッチし、それを使用してページをプリレンダリングできるように`getStaticProps`をエクスポートする必要があります。

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によってキャッシュできないため遅くなりますが、プリレンダリングされたページは常に最新になります。このアプローチについては、後述します。