mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
vinext@0.1.4
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
696948aca4 |
fix(next/font/google): use real axis range, validate options at build time (#885) (#893)
* shim: rewrite buildGoogleFontsUrl on top of the new build-url helper
Replace the inline URL builder in shims/font-google-base.ts with a thin
wrapper around the pure buildGoogleFontsUrl helper from PR 1
(packages/vinext/src/build/google-fonts/build-url.ts). The shim still
takes a FontOptions object and still returns a CSS URL, so external
callers and the existing 84 unit tests are unaffected.
Two visible behaviour changes:
1. Empty options no longer emit `:wght@100..900`. They emit no axis
segment at all, which makes Google return the default static face
(HTTP 200) for every font, including narrow-axis families like Sen
that previously got HTTP 400. This is the dev fallback only; the
build plugin always pre-resolves the real axis range from metadata
in production.
2. Italic-only requests no longer drop the ital axis. Pre-fix the outer
guard `weights.length > 0 || styles.length > 0` entered the block
but the inner branch only handled the wght path, so a call like
`Inter({ style: ['italic'] })` produced `family=Inter&display=swap`
with no italic anywhere in the URL. The shim now derives an ital
array from style and falls back to weight '400' when ital is set
without an explicit weight, so Google has somewhere to attach the
ital axis in the URL.
The shim deliberately does not import font-data.json or validate.ts: a
388 KB metadata file in the Worker bundle would dwarf the rest of the
shim, and the production path already has the metadata-aware variant.
Refs #885.
* plugin: validate options against metadata, surface HTTP errors as build errors
Replace the inline URL builder in plugins/fonts.ts with the pipeline added
in PR 1: validateGoogleFontOptions parses the call's options against the
bundled font metadata, getFontAxes resolves the actual `wght` range for
variable fonts, and buildGoogleFontsUrl emits the URL.
Three behaviour changes:
1. Variable fonts called with no `weight` now request the font's real
axis range (Sen 400..800, Inter 100..900) instead of a hardcoded
100..900. This is the user-visible fix for issue #885: Sen returns
HTTP 200 with all five face files instead of HTTP 400.
2. Validation errors surface as build errors with the source file path
attached. Unknown family, missing weight on a static font (Anton,
Archivo Black, etc.), unknown weight, mixing 'variable' with explicit
weights, axes on non-variable fonts, invalid display values, and
missing/unknown subsets are now all caught at transform time. Pre-fix
these silently produced URLs that Google rejected at request time.
3. HTTP non-2xx responses from Google are now distinguished from network
errors. A 4xx/5xx is wrapped in GoogleFontsHttpError and surfaced
with the failing URL plus the response body, because pre-fix the
silent `catch { return; }` skipped self-hosting and let the runtime
CDN path retry the same broken URL in the browser. Network errors
(offline dev) still fall through silently to keep `vp dev` usable
without a connection.
The fontCache key is the URL, so existing on-disk caches under
`.vinext/fonts/<hash>/` will be stale for affected fonts after this
change. One refetch per font on the next build.
Refs #885.
* tests: regression coverage for the #885 narrow-axis bug and validator throws
Five new tests in tests/font-google.test.ts plus subset additions to
existing fixtures whose Inter() / Roboto() calls were missing them.
Shim regressions:
- buildGoogleFontsUrl with empty options must not emit `:wght@100..900`
- buildGoogleFontsUrl with style-only options must keep the ital axis
visible in the URL
Plugin regressions:
- Sen() with no weight must fetch `:wght@400..800`, not `:wght@100..900`
- unknown families throw a build error with the file path attached
- non-variable fonts called without an explicit weight throw at build
time instead of silently emitting a broken URL
- HTTP 4xx/5xx from Google surfaces as a build error containing the URL
and the response body
- network errors (DNS, ECONNREFUSED, AbortError) still fall through
silently so offline dev keeps working
The existing plugin transform tests passed `Inter({ weight: '400' })`
without subsets; the validator now treats that as a missing-subsets
error (matches Next.js behaviour), so those fixtures gain
`subsets: ['latin']`. The two nested-brace regression tests still
exercise the parser's balanced-brace logic but use a benign
`_placeholder` field instead of `axes: { wght: 400 }`, which is
semantically invalid for Inter under the new validator.
Refs #885.
* address google font review feedback
|
||
|
|
428c199ec1 |
port Next.js Google Fonts metadata + URL pipeline (PR 1 of 2 for #885) (#892)
* vendor Google Fonts metadata from Next.js Adds packages/vinext/src/build/google-fonts/font-data.json (1911 entries, 388 KB pretty-printed) plus a typed re-export wrapper. The metadata enumerates each Google Font's available weights, styles, variable axes, and preloadable subsets, and is the source of truth a faithful next/font/google port needs to encode the right URL for variable fonts and reject invalid options at build time. Today vinext hardcodes :wght@100..900 in both the shim runtime URL builder and the build-time plugin, which produces HTTP 400 from Google for fonts whose wght axis is narrower (Sen 400..800, Anton single 400). Without metadata there is no way to emit the correct axis range, validate weights against the font's real options, or auto-disable preload for fonts with no preloadable subsets. The JSON itself is consumed only at build time and during dev. Production Workers run the self-hosted CSS injected by the build plugin and never read this file. The pretty-printed shape matches the upstream layout so future refreshes from canary remain reviewable. This commit only vendors the data and types. URL pipeline and validator land in the next two commits. Refs #885. * port Google Fonts URL pipeline from Next.js Adds three pure helpers under packages/vinext/src/build/google-fonts: sortFontsVariantValues (numeric variant comparator), buildGoogleFontsUrl (URL assembler), and getFontAxes (metadata-driven axis resolver). Each is a direct port of the matching module in vercel/next.js packages/font/src and has no defaults of its own. Defaults live in the validator (next commit). This is the layer that translates a validated options object into the URL shape Google Fonts CDN actually accepts. Sorting matters because Google rejects out-of-order variant lists with HTTP 400. The metadata-driven axis resolver is what lets a Sen({}) call produce :wght@400..800 instead of the broken :wght@100..900 default. No consumer wired up yet. The shim and plugin still call the old hardcoded URL builders; the integration lands in PR 2. Tests: 21 new tests across the three modules. Each helper is exercised in isolation against the vendored metadata, including the regression case from #885 (variable Sen resolves to wght 400..800) and the italic-only branch that vinext currently drops. Refs #885. * port Google Fonts options validator from Next.js Adds validateGoogleFontOptions, the parse-once boundary for next/font/google calls. Mirrors Next's validate-google-font-function-call.ts, dropping the SWC-coupled (functionName, fontFunctionArgument) signature in favour of (fontFamily, options). Returns ValidatedGoogleFontOptions, a type whose existence proves the input was rejected if Google would have rejected it. Behavior matches Next.js: throws on unknown family, unknown weight, mixing 'variable' with explicit weights, axes on non-variable fonts, axes without weight 'variable', invalid display, unknown subsets, preload with no subsets. Defaults missing weight to ['variable'] for variable fonts, and auto-disables preload for fonts with no preloadable subsets. This closes the loop on the URL pipeline added in the previous commit. Together with getFontAxes and buildGoogleFontsUrl, vinext now has a metadata-driven path from caller options to a valid Google Fonts URL. The shim and plugin still build URLs the old way; PR 2 wires this through. Tests: 16 new tests covering every throw branch and every default branch, plus an index.ts barrel that the future plugin import will use. The "auto-disable preload" test pins on Playwrite AR Guides, which has empty subsets in upstream metadata; if a future canary refresh adds a subset to that family the test will need a different fixture. Refs #885. * fold attribution into font-metadata header, drop unused exports Drop NOTICE.md and the index.ts barrel, demote four type aliases from exports to module-internal. Knip flagged the index file as unused (no consumer until PR 2) and the type aliases as unused exports for the same reason; YAGNI says wait for the consumer rather than ship dead public API. Vercel's MIT copyright on font-data.json is preserved in the font-metadata.ts header instead of in a sibling NOTICE.md, matching the in-tree pattern Next.js uses for vendored third-party files. Tests: vp run knip exits 0, 37 google-fonts tests still pass. * address PR 892 review: document subsets parity, harden preload-disable test `validateGoogleFontOptions` rejects `subsets: []` with `preload: true` where Next.js silently accepts it (Next uses a truthy check on `subsets`, vinext defaults to `[]` and checks `length`). The behavior is intentional (an empty subsets array with preload enabled is always a caller mistake), but undocumented divergence from a faithful port invites a future "fix back to upstream" PR. Annotate the divergence at the throw site. Auto-disable-preload test pins on `Playwrite AR Guides` having an empty subsets array in the bundled metadata. If a metadata refresh ever adds a subset to that family, the family-specific test silently flips into a false positive. Add an invariant test asserting the bundled metadata still contains at least one family with no preloadable subsets, so loss of branch coverage fails CI loud. |