Open4

Static Site Generation (SSG)

あおけんあおけん

ページが Static Generation を使用する場合、ページのHTMLはビルド時に生成される。
つまり、運用環境では、next build を実行するときにページのHTMLが生成される。
このHTMLはリクエストごとに再利用される。
CDNによってキャッシュされることもある。
Next.jsでは、データの有無にかかわらず、静的にページを生成することができる。

あおけんあおけん

Static Generation without data

デフォルトでは、Next.jsはデータをフェッチせずに Static Generation を使ってページをプリレンダリングする。

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

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

あおけんあおけん

Static Generation with data

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

Scenario 1: Your page content depends on external data(getStaticProps)

例: あなたのブログページは、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という非同期関数をエクスポートできる。
この関数はビルド時に呼び出され、
プリレンダリング時に取得したデータをページの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の動作の詳細については、
Data Fetchingのドキュメントを参照。

Scenario 2: Your page paths depend on external data(getStaticPaths)

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

しかし、ビルド時にどのidをプリレンダリングするかは、
外部データに依存するかもしれない。

例えば、ブログ記事(id: 1)を1つだけデータベースに追加したとする。
この場合、ビルド時にposts/1をプリレンダリングしたいだけ。
その後、2番目の投稿をid: 2で追加することになる。

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

// 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 } }
}
あおけんあおけん

When should I use Static Generation?

私たちは、可能な限り Static Generation(データあり、データなし)を使用することを推奨。

Static Generationは、次のようなさまざまなタイプのページに使用できる。

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

あなたは自問すべき。
"ユーザーのリクエストに先駆けて、このページをプリレンダリングできるか?"
もし答えがイエスなら、Static Generationを選ぶべき。

一方、Static Generation(静的生成)は、
ユーザーのリクエストに先立ってページをプリレンダリングできない場合には、
良いアイデアとは言えません。
例えば、あなたのページが頻繁に更新されるデータを表示していて、
リクエストのたびにページの内容が変わるような場合です。

このような場合、次のいずれかの方法をとることができる。

その1

クライアントサイドのデータ・フェッチでStatic Generationを使用する。
ページの一部のプリレンダリングをスキップして、
クライアントサイドのJavaScriptを使用してデータを入力することができる。

その2

サーバーサイド・レンダリングを使用する。
Next.jsはリクエストごとにページをプリレンダリングします。
CDNによってページがキャッシュされないので遅くなりますが、
プリレンダリングされたページは常に最新の状態になる。