diff --git a/crates/next-core/src/next_font_google/mod.rs b/crates/next-core/src/next_font_google/mod.rs index 56fdad8f40426..c8370af56a6a6 100644 --- a/crates/next-core/src/next_font_google/mod.rs +++ b/crates/next-core/src/next_font_google/mod.rs @@ -82,14 +82,19 @@ impl ImportMappingReplacement for NextFontGoogleReplacer { formatdoc!( r#" import cssModule from "@vercel/turbopack-next/internal/font/google/cssmodule.module.css?{}"; - export default {{ + const fontData = {{ className: cssModule.className, style: {{ fontFamily: "{}", {}{} }}, - variable: cssModule.variable }}; + + if (cssModule.variable != null) {{ + fontData.variable = cssModule.variable; + }} + + export default fontData; "#, // Pass along whichever options we received to the css handler qstring::QString::new(query.as_ref().unwrap().iter().collect()), @@ -362,10 +367,10 @@ async fn font_options_from_query_map(query: QueryMapVc) -> Result<NextFontGoogle // of Issues should be okay. let query_map = query_map .as_ref() - .context("@next/font/google queries must exist")?; + .context("next/font/google queries must exist")?; if query_map.len() != 1 { - bail!("@next/font/google queries must only have one entry"); + bail!("next/font/google queries must only have one entry"); } let Some((json, _)) = query_map.iter().next() else { diff --git a/crates/next-core/src/next_font_google/options.rs b/crates/next-core/src/next_font_google/options.rs index 3bf12d6a89792..3781913b43943 100644 --- a/crates/next-core/src/next_font_google/options.rs +++ b/crates/next-core/src/next_font_google/options.rs @@ -47,7 +47,7 @@ pub struct Axis { } // Transforms the request fields to a struct suitable for making requests to -// Google Fonts. Similar to @next/font/google's validateData: +// Google Fonts. Similar to next/font/google's validateData: // https://github.com/vercel/next.js/blob/28454c6ddbc310419467e5415aee26e48d079b46/packages/font/src/google/utils.ts#L22 pub fn options_from_request( request: &NextFontRequest, diff --git a/crates/next-core/src/next_font_google/request.rs b/crates/next-core/src/next_font_google/request.rs index 9cefc7072f258..181e0e49c562f 100644 --- a/crates/next-core/src/next_font_google/request.rs +++ b/crates/next-core/src/next_font_google/request.rs @@ -1,8 +1,8 @@ use serde::Deserialize; /// The top-most structure encoded into the query param in requests to -/// `@next/font/google` generated by the @next/font swc transform. e.g. -/// `@next/font/google/target.css?{"path": "index.js", "import": "Inter"...` +/// `next/font/google` generated by the next/font swc transform. e.g. +/// `next/font/google/target.css?{"path": "index.js", "import": "Inter"...` #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct NextFontRequest { diff --git a/crates/next-core/src/next_import_map.rs b/crates/next-core/src/next_import_map.rs index 3ff64de353206..390aae2ce0dd4 100644 --- a/crates/next-core/src/next_import_map.rs +++ b/crates/next-core/src/next_import_map.rs @@ -352,6 +352,12 @@ pub async fn insert_next_shared_aliases( package_root, ); + import_map.insert_alias( + // Request path from js via next-font swc transform + AliasPattern::exact("next/font/google/target.css"), + ImportMapping::Dynamic(NextFontGoogleReplacerVc::new(project_path).into()).into(), + ); + import_map.insert_alias( // Request path from js via next-font swc transform AliasPattern::exact("@next/font/google/target.css"), diff --git a/crates/next-core/src/next_shared/transforms.rs b/crates/next-core/src/next_shared/transforms.rs index 76f18eb979530..917bcb64d2f32 100644 --- a/crates/next-core/src/next_shared/transforms.rs +++ b/crates/next-core/src/next_shared/transforms.rs @@ -61,9 +61,15 @@ pub fn get_next_dynamic_transform_rule( /// Returns a rule which applies the Next.js font transform. pub fn get_next_font_transform_rule() -> ModuleRule { #[allow(unused_mut)] // This is mutated when next-font-local is enabled - let mut font_loaders = vec!["@next/font/google".to_owned()]; + let mut font_loaders = vec![ + "next/font/google".to_owned(), + "@next/font/google".to_owned(), + ]; #[cfg(feature = "next-font-local")] - font_loaders.push("@next/font/local".to_owned()); + { + font_loaders.push("next/font/local".to_owned()); + font_loaders.push("@next/font/local".to_owned()); + } ModuleRule::new( // TODO: Only match in pages (not pages/api), app/, etc. diff --git a/crates/next-dev-tests/tests/integration/next/font-google/at-next-font/__httpmock__/fonts.yml b/crates/next-dev-tests/tests/integration/next/font-google/at-next-font/__httpmock__/fonts.yml new file mode 100644 index 0000000000000..1038455d4a05c --- /dev/null +++ b/crates/next-dev-tests/tests/integration/next/font-google/at-next-font/__httpmock__/fonts.yml @@ -0,0 +1,74 @@ +when: + method: GET + path: /css2 + query_param: + - name: family + value: "Inter:ital,wght@0,100..900" + - name: display + value: optional +then: + status: 200 + body: |- + /* cyrillic-ext */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; + } + /* cyrillic */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; + } + /* greek-ext */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; + } + /* greek */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0370-03FF; + } + /* vietnamese */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; + } + /* latin-ext */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7W0Q5n-wU.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; + } + /* latin */ + @font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: optional; + src: url(https://fonts.gstatic.com/s/inter/v12/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7W0Q5nw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + } diff --git a/crates/next-dev-tests/tests/integration/next/font-google/at-next-font/input/pages/index.js b/crates/next-dev-tests/tests/integration/next/font-google/at-next-font/input/pages/index.js new file mode 100644 index 0000000000000..23da4f858db11 --- /dev/null +++ b/crates/next-dev-tests/tests/integration/next/font-google/at-next-font/input/pages/index.js @@ -0,0 +1,25 @@ +import { useEffect } from "react"; +import { Inter } from "@next/font/google"; + +const interNoArgs = Inter(); + +export default function Home() { + useEffect(() => { + // Only run on client + import("@turbo/pack-test-harness").then(runTests); + }); + + return <div className={interNoArgs.className}>Test</div>; +} + +function runTests() { + it("continues to be able to import from `@next/font/google`", () => { + expect(interNoArgs).toEqual({ + className: "className__inter_34ab8b4d__318bf44f", + style: { + fontFamily: "'__Inter_34ab8b4d'", + fontStyle: "normal", + }, + }); + }); +} diff --git a/crates/next-dev-tests/tests/integration/next/font-google/basic/input/pages/index.js b/crates/next-dev-tests/tests/integration/next/font-google/basic/input/pages/index.js index 613abc7987815..aa4c32f10d251 100644 --- a/crates/next-dev-tests/tests/integration/next/font-google/basic/input/pages/index.js +++ b/crates/next-dev-tests/tests/integration/next/font-google/basic/input/pages/index.js @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import { Inter } from "@next/font/google"; +import { Inter } from "next/font/google"; const interNoArgs = Inter(); const interWithVariableName = Inter({