mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #920] [MERGED] fix(fonts): google fonts building perfectly (it was just a regex 😭) #948
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#948
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/920
Author: @MrIago
Created: 4/27/2026
Status: ✅ Merged
Merged: 4/27/2026
Merged by: @james-elicx
Base:
main← Head:fix/font-google-working-fine📝 Commits (3)
3096114fix(fonts): google fonts building perfectly (it was just a regex 😭)82d80fcfix(fonts): allow newlines inside bracket clausesdff1643fix(fonts): apply formatter to test file📊 Changes
2 files changed (+68 additions, -1 deletions)
View changed files
📝
packages/vinext/src/plugins/fonts.ts(+11 -1)📝
tests/font-google.test.ts(+57 -0)📄 Description
What this is, in one breath
If you copy the exact sample from the official Next.js font docs into a vinext project, the build dies.
Not because your code is wrong. Not because vinext doesn't support it. Because of how your code formatter ends each line.
Wait, what?
Modern formatters — Prettier, Biome, oxfmt — all ship without trailing semicolons by default. That's how
import { Inter } from 'next/font/google'shows up in 90%+ of new Next.js projects today.In vinext, the absence of those semicolons made the font plugin's regex misfire. The rewrite was silently skipped. Rolldown then complained about a missing export, and the build was dead.
Same code. Same import. Different format. One worked, one didn't.
Why this matters
This wasn't a niche edge case. It was the canonical path:
vinext init.Every one of them hit a wall.
How small the actual fix was
Two characters.
\nadded to a single regex (twice — once for imports, once for exports).The regex was written to stop at
;. Now it also stops at line breaks. That's it. The rest of the font pipeline was already correct.Proof it works
A real Cloudflare Workers project that wouldn't deploy now deploys cleanly:
Tested with Inter, Geist, and Architects_Daughter — swapping the font name is now a no-op, exactly as the docs promise.
For reviewers (the technical bit)
Click to expand — root cause walk-through
The plugin scans source files for
import … from 'next/font/google'with a regex. The clause portion was[^;]+?— "any character that isn't a;, lazy".When the previous line in the file lacks a
;, that lazy match still has to eventually hitnext/font/google. So it walks across the\nand consumes the previous import line on its way down. The captured clause looks like:That mangled clause goes into
parseGoogleFontImportClause(), returns nofontImports, and the rewrite branch is skipped.hasChangesstaysfalse, the transform returnsnull, andIntersurvives untouched into rolldown — which then can't find a named export on the Proxy-default shim.The fix:
Same change on
exportRefor parity ({ … }clause).A full ESM parser would have been overkill — the transform's
filteralready opts in only whencode: "next/font/google"is present, and the regex sweep is what keeps the hot path Rust-side. The minimal regex change preserves that contract.Why your existing tests didn't catch it
Every fixture in
tests/font-google.test.tswrites imports with trailing;. Reasonable style, just not the modern default.Added a regression test that mirrors a real Prettier-default 3-line layout. Asserts (a) the font import gets rewritten, (b) the unrelated preceding
import typeline is left untouched.Validation
pnpm test run tests/font-google.test.ts— 100 passed (1 added)pnpm run check— format, lint, typecheck greenvinext@0.0.44,@vitejs/plugin-rsc@0.5.24,@cloudflare/vite-plugin@1.32.3)Refs
next-font-loaderparser is line-bounded by construction because SWC emits one font import per call into the resourceQuery: https://github.com/vercel/next.js/blob/canary/packages/next/src/build/webpack/loaders/next-font-loader/index.ts#L25-L31🧠 Thought by a Human (@MrIago) · 🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.