Vendoring the fonts (#730) removed the build's dependency on Google, and cost one thing worth
recording: next/font used to emit <link rel="preload" as="font" crossorigin> for the eight
preloadable latin faces. Production now emits zero — verified against the live site.
Impact, stated honestly
Small, and not a correctness bug:
- The faces still load. Verified on prod: 70
@font-face blocks, 34 woff2, and a real file
serving HTTP 200 · 24,900 bytes · font/woff2.
font-display: swap still applies, and the six size-adjust/ascent-override fallback
faces survived vendoring — so text renders immediately in a metric-matched fallback and
there is no layout shift.
What is lost is discovery time. With a preload the browser starts fetching the face from the
HTML; without one it must parse the CSS and reach layout first. That is a slightly longer FOUT
on a cold cache, most visible on a slow connection.
Why it is not a one-line fix
The filenames are content-hashed by the bundler — on prod they carry a second hash,
0c310187b552b27d-s.0c310187.woff2 — so a preload link cannot be hardcoded in layout.tsx.
Options, roughly in order of how much they touch:
- Import the font files in TS so the bundler resolves the URLs, then render the eight
<link rel="preload"> tags from those values. Keeps a single source of truth. The .p
suffix already marks which faces next/font considered preloadable, so the set is known.
- Emit the tags from the vendoring script into a generated TS module that
layout.tsx
imports — same idea, but the hash is only correct if the script runs after every build that
changes a font, which is fragile.
- Accept it. With
swap plus metric-matched fallbacks the visible cost is small, and the
build no longer depends on a third party. This is a defensible trade — it just should be a
decision rather than an oversight.
Do not
Re-introduce next/font/google to get the preloads back. That restores the build-time
dependency on fonts.gstatic.com that broke a production deploy and a CI shard inside twelve
hours, which is a strictly worse failure than a marginally later font fetch.
tests/unit/fonts-vendored.test.ts will fail if anyone tries.
Related
Vendoring the fonts (#730) removed the build's dependency on Google, and cost one thing worth
recording:
next/fontused to emit<link rel="preload" as="font" crossorigin>for the eightpreloadable latin faces. Production now emits zero — verified against the live site.
Impact, stated honestly
Small, and not a correctness bug:
@font-faceblocks, 34 woff2, and a real fileserving
HTTP 200 · 24,900 bytes · font/woff2.font-display: swapstill applies, and the sixsize-adjust/ascent-overridefallbackfaces survived vendoring — so text renders immediately in a metric-matched fallback and
there is no layout shift.
What is lost is discovery time. With a preload the browser starts fetching the face from the
HTML; without one it must parse the CSS and reach layout first. That is a slightly longer FOUT
on a cold cache, most visible on a slow connection.
Why it is not a one-line fix
The filenames are content-hashed by the bundler — on prod they carry a second hash,
0c310187b552b27d-s.0c310187.woff2— so a preload link cannot be hardcoded inlayout.tsx.Options, roughly in order of how much they touch:
<link rel="preload">tags from those values. Keeps a single source of truth. The.psuffix already marks which faces
next/fontconsidered preloadable, so the set is known.layout.tsximports — same idea, but the hash is only correct if the script runs after every build that
changes a font, which is fragile.
swapplus metric-matched fallbacks the visible cost is small, and thebuild no longer depends on a third party. This is a defensible trade — it just should be a
decision rather than an oversight.
Do not
Re-introduce
next/font/googleto get the preloads back. That restores the build-timedependency on
fonts.gstatic.comthat broke a production deploy and a CI shard inside twelvehours, which is a strictly worse failure than a marginally later font fetch.
tests/unit/fonts-vendored.test.tswill fail if anyone tries.Related
--font-*variables live on
:root.