mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-28 07:32:52 +00:00
noindex, the font preload, the canonical and the markdown link were each a process that read the pages from disk and wrote back what it changed: 8.6 s of every deploy (run 39431048221). scripts/export.mjs reads every page at once, runs the same passes in the same order over memory, and writes each changed page once; wellknown and skill follow as before. On the export rebuilt from the live pages the output is byte for byte what the four processes wrote, .md files, llms.txt and skill.md included, in 4.8 s where they took 12.7 on the same box.
110 lines
5.2 KiB
JavaScript
110 lines
5.2 KiB
JavaScript
/**
|
|
* The typeface starts downloading with the document, not after it.
|
|
*
|
|
* THE FLASH THIS REMOVES, measured on the export at 1440x900 over a 400 kbps
|
|
* link with 150 ms latency (scripts are in-repo: e2e/flash.mjs):
|
|
*
|
|
* 327 ms the three stylesheets begin arriving (233 KB together)
|
|
* 2230 ms they finish parsing — layout appears, sidebar resolves to its width
|
|
* 3340 ms Zen-Variable.woff2 arrives, and only NOW is there type
|
|
*
|
|
* Between 2230 and 3340 the page is fully laid out and holds NO WORDS. Not the
|
|
* wrong font — no font: `@hanzo/design/tokens/fonts.css` declares both faces
|
|
* `font-display: block`, which paints nothing until the face lands. That is the
|
|
* "unstyled flash", and the 1.1 s of it is bought entirely by WHEN the request
|
|
* starts.
|
|
*
|
|
* A font is discovered by parsing CSS, so the request cannot begin until 233 KB
|
|
* of render-blocking stylesheet has been fetched and read — a third round trip,
|
|
* serialised behind the second. A preload link is discovered by the PRELOAD
|
|
* SCANNER, which reads the raw bytes of <head> before any stylesheet is parsed,
|
|
* so the same two files leave the wire in parallel with the CSS instead of after
|
|
* it. The block period then elapses during time the page was already blocked, and
|
|
* there is no interval where layout exists without type.
|
|
*
|
|
* `font-display: block` STAYS, and this is the fix precisely because it does.
|
|
* That value is a stated brand decision in the design package — "a held word is a
|
|
* moment; the wrong typeface is the brand" — and flipping this one app to `swap`
|
|
* would answer an estate-wide policy with a local override, which is how the
|
|
* surfaces come to render in different faces. The complaint is that the hold is
|
|
* LONG, and the hold is long because the request is late. So this moves the
|
|
* request rather than shortening the hold.
|
|
*
|
|
* WHY A POSTBUILD PASS AND NOT A <link> IN THE LAYOUT. The URL carries a content
|
|
* hash the bundler assigns while it emits, so it does not exist at the time a layout
|
|
* is authored, and a hand-written path would preload a file the stylesheet does
|
|
* not reference — two downloads of one font, the second of them useless. Reading
|
|
* it back off the export is the only spelling that cannot disagree with the CSS,
|
|
* and it re-derives itself whenever the face changes. It runs beside noindex.mjs
|
|
* and canonical.mjs, over the same `shipped()` listing, and follows the same
|
|
* three rules those state: derive the answer rather than list it, refuse to write
|
|
* a second copy over a page that already carries one, and count what was stamped
|
|
* so a partial pass cannot pass quietly.
|
|
*
|
|
* ONE FACE, the sans. There are nine woff2 files in the export — sans, mono and
|
|
* the five pixel faces, each with an italic where one exists — 455 KB together,
|
|
* and only Zen Variable sets the first screen. Preloading all nine put 385 KB of
|
|
* fonts no first paint uses ahead of the scripts on a Fast 3G link, and the one
|
|
* that was needed arrived behind them: the headline held for 3.4 s of a 5.6 s
|
|
* LCP. A face nothing on screen uses is not requested at all, so the others cost
|
|
* nothing until a page sets type in them; the `block` period they then hold is
|
|
* the same as it was before this pass existed, for the same reason it always was.
|
|
*
|
|
* `crossorigin` is REQUIRED and is not decoration: fonts are fetched in CORS mode
|
|
* even from the same origin, and a preload whose mode does not match the eventual
|
|
* request is discarded and fetched a second time — which would make this slower
|
|
* than doing nothing at all.
|
|
*/
|
|
import { readdirSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
import { shipped } from '../lib/routes.ts'
|
|
|
|
const OUT = join(import.meta.dirname, '..', 'out')
|
|
const MEDIA = join(OUT, '_next', 'static', 'media')
|
|
const HEAD = '</head>'
|
|
const EXISTING = /<link[^>]+rel=["']preload["'][^>]+as=["']font["']/i
|
|
|
|
// A pass of scripts/export.mjs, which reads each page once and writes it once.
|
|
export default function preloadFont({ read, write }) {
|
|
/** The sans, hash and all: the one face the first screen is set in. */
|
|
const faces = readdirSync(MEDIA)
|
|
.filter((f) => /^Zen-Variable\.[\w-]+\.woff2$/.test(f))
|
|
.sort()
|
|
.map((f) => `/_next/static/media/${f}`)
|
|
|
|
if (faces.length === 0) {
|
|
throw new Error(`no Zen-Variable woff2 in ${MEDIA}: the type is self-hosted, so an export without it is a broken build`)
|
|
}
|
|
|
|
const links = faces
|
|
.map((href) => `<link rel="preload" as="font" type="font/woff2" href="${href}" crossorigin/>`)
|
|
.join('')
|
|
|
|
const pages = shipped(OUT)
|
|
if (pages.length === 0) {
|
|
throw new Error(`no export at ${OUT}: \`next build\` writes it, and this is the rest of that build`)
|
|
}
|
|
|
|
let stamped = 0
|
|
let already = 0
|
|
for (const { route, file } of pages) {
|
|
const html = read(file)
|
|
if (EXISTING.test(html)) {
|
|
already++
|
|
continue
|
|
}
|
|
if (!html.includes(HEAD)) throw new Error(`${route} has no <head> to carry a font preload`)
|
|
write(file, html.replace(HEAD, `${links}${HEAD}`))
|
|
stamped++
|
|
}
|
|
|
|
if (stamped === 0 && already === 0) {
|
|
throw new Error(`no page took a font preload across ${pages.length} pages — the pass did nothing`)
|
|
}
|
|
|
|
console.log(
|
|
`font preload: ${faces.length} face(s) stamped into ${stamped} pages` +
|
|
(already ? `, ${already} already carried one` : ''),
|
|
)
|
|
}
|