[PR #1038] [MERGED] fix(dev): self-host Google Fonts in dev mode #1040

Closed
opened 2026-05-06 13:11:41 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/1038
Author: @james-elicx
Created: 5/3/2026
Status: Merged
Merged: 5/3/2026
Merged by: @james-elicx

Base: mainHead: claude/stoic-rosalind-dcd524


📝 Commits (1)

  • ca90964 fix(dev): self-host Google Fonts in dev mode

📊 Changes

5 files changed (+163 additions, -64 deletions)

View changed files

📝 packages/vinext/src/plugins/fonts.ts (+108 -60)
tests/e2e/app-router/font-google.spec.ts (+15 -0)
tests/fixtures/app-basic/app/font-google-test/layout.tsx (+19 -0)
tests/fixtures/app-basic/app/font-google-test/page.tsx (+8 -0)
📝 tests/font-google.test.ts (+13 -4)

📄 Description

Summary

The build pipeline already rewrites next/font/google calls to embed self-hosted @font-face CSS pointing at /<assetsDir>/_vinext_fonts/..., but the call-site rewrite was gated behind isBuild. In dev:

  • Those URLs 404'd because nothing copies the cached .vinext/fonts/ files into the dev server's served paths.
  • Once _selfHostedCSS is present, the shim no longer emits the fonts.googleapis.com <link> — so dev showed unstyled glyphs with no CDN fallback either.

This PR:

  • Drops the build-only gate so the call-site rewrite (and _selfHostedCSS injection) runs in dev too.
  • Adds a configureServer middleware that serves cached files directly from .vinext/fonts/ under the same URL prefix _rewriteCachedFontCssToServedUrls() embeds.
  • Reuses the prod CONTENT_TYPES map so dev and prod hand out identical MIME types.
  • Cleans up the now-unused isBuild closure variable and the dead { } block left after removing the gate.

Regression test

tests/e2e/app-router/font-google.spec.ts navigates to a new /font-google-test route in the app-basic fixture that uses Geist + Geist_Mono, then:

  1. Asserts no fonts.googleapis.com URL leaks into the HTML.
  2. Asserts a <style data-vinext-fonts> block is present.
  3. Pulls a preload URL out of the HTML and fetches it — verifies HTTP 200, Content-Type: font/woff2, and a real body. This is the layer that catches both the CDN-leakage and the middleware-broken regressions in one shot.

The spec runs under the existing app-router Playwright project, so no new CI matrix entry is needed.

Test plan

  • vp test tests/font-google.test.ts tests/font-google-build.test.ts — 104 passed
  • PLAYWRIGHT_PROJECT=app-router npx playwright test --project=app-router tests/e2e/app-router/font-google.spec.ts — passing
  • Verify CI green across all Playwright projects (the gate removal also affects app-router/app-with-src since they import next/font/local, which is a different plugin — but worth confirming nothing regresses)

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/1038 **Author:** [@james-elicx](https://github.com/james-elicx) **Created:** 5/3/2026 **Status:** ✅ Merged **Merged:** 5/3/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `claude/stoic-rosalind-dcd524` --- ### 📝 Commits (1) - [`ca90964`](https://github.com/cloudflare/vinext/commit/ca909640501ab78c3b072ef4222774b6b07b89e5) fix(dev): self-host Google Fonts in dev mode ### 📊 Changes **5 files changed** (+163 additions, -64 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/plugins/fonts.ts` (+108 -60) ➕ `tests/e2e/app-router/font-google.spec.ts` (+15 -0) ➕ `tests/fixtures/app-basic/app/font-google-test/layout.tsx` (+19 -0) ➕ `tests/fixtures/app-basic/app/font-google-test/page.tsx` (+8 -0) 📝 `tests/font-google.test.ts` (+13 -4) </details> ### 📄 Description ## Summary The build pipeline already rewrites `next/font/google` calls to embed self-hosted `@font-face` CSS pointing at `/<assetsDir>/_vinext_fonts/...`, but the call-site rewrite was gated behind `isBuild`. In dev: - Those URLs 404'd because nothing copies the cached `.vinext/fonts/` files into the dev server's served paths. - Once `_selfHostedCSS` is present, the shim no longer emits the `fonts.googleapis.com` `<link>` — so dev showed unstyled glyphs with no CDN fallback either. This PR: - Drops the build-only gate so the call-site rewrite (and `_selfHostedCSS` injection) runs in dev too. - Adds a `configureServer` middleware that serves cached files directly from `.vinext/fonts/` under the same URL prefix `_rewriteCachedFontCssToServedUrls()` embeds. - Reuses the prod `CONTENT_TYPES` map so dev and prod hand out identical MIME types. - Cleans up the now-unused `isBuild` closure variable and the dead `{ }` block left after removing the gate. ## Regression test `tests/e2e/app-router/font-google.spec.ts` navigates to a new `/font-google-test` route in the `app-basic` fixture that uses `Geist` + `Geist_Mono`, then: 1. Asserts no `fonts.googleapis.com` URL leaks into the HTML. 2. Asserts a `<style data-vinext-fonts>` block is present. 3. Pulls a preload URL out of the HTML and fetches it — verifies HTTP 200, `Content-Type: font/woff2`, and a real body. This is the layer that catches both the CDN-leakage and the middleware-broken regressions in one shot. The spec runs under the existing `app-router` Playwright project, so no new CI matrix entry is needed. ## Test plan - [x] `vp test tests/font-google.test.ts tests/font-google-build.test.ts` — 104 passed - [x] `PLAYWRIGHT_PROJECT=app-router npx playwright test --project=app-router tests/e2e/app-router/font-google.spec.ts` — passing - [ ] Verify CI green across all Playwright projects (the gate removal also affects `app-router`/`app-with-src` since they import `next/font/local`, which is a different plugin — but worth confirming nothing regresses) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:11:41 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#1040
No description provided.