-
Notifications
You must be signed in to change notification settings - Fork 308
fix(plugins): track font call ranges during transform #785
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c92de34
0e44a62
ed6295c
73858a1
0676075
68883af
65bb0de
c636958
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -729,6 +729,7 @@ export function createGoogleFontsPlugin(fontGoogleShimPath: string, shimsDir: st | |
|
|
||
| const replacement = `${calleeSource}(${optionsWithCSS})`; | ||
| s.overwrite(callStart, callEnd, replacement); | ||
| overwrittenRanges.push([callStart, callEnd]); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a correct fix. Every other That said, for the specific scenario described in the PR (two non-overlapping
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct fix. This was the only Note: for the specific |
||
| hasChanges = true; | ||
| } | ||
|
|
||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import type { Metadata } from "next"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding a nested layout with Consider either:
|
||
| import { Geist, Geist_Mono } from "next/font/google"; | ||
|
|
||
| const geistSans = Geist({ | ||
| variable: "--font-geist-sans", | ||
| subsets: ["latin"], | ||
| }); | ||
|
|
||
| const geistMono = Geist_Mono({ | ||
| variable: "--font-geist-mono", | ||
| subsets: ["latin"], | ||
| }); | ||
|
|
||
| export const metadata: Metadata = { | ||
| title: "Font Google Multiple Test", | ||
| }; | ||
|
|
||
| export default function RootLayout({ | ||
| children, | ||
| }: Readonly<{ | ||
| children: React.ReactNode; | ||
| }>) { | ||
| return ( | ||
| <html lang="en" className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}> | ||
| <body className="min-h-full flex flex-col">{children}</body> | ||
| </html> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| export default function HomePage() { | ||
| return ( | ||
| <main> | ||
| <h1>Font Google Multiple Test</h1> | ||
| <p>This page tests multiple Google Fonts (Geist + Geist_Mono).</p> | ||
| </main> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| { | ||
| "name": "font-google-multiple-fixture", | ||
| "private": true, | ||
| "type": "module", | ||
| "dependencies": { | ||
| "@vitejs/plugin-rsc": "catalog:", | ||
| "react": "catalog:", | ||
| "react-dom": "catalog:", | ||
| "react-server-dom-webpack": "catalog:", | ||
| "vinext": "workspace:*", | ||
| "vite": "catalog:" | ||
| }, | ||
| "devDependencies": { | ||
| "vite-plus": "catalog:" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,80 @@ | ||||||||||
| import { describe, it, expect, afterAll } from "vite-plus/test"; | ||||||||||
| import path from "node:path"; | ||||||||||
| import fs from "node:fs/promises"; | ||||||||||
| import os from "node:os"; | ||||||||||
| import { createBuilder } from "vite-plus"; | ||||||||||
| import vinext from "../packages/vinext/src/index.js"; | ||||||||||
|
|
||||||||||
| const APP_FIXTURE_DIR = path.resolve(import.meta.dirname, "./fixtures/font-google-multiple"); | ||||||||||
|
|
||||||||||
| async function buildFontGoogleMultipleFixture(): Promise<string> { | ||||||||||
| const outDir = await fs.mkdtemp(path.join(os.tmpdir(), "vinext-font-google-multiple-")); | ||||||||||
|
|
||||||||||
| const rscOutDir = path.join(outDir, "server"); | ||||||||||
| const ssrOutDir = path.join(outDir, "server", "ssr"); | ||||||||||
| const clientOutDir = path.join(outDir, "client"); | ||||||||||
|
|
||||||||||
| const originalFetch = globalThis.fetch; | ||||||||||
| globalThis.fetch = async (input: any) => { | ||||||||||
| const url = String(input); | ||||||||||
| if (url.includes("Geist") && !url.includes("Mono")) { | ||||||||||
| return new Response("@font-face { font-family: 'Geist'; src: url(/geist.woff2); }", { | ||||||||||
| status: 200, | ||||||||||
| headers: { "content-type": "text/css" }, | ||||||||||
| }); | ||||||||||
| } | ||||||||||
| return new Response("@font-face { font-family: 'Geist Mono'; src: url(/geist-mono.woff2); }", { | ||||||||||
| status: 200, | ||||||||||
| headers: { "content-type": "text/css" }, | ||||||||||
| }); | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| const nodeModulesLink = path.join(APP_FIXTURE_DIR, "node_modules"); | ||||||||||
|
|
||||||||||
| try { | ||||||||||
| const projectNodeModules = path.resolve(import.meta.dirname, "../node_modules"); | ||||||||||
| await fs.rm(nodeModulesLink, { recursive: true, force: true }); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: since this fixture is registered in Consider either:
|
||||||||||
| await fs.symlink(projectNodeModules, nodeModulesLink); | ||||||||||
|
|
||||||||||
| const builder = await createBuilder({ | ||||||||||
| root: APP_FIXTURE_DIR, | ||||||||||
| configFile: false, | ||||||||||
| plugins: [ | ||||||||||
| vinext({ | ||||||||||
| appDir: APP_FIXTURE_DIR, | ||||||||||
| rscOutDir, | ||||||||||
| ssrOutDir, | ||||||||||
| clientOutDir, | ||||||||||
| }), | ||||||||||
| ], | ||||||||||
| logLevel: "silent", | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| await builder.buildApp(); | ||||||||||
|
|
||||||||||
| return path.join(outDir, "server", "index.js"); | ||||||||||
| } finally { | ||||||||||
| globalThis.fetch = originalFetch; | ||||||||||
| await fs.unlink(nodeModulesLink).catch(() => {}); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: if the fixture already has a real |
||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| describe("font-google build integration", () => { | ||||||||||
| let buildOutputPath: string; | ||||||||||
| let outDir: string; | ||||||||||
|
|
||||||||||
| afterAll(async () => { | ||||||||||
| if (outDir) { | ||||||||||
| await fs.rm(outDir, { recursive: true, force: true }); | ||||||||||
| } | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| it("should build and transform multiple Google fonts (Geist + Geist_Mono)", async () => { | ||||||||||
| buildOutputPath = await buildFontGoogleMultipleFixture(); | ||||||||||
| outDir = path.dirname(path.dirname(buildOutputPath)); | ||||||||||
|
|
||||||||||
| const content = await fs.readFile(buildOutputPath, "utf-8"); | ||||||||||
| expect(content).toContain("Geist"); | ||||||||||
| expect(content).toContain("_selfHostedCSS"); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit:
Suggested change
Alternatively, you could count |
||||||||||
| }, 120000); | ||||||||||
| }); | ||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is a reasonable defensive improvement — it ensures
overwrittenRangesis consistent afterinjectSelfHostedCssruns, preventing theoretical double-overwrite of overlapping ranges.However, it does not fix issue #751. I verified by reverting this line and running the new test — it still passes. The two font calls (
Geist(...)andGeist_Mono(...)) occupy non-overlapping character ranges in the original source, so the overlap check at line 757 was never triggered.The actual error from #751 (
Unexpected token in app/layout.tsx at 234..235) likely originates from a different part of the build pipeline. To find the real cause, someone needs to reproduce the build failure with the reproduction repo and trace the actual error through the Vite build.