[PR #719] [MERGED] fix(fonts): double-comma syntax error when font options have a trailing comma #797

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

📋 Pull Request Information

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

Base: mainHead: james/fonts-fix


📝 Commits (1)

  • 12694cd fix(fonts): double-comma syntax error when font options have a trailing comma

📊 Changes

2 files changed (+45 additions, -1 deletions)

View changed files

📝 packages/vinext/src/plugins/fonts.ts (+7 -1)
📝 tests/font-google.test.ts (+38 -0)

📄 Description

Problem

vinext build failed with a cryptic [builtin:vite-transform] Error: Unexpected token in app/layout.tsx at 191..192 for any project that used next/font/google with trailing-comma style (common with Prettier defaults):

const inter = Inter({
  subsets: ["latin"],  // ← trailing comma
});

The error position and file name were both misleading — the reported byte offset pointed into function Layout in the original source, but the actual failure was in the transformed code produced by the vinext:google-fonts Vite plugin.

Root cause

injectSelfHostedCss (in packages/vinext/src/plugins/fonts.ts) injects a _selfHostedCSS property into the font constructor's options object at build time. It computed the separator before the new property as:

// separator = "" if object is empty, ", " otherwise
optionsStr.slice(0, closingBrace).trim().endsWith("{") ? "" : ", "

This only handled the empty-object case. When the options already had a trailing comma, the trimmed content ended with ,, not {, so it unconditionally prepended , and produced a double comma:

Inter({
  subsets: ["latin"],
, _selfHostedCSS: "..."  // syntax error
})

Rolldown's builtin:vite-transform native plugin then failed to parse this invalid JS, attributing the error to a byte offset in the MagicString sourcemap that mapped back to an unrelated position in the original source file.

Fix

Extend the separator check to also skip , when the content already ends with a trailing comma:

const beforeBrace = optionsStr.slice(0, closingBrace).trim();
const separator = beforeBrace.endsWith("{") || beforeBrace.endsWith(",") ? "" : ", ";

Also adds a regression test (does not produce double-comma when font options have a trailing comma) to tests/font-google.test.ts.


🔄 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/719 **Author:** [@james-elicx](https://github.com/james-elicx) **Created:** 3/30/2026 **Status:** ✅ Merged **Merged:** 3/30/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `james/fonts-fix` --- ### 📝 Commits (1) - [`12694cd`](https://github.com/cloudflare/vinext/commit/12694cd7fe18822ce05a089821018e93e68a11ff) fix(fonts): double-comma syntax error when font options have a trailing comma ### 📊 Changes **2 files changed** (+45 additions, -1 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/plugins/fonts.ts` (+7 -1) 📝 `tests/font-google.test.ts` (+38 -0) </details> ### 📄 Description Problem `vinext build` failed with a cryptic `[builtin:vite-transform] Error: Unexpected token in app/layout.tsx at 191..192` for any project that used `next/font/google` with trailing-comma style (common with Prettier defaults): ```ts const inter = Inter({ subsets: ["latin"], // ← trailing comma }); ``` The error position and file name were both misleading — the reported byte offset pointed into `function Layout` in the original source, but the actual failure was in the **transformed** code produced by the `vinext:google-fonts` Vite plugin. ## Root cause `injectSelfHostedCss` (in `packages/vinext/src/plugins/fonts.ts`) injects a `_selfHostedCSS` property into the font constructor's options object at build time. It computed the separator before the new property as: ```ts // separator = "" if object is empty, ", " otherwise optionsStr.slice(0, closingBrace).trim().endsWith("{") ? "" : ", " ``` This only handled the empty-object case. When the options already had a trailing comma, the trimmed content ended with `,`, not `{`, so it unconditionally prepended `, ` and produced a double comma: ```js Inter({ subsets: ["latin"], , _selfHostedCSS: "..." // syntax error }) ``` Rolldown's `builtin:vite-transform` native plugin then failed to parse this invalid JS, attributing the error to a byte offset in the MagicString sourcemap that mapped back to an unrelated position in the original source file. ## Fix Extend the separator check to also skip `, ` when the content already ends with a trailing comma: ```ts const beforeBrace = optionsStr.slice(0, closingBrace).trim(); const separator = beforeBrace.endsWith("{") || beforeBrace.endsWith(",") ? "" : ", "; ``` Also adds a regression test (`does not produce double-comma when font options have a trailing comma`) to `tests/font-google.test.ts`. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:10:09 +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#797
No description provided.