Sponsor
ChatHubChatHub Use GPT-4, Gemini, Claude 3.5 and more chatbots side-by-side
ここをクリック
Menu

静的サイト生成(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つのシナリオがあり、どちらか一方または両方が適用される可能性があります。各ケースで、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`をpropsとして受け取ります
  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の詳細については、データフェッチングのドキュメントを確認してください。

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

ページを1回ビルドしてCDNで提供できるため、サーバーが各リクエストでページをレンダリングするよりもはるかに高速になるので、可能な限り静的生成(データありとなし)を使用することをお勧めします。

以下のようなタイプのページに静的生成を使用できます:

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

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

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

このようなケースでは、以下のいずれかを実行できます:

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