ブログをSSGにした
Notionで書いた記事をマークダウンにしてNext.jsで表示させている静的サイト(これ)がSSRである必要がないと思ったのでSSGに変更してみる。
※Next.js14.2.3 AppRouter で実装しているので注意。
ネットにはgetStaticProps
やgetStaticPath
などの情報がありそれを読みながら実装していたが何回やってもエラーになり詰まってしまったがよくよく調べるとgetStaticProps
やgetStaticPath
はAppRouterでは対応していないっぽい….(前のバージョン?PageRouter?なら使用できるっぽい)
そこで改めてドキュメントを読んで実装してみたら簡単に実装できて嬉しかった。
自分は動的ルーティング(dynamic rooting)をSSGしたかったのでそれについてメモしていく。
動的ルーティングページをgenerateStaticParamsを使ってSSGする
もともとは以下のコードの通り記述していた。
// app/post/[slug]/page.tsx
export default function Page({ params }: { params: { slug: string }}) {
// ページに表示する.mdxファイルを取得
const fullPath = path.join(process.cwd(), 'src', 'static', 'markdown', `${params.slug}.mdx`);
const fileContents = fs.readFileSync(fullPath, 'utf8');
const { content } = matter(fileContents);
return <CustomMDX source={content} />
}
ただ、これだとSSRになることがわかった。
なぜなら動的ルーティングは slug
が動的に決まるのでslug
が何者かが分かってからじゃないとレンダリングできない。よってSSRになってしまう。
なので予め受け取る可能性のある slug
を定義しておけば、その slug
を使用してページをビルドしてくれるので結果SSGになるみたい。
受け取る可能性のある slug
を定義する方法は以下。
export async function generateStaticParams() {
const directoryPath = path.join(process.cwd(), 'src', 'static', 'markdown');
const metadata = getMarkdownMetadata(directoryPath);
const paths = metadata.map(data => ({ slug: data.slug }));
console.log(paths);
return paths;
}
// console.log output
// { slug: 'post1_react_doc' },
// { slug: 'post2_gw' },
// { slug: 'post3_mobile_text_scale' },
// { slug: 'post4_html_to_mdx' }
このように return paths
; で受け取る可能性のある slug
を返せばOK。これでNext.jsは paths
の値を使ってbuildしてくれるはず。
これで動的ルーティングを静的にできたので以下のように Page()
の上に記述すればSSGになる。
// app/post/[slug]/page.tsx
export async function generateStaticParams() {
const directoryPath = path.join(process.cwd(), 'src', 'static', 'markdown');
const metadata = getMarkdownMetadata(directoryPath);
const paths = metadata.map(data => ({ slug: data.slug }));
return paths;
}
export default function Page({ params }: { params: { slug: string }}) {
const fullPath = path.join(process.cwd(), 'src', 'static', 'markdown', `${params.slug}.mdx`);
const fileContents = fs.readFileSync(fullPath, 'utf8');
const { content } = matter(fileContents);
return <CustomMDX source={content} />
}
// npm run build => log
Route (app) Size First Load JS
┌ ○ / 621 B 99.6 kB
├ ○ /_not-found 875 B 87.9 kB
├ ○ /icon.svg 0 B 0 B
└ ● /post/[slug] 292 B 92.4 kB
├ /post/post1_react_doc
├ /post/post2_gw
├ /post/post3_mobile_text_scale
└ /post/post4_html_to_mdx
+ First Load JS shared by all 87 kB
├ chunks/23-6de92bf77c16c86b.js 31.5 kB
├ chunks/fd9d1056-62aaf4b921c84028.js 53.7 kB
└ other shared chunks (total) 1.89 kB
○ (Static) prerendered as static content
● (SSG) prerendered as static HTML (uses getStaticProps)
表示速度が格段を上がって快適。SSGいい。
他にも定義していないページにアクセスした時のハンドリングができる dynamicParams
など、ドキュメントにいろいろ書いてあるので暇な時見てみる。(Next.jsDoc-generate-static-params)