Skip to content

fix: OG image fonts, per-request gateway, NuxtImg everywhere, config tidy-up - #246

Merged
kashalls merged 4 commits into
mainfrom
claude/nuxt-config-tuning
Oct 5, 2026
Merged

kashalls merged 4 commits into
mainfrom
claude/nuxt-config-tuning

Conversation

@kashalls

@kashalls kashalls commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Summary

Follow-up to the Nuxt config review: these are the remaining items after #245.

Fonts and OG images (fix(fonts))

  • OG images were never using PP Neue Machina. During prerender, nuxt-og-image resolves /_fonts/* only from .output/public. Nuxt hasn't copied public assets there yet when prerender runs, so every build warned not found in mapping or cache and the images fell back to Inter. Files outside /_fonts/ are read from public/ directly, so the fonts now live in public/fonts/.
  • Converted the 12 OTF files to WOFF2: 1.5 MB → 640 KB. nuxt-og-image decodes WOFF2 to TTF for satori (see _og-static-fonts/).
  • /fonts/** is now cached for 30 days. It's not marked immutable, because the filenames aren't content-hashed.
  • The OG title weight changes from 800 to 700. @nuxt/fonts registers Ultrabold as 700, and the OG converter only picks fonts whose weight matches exactly. It's the same Ultrabold face; before this, the title rendered in bold Inter.

Gateway (fix(gateway))

/gateway shows the requesting hostname, but it was prerendered, so the HTML said localhost until hydration (and always did for crawlers and users without JS). It's now prerender: false and rendered per request. Its OG image is dropped, because zeroRuntime OG images require prerendering.

Config cleanup (chore(config))

  • Removed future.compatibilityVersion: 4; it's the default on Nuxt 4.
  • Removed turnstile.siteKey: process.env.NUXT_TURNSTILE_SITE_KEY. It's read at build, and container builds never had it. The module already registers both keys in runtime config (verified in the built output), so set NUXT_PUBLIC_TURNSTILE_SITE_KEY and NUXT_TURNSTILE_SECRET_KEY in the container environment.
  • sourcemap: { server: false }.
  • Removed the Cloudflare comments for the OG renderer and the KV cache block. The production cache stays in memory, which is fine for a single replica; persisting it would need a writable volume, since the image runs as nonroot.

NuxtImg everywhere (refactor)

  • Replaced the 15 remaining raw <img> tags in the Discord and game cards with <NuxtImg>. @nuxt/image stays; UAvatar already renders through NuxtImg when it's installed.
  • The provider is still none (passthrough), so the image URLs are unchanged. Switching to ipx for real resizing on the Node server would be a separate change, and would need the Blizzard/Overwatch hosts added to domains.
  • Updated the stale Cloudflare comment on the image config.

Testing

  • nuxt build: no OG font warnings; _og-static-fonts now contains PPNeueMachinaInktrap-Regular.ttf and -Ultrabold.ttf, and I checked the rendered OG PNG by eye.
  • 10 routes prerender (previously 13: /gateway plus its payload and OG image are no longer prerendered).
  • Container: /, /blog, /blog/hello-world, /gateway and /api/github return 200. /gateway with Host: nothing.example.com renders that hostname. /fonts/*.woff2 is served as font/woff2 with cache-control: public, max-age=2592000.
  • Headless Chromium against the built server: all 15 images on the homepage, across the Discord card and the WoW/Overwatch cards, render as NuxtImg (data-nuxt-img), and there are no raw <img> tags. The game APIs don't send CORS headers for localhost, so that check ran with web security disabled.

🤖 Generated with Claude Code

kashalls and others added 4 commits October 4, 2026 23:20
…them

During prerender, nuxt-og-image resolves /_fonts/* only from
.output/public, which Nuxt has not populated yet, so every OG image fell
back to Inter. Files outside /_fonts/ are read from public/ directly.

Move the PP Neue Machina files to public/fonts, convert them from OTF
to WOFF2 (1.5 MB to 640 KB; nuxt-og-image decodes them for satori), and
cache them for 30 days. The OG title uses weight 700 because that is
the weight @nuxt/fonts assigns to Ultrabold, and the OG converter only
picks exact weight matches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jordan Jones <git@svcs.ok8.sh>
The page shows the requesting hostname, but prerendering baked in
`localhost` until hydration. Render it per request and drop its OG
image, which required prerendering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jordan Jones <git@svcs.ok8.sh>
- drop `future.compatibilityVersion: 4`, the default on Nuxt 4
- drop `turnstile.siteKey` read from process.env at build; container
  builds never had it, and the runtime keys already come from
  NUXT_PUBLIC_TURNSTILE_SITE_KEY / NUXT_TURNSTILE_SECRET_KEY
- disable server sourcemaps
- remove Cloudflare-specific comments

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jordan Jones <git@svcs.ok8.sh>
Use <NuxtImg> for the remaining raw <img> tags in the Discord and game
cards so every image goes through @nuxt/image, and drop the stale
Cloudflare note from the image config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jordan Jones <git@svcs.ok8.sh>
@kashalls
kashalls force-pushed the claude/nuxt-config-tuning branch from 2aef845 to 50c66c6 Compare October 5, 2026 06:36
@kashalls kashalls changed the title fix: OG image fonts, per-request gateway, and Nuxt config tidy-up fix: OG image fonts, per-request gateway, NuxtImg everywhere, config tidy-up Oct 5, 2026
@kashalls
kashalls merged commit fec48f4 into main Oct 5, 2026
3 checks 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