kikuta@dev:~$ls -lt ./notes
kikuta@dev:~$cat ./notes/cloudflare-pages-personal-site.md
·9 min·kikuta

Next.js静的サイトをCloudflare Pagesへ出す:build・sitemap・独自ドメインを別々に検証する

kikuta.devの実構成を使い、Next.js static exportからCloudflare Pages deploy、custom domainのproduction確認までを分離する。

使える場面

Next.jsの静的サイトをCloudflare Pagesへ出しているが、build成功だけで独自domain・sitemap・metadataまで正しいと思い込んでいるとき。

持ち帰れるもの

static export、content-driven sitemap、metadataBase、Cloudflare deploy、production URL検証を別gateとして確認する方法。

本番成果物をoutディレクトリへ固定する

kikuta.devではNext.jsのnext.config.jsにoutput: “export”を設定しています。production buildの結果は静的なoutディレクトリへ落ちるため、Cloudflare側でNode.js application serverを動かすことを本番要件にしていません。

ローカルではpnpm lint、pnpm exec tsc –noEmit、pnpm exec next build –webpack、git diff –checkを通してから配布します。buildが通るか、型が通るか、不要なwhitespace差分がないかを一つの結果へまとめず、別のfailureとして確認しています。

URL一覧を手で二重管理しない

記事とProjectはsrc/lib/content.tsの配列を正本にし、sitemap.tsはその配列から/articles/と/projects/を生成します。新しい技術記事を追加したのにsitemapへ書き忘れる、Projectを削除したのに古いURLだけ残る、といった二重管理を避けるためです。

root layoutではmetadataBaseをhttps://kikuta.devへ固定し、各記事・Project側はrelative canonicalを返します。Open Graphやcanonicalの基準URLをpageごとに文字列連結しないことで、metadataの生成規則も一箇所へ寄せています。

Pagesへのdeploy成功とcustom domainの公開成功は別

配布はnpx wrangler pages deploy out –project-name kikutaで行います。Wranglerが返すpages.devのdeployment URLはupload結果を確認するには便利ですが、利用者とcrawlerが見るkikuta.devで同じHTMLが返ることまでは証明しません。

そのためdeploy後はkikuta.devの実URLへcurl -fsSLを送り、今回追加した見出し・Project link・article linkなど具体的な文字列を検査します。『Cloudflareのdeploy commandが0で終了した』ではなく、『public URLから期待したartifactを読める』を最後のacceptanceにしています。

robotsとsitemapもbuild対象として扱う

robots.tsとsitemap.tsもNext.jsのstatic routeとして生成します。robotsは全pathをallowし、sitemapとhostをkikuta.devへ向けます。記事本文だけ更新して終わりではなく、公開surfaceに含まれるmachine-readableな入口も同じbuildから出力します。

この構成の利点はCloudflare Pages固有の設定を増やさないことです。content、metadata、sitemap、robotsをNext.js側のsourceへ置き、Cloudflare Pagesは生成済みの静的成果物を配る役割へ絞っています。