From b32294825b53b4ed26c4859a6df2e1301f04f0f0 Mon Sep 17 00:00:00 2001 From: Lars Francke Date: Thu, 16 Jul 2026 09:21:12 +0200 Subject: [PATCH] perf: Load fonts with font-display swap, preloads and caching Mobile Lighthouse attributes ~400 ms of first-paint delay to the fonts blocking text rendering: - font-display: swap on all six faces, so text renders in the fallback font until the webfonts arrive. - Preload the two above-the-fold fonts (body Noto Sans 400 and heading IBM Plex Mono 600), so they usually arrive before first paint anyway. - Cache the UI bundle assets for a day via netlify.toml headers (the Lighthouse cache-lifetimes finding; a day keeps a stale-css window after deploys short since the file names are not content-hashed). --- netlify.toml | 8 ++++++++ ui/src/css/fonts.css | 11 ++++++++--- ui/src/partials/head-styles.hbs | 2 ++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/netlify.toml b/netlify.toml index 05d325692..8f5cbcc1b 100644 --- a/netlify.toml +++ b/netlify.toml @@ -11,3 +11,11 @@ from = "/home/stable/release_notes.html" to = "/home/stable/release-notes" status = 301 + +# The bundle file names are not content-hashed, so a stale asset can be +# served until max-age expires. One hour keeps that window small; with +# content-hashed file names this could be immutable. +[[headers]] + for = "/_/*" + [headers.values] + Cache-Control = "public, max-age=3600" diff --git a/ui/src/css/fonts.css b/ui/src/css/fonts.css index 16935b433..8fad46cc3 100644 --- a/ui/src/css/fonts.css +++ b/ui/src/css/fonts.css @@ -1,13 +1,13 @@ /* How do fonts work in this build setup? * Fonts are installed from fontsource packages. - * In the file ./gulp.d/tasks/build.js there is an action that copies the font files - * from the installed packages into the output directory, based on matching file names. - * search for 'fontsource' in the file, and you will find a post CSS action. + * The build (ui/build.mjs) resolves the ~@fontsource urls below and emits the + * font files into the bundle's font/ directory. */ /* Noto Sans - the base font for the body */ @font-face { + font-display: swap; font-family: "Noto Sans"; font-style: normal; font-weight: 400; @@ -17,6 +17,7 @@ } @font-face { + font-display: swap; font-family: "Noto Sans"; font-style: normal; font-weight: 700; @@ -28,6 +29,7 @@ /* IMB Plex Mono - the header font */ @font-face { + font-display: swap; font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400; @@ -37,6 +39,7 @@ } @font-face { + font-display: swap; font-family: "IBM Plex Mono"; font-style: normal; font-weight: 600; @@ -48,6 +51,7 @@ /* Noto Sans Mono - The monospace font for code blocks */ @font-face { + font-display: swap; font-family: "Noto Sans Mono"; font-style: normal; font-weight: 400; @@ -57,6 +61,7 @@ } @font-face { + font-display: swap; font-family: "Noto Sans Mono"; font-style: normal; font-weight: 500; diff --git a/ui/src/partials/head-styles.hbs b/ui/src/partials/head-styles.hbs index beca1d450..321a12378 100644 --- a/ui/src/partials/head-styles.hbs +++ b/ui/src/partials/head-styles.hbs @@ -1,2 +1,4 @@ + +