PERF: cache self-hosted fonts with hashed URLs or conditional 304 (#663) #804

Open
opened 2026-10-02 13:12:31 +00:00 by kayg · 2 comments
Owner

Parent: #663. Non-blocking performance finding; no font design change requested.

Context: DESIGN §44 already uses self-hosted WOFF2 subsets and font-display: swap. Source audited at origin/dev c4a61e8cf0; round 7a retains this serving path.

Evidence: packages/ui/src/tokens.css:44–243 points to stable /fonts/*.woff2 names. crates/calternal-server/src/main.rs:1151–1160 returns no-cache for these paths because is_hashed_asset only accepts assets/ or _app/immutable/. asset_response at :1131–1148 emits neither ETag nor Last-Modified and does not process conditional requests. A repeat document load must revalidate, and the current server cannot return a 304 for these fonts. The service worker is push-only, with no fetch cache.

Measured files from the production build: default Latin Google Sans 70,752 B plus Bricolage Grotesque 76,888 B = 147,640 B. Default Latin Maple Mono adds 67,420 B only when code text uses it. All WOFF2 choices total 1,685,316 B; this is packaged size, not the amount fetched by each route. Subsetting and demand loading work; do not preload every choice.

Concrete fix: use content-hashed font URLs and immutable public caching, or strong validators on stable URLs with conditional 304. Keep source font identity, license files and the selected-font-only behavior. Preload only a selected, used UI/display Latin face if a trace shows discovery is on the critical path; do not hard-code default preloads when the boot script selects another font.

Test: load a real page twice on the production server, then use If-None-Match on a font. Assert unchanged font gets a cache hit or 304, font replacement invalidates it, and the selected choice downloads without unused font requests. Cover English, Latin Extended text, System fonts, code-free and code routes. No font-related UI warning. Search before filing: all issues for WOFF2 and font cache; #234 and #322 own typography choices, not this HTTP policy.

Parent: #663. Non-blocking performance finding; no font design change requested. Context: DESIGN §44 already uses self-hosted WOFF2 subsets and font-display: swap. Source audited at origin/dev c4a61e8cf090170f35b1bed3350d9de20c83ecd5; round 7a retains this serving path. Evidence: packages/ui/src/tokens.css:44–243 points to stable /fonts/*.woff2 names. crates/calternal-server/src/main.rs:1151–1160 returns no-cache for these paths because is_hashed_asset only accepts assets/ or _app/immutable/. asset_response at :1131–1148 emits neither ETag nor Last-Modified and does not process conditional requests. A repeat document load must revalidate, and the current server cannot return a 304 for these fonts. The service worker is push-only, with no fetch cache. Measured files from the production build: default Latin Google Sans 70,752 B plus Bricolage Grotesque 76,888 B = 147,640 B. Default Latin Maple Mono adds 67,420 B only when code text uses it. All WOFF2 choices total 1,685,316 B; this is packaged size, not the amount fetched by each route. Subsetting and demand loading work; do not preload every choice. Concrete fix: use content-hashed font URLs and immutable public caching, or strong validators on stable URLs with conditional 304. Keep source font identity, license files and the selected-font-only behavior. Preload only a selected, used UI/display Latin face if a trace shows discovery is on the critical path; do not hard-code default preloads when the boot script selects another font. Test: load a real page twice on the production server, then use If-None-Match on a font. Assert unchanged font gets a cache hit or 304, font replacement invalidates it, and the selected choice downloads without unused font requests. Cover English, Latin Extended text, System fonts, code-free and code routes. No font-related UI warning. Search before filing: all issues for WOFF2 and font cache; #234 and #322 own typography choices, not this HTTP policy.
Author
Owner

Starting work on job/webperf, based on 2f4482ded066d9c5d9c59130377907f7fd2916c9 (job/merge-round-7a). I am reading the matching audit evidence and will report the concrete finding, regression coverage, measurements, and gate output here when finished.

Starting work on `job/webperf`, based on `2f4482ded066d9c5d9c59130377907f7fd2916c9` (`job/merge-round-7a`). I am reading the matching audit evidence and will report the concrete finding, regression coverage, measurements, and gate output here when finished.
Author
Owner

Finding: static assets were served without negotiated compression or representation validators. The production build now writes Brotli/gzip sidecars; the server negotiates encodings and sends Vary, representation ETags, HEAD/304 behavior and font revalidation headers. Static-sidecar tests passed as part of the web suite; the server test is still compiling.

Finding: static assets were served without negotiated compression or representation validators. The production build now writes Brotli/gzip sidecars; the server negotiates encodings and sends Vary, representation ETags, HEAD/304 behavior and font revalidation headers. Static-sidecar tests passed as part of the web suite; the server test is still compiling.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#804
No description provided.