この記事はCodex製です。
##依頼内容と課題
https://ro1.dev/memo や https://ro1.dev/note の記事詳細ページで、ページ自体は 200 を返すものの本文が空になり、記事詳細として正しく表示されない不具合を直す依頼だった。
調査したところ、Cloudflare Workers 上の詳細ページでは __NEXT_DATA__ の post.content が空文字になっていた。/memo/raw/...md や /note/raw/...md の raw markdown asset は配信されているが、詳細ページの getStaticProps 側で raw content を取得できない場合に本文が空のまま HTML 化されていた。
##アプローチ
根本原因は、詳細ページが本文を runtime fetch に依存していたことだった。Cloudflare Workers / OpenNext 環境では同一 origin の raw markdown を server-side fallback として取得できないケースがあり、失敗時に fetchRawContent が空文字を返すため、記事 shell と metadata だけが出て本文が消えていた。
そこで、raw markdown を fetch する前に、ビルド時の Node.js 環境では public/.../raw/*.md をローカルファイルとして直接読むようにした。これにより、Cloudflare Workers / OpenNext の production build でも記事本文が getStaticProps に入る。
当初は snapshot JSON に本文を入れる案も試したが、Workers の script size が無料枠 3 MiB を超えてデプロイできなかったため採用しなかった。最終版では snapshot の肥大化を避け、raw markdown を build-time local read する方針にした。
##アウトプット
src/lib/fetch-raw-content.tsを更新public配下の raw markdown をnode:fs/promisesで読む fallback を追加- Cloudflare Workers runtime では OpenNext が
globalThis[Symbol.for("__cloudflare-context__")]に載せるenv.ASSETSbinding から raw markdown を読む fallback を追加 - local read と
ASSETSbinding read が失敗した場合だけ従来どおりhttps://ro1.dev/.../raw/...mdを fetch ..を含む raw path は読まないよう簡易ガードを追加
scripts/generate-content-snapshots.mjsは snapshot に本文を含めない形へ戻し、Worker サイズ増加を避けたsrc/lib/memo/snapshot.jsonとsrc/lib/note/snapshot.jsonを再生成bun run typecheckが成功することを確認
検証では、代表 URL の raw markdown は本番で 200 を返している一方、詳細ページの post.content が空だった。修正後の local build では .next/server/pages/memo/2026/05/youtube-video-registry-duplicate-guard.html と .next/server/pages/note/prog_nextjs_vercel_supabase.html に本文要素が入り、__NEXT_DATA__ の content も空でないことを確認した。さらに globalThis[Symbol.for("__cloudflare-context__")].env.ASSETS.fetch を模擬した tsx 実行で、Worker runtime 側の asset fallback が frontmatter を除いた本文を返すことを確認した。bun run build は next build / OGP 生成が長時間化したため完走確認までは行っていない。
推論: raw asset 自体は正常に配信されているため、今回の問題は asset 欠落ではなく、詳細ページ生成時の server-side fallback fetch に依存していた設計が Workers build/runtime 環境で空振りすることにある。OpenNext の Workers runtime では同一 origin fetch よりも ASSETS binding を直接読むほうが、生成済み静的 asset への依存として明確で安全。
##参照した一次情報
https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props
https://nextjs.org/docs/pages/api-reference/functions/get-static-paths
https://opennext.js.org/cloudflare
https://developers.cloudflare.com/workers/runtime-apis/fetch/