静的サイト生成 (SSG)
使用例
- WordPress の例(デモ)
- Markdown ファイルを使用したブログスターター (デモ)
- DatoCMS の例 (デモ)
- TakeShape の例 (デモ)
- Sanity の例 (デモ)
- Prismic の例 (デモ)
- Contentful の例 (デモ)
- Strapi の例 (デモ)
- Prepr の例 (デモ)
- Agility CMS の例 (デモ)
- Cosmic の例 (デモ)
- ButterCMS の例 (デモ)
- Storyblok の例 (デモ)
- GraphCMS の例 (デモ)
- Kontent の例 (デモ)
- Builder.io の例 (デモ)
- TinaCMS の例 (デモ)
- Static Tweet (デモ)
- Enterspeed の例 (デモ)
静的生成 (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 が提供する以下の関数を使用できます:
- ページのコンテンツが外部データに依存する場合:
getStaticProps
を使用 - ページのパスが外部データに依存する場合:
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` を prop として受け取る
return {
props: {
posts,
},
}
}
getStaticProps
の動作について詳しくは、データ取得のドキュメントを参照してください。
シナリオ2: ページパスが外部データに依存する場合
Next.js では、動的ルートを使用してページを作成できます。例えば、pages/posts/[id].js
というファイルを作成して、id
に基づいて単一のブログ投稿を表示できます。これにより、posts/1
にアクセスした際に id: 1
のブログ投稿を表示できます。
動的ルーティングについて詳しくは、動的ルーティングのドキュメントを参照してください。
ただし、ビルド時にどの id
を事前レンダリングするかは外部データに依存する場合があります。
例: データベースに id: 1
のブログ投稿を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 でそれらを埋めることができます。このアプローチについて詳しくは、データ取得のドキュメントを参照してください。
- サーバーサイドレンダリング (SSR) を使用: Next.js は各リクエストでページを事前レンダリングします。CDN でキャッシュできないため遅くなりますが、事前レンダリングされたページは常に最新の状態になります。このアプローチについては後述します。