静的サイト生成 (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では、動的ルートを使用してページを作成できます。例えば、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
できます。この関数はビルド時に呼び出され、事前レンダリングするパスを指定できます。
// この関数はビルド時に呼び出される
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から配信できるため、サーバーがリクエストごとにページをレンダリングするよりもはるかに高速だからです。
静的生成は以下のような多くの種類のページに使用できます:
- マーケティングページ
- ブログ投稿やポートフォリオ
- Eコマースの商品リスト
- ヘルプとドキュメント
「このページをユーザーのリクエストに先立って事前レンダリングできるか?」と自問してください。答えが「はい」なら、静的生成を選択すべきです。
一方、ユーザーのリクエストに先立ってページを事前レンダリングできない場合、静的生成は適していません。ページに頻繁に更新されるデータが表示され、ページコンテンツがリクエストごとに変更される場合などです。
このような場合は、以下のいずれかを行えます:
- クライアントサイドデータ取得を伴う静的生成: ページの一部を事前レンダリングせず、クライアントサイドのJavaScriptを使用してそれらを埋められます。このアプローチについて詳しくは、データ取得のドキュメントを参照してください。
- サーバーサイドレンダリング (SSR) を使用: Next.jsはリクエストごとにページを事前レンダリングします。CDNによるキャッシュができないため遅くなりますが、事前レンダリングされたページは常に最新の状態になります。このアプローチについては後述します。