Skip to content

Generate docs OG PNGs at build time (fixes 500s on preview)#8

Merged
jrphilo merged 1 commit into
mainfrom
og-static
Apr 22, 2026
Merged

Generate docs OG PNGs at build time (fixes 500s on preview)#8
jrphilo merged 1 commit into
mainfrom
og-static

Conversation

@jrphilo
Copy link
Copy Markdown
Collaborator

@jrphilo jrphilo commented Apr 22, 2026

Summary

The /og/* routes using next/og's ImageResponse worked on Vercel but failed on Cloudflare — @opennextjs/cloudflare serves force-static route-handler bodies through an incremental cache adapter, and our config has no backend wired up, so the worker fell through to executing the handler at request time. The handler's readFileSync() calls for fonts + brand PNGs then crashed (Workers have no filesystem), returning 500 on every OG URL on preview.happyhq.com.

Switches to the same pattern as the welcome repo: a Node script walks the content markdown at build time, renders PNGs via satori + @resvg/resvg-js, and writes into public/og/. Next serves them as plain static assets via the edge CDN — no worker execution per share, no ISR cache plumbing, no R2 dependency.

Changes

  • New: scripts/generate-og.mjs (walks docs + changelog, renders 39 PNGs), scripts/og/card.mjs (cream card, ported from the deleted route handler), fonts moved from src/app/og/_fonts/scripts/og/
  • Deleted: all three src/app/og/*/route.tsx files + src/app/og/_lib/
  • Updated: page.tsx metadata in docs + changelog now references /og/.../<slug>.png
  • Build wiring: prebuild now runs a new build:pre script (content manifest + OG generator)
  • public/og/ is gitignored (build output)

Test plan

  • pnpm build passes; 39 PNGs generated under public/og/
  • pnpm start serves /og/docs.png, /og/docs/start-here/install.png, /og/docs/concepts/chat.png, /og/changelog.png, /og/changelog/2026-04-19-multi-surface.png → all 200
  • Rendered HTML's <meta property="og:image"> points at /og/.../<slug>.png
  • After CF dashboard update, verify preview serves PNGs (200) and Slack/Twitter preview cards render correctly

🤖 Generated with Claude Code

…ndlers

The /og/* routes rendered via next/og's ImageResponse worked on Node/Vercel
but failed on Cloudflare — @opennextjs/cloudflare serves force-static route
handler bodies through an incremental cache backend, and with no backend
configured the worker fell through to running the handler at request time.
The handler's readFileSync() calls for fonts and brand PNGs then crashed
(Workers have no filesystem), returning 500 on every OG URL.

Switch to the same pattern as the welcome repo: a Node script walks the
content markdown at build time, renders one PNG per page via satori +
@resvg/resvg-js, and writes into public/og/. Next then serves them as
plain static assets via the edge CDN — no worker execution per share, no
ISR cache plumbing, no R2 dependency.

The cream card design (wordmark top-left, green bush top-right, eyebrow +
title + description bottom-left) is ported from the deleted route handler
into scripts/og/card.mjs. Title font auto-shrinks for long headlines.
Metadata in page.tsx now points at /og/.../<slug>.png.

CF build command needs a one-line update to run prebuild steps explicitly,
since opennextjs-cloudflare invokes next build directly and bypasses the
npm prebuild hook. New command: pnpm install && pnpm run build:pre && pnpm
exec opennextjs-cloudflare build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
docs-preview 304beb7 Commit Preview URL

Branch Preview URL
Apr 22 2026, 10:51 PM

@jrphilo jrphilo merged commit 2d8fc8f into main Apr 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant