build(fonts): the two faces are served from this origin - #304
Merged
Conversation
Anton and Archivo came from fonts.googleapis.com, which was the only third party the app talked to. It is a privacy leak before it is a performance one: a stylesheet fetched from another host tells that host who is baking, and it put a server we do not run in front of the first paint of an app that is otherwise entirely local. Both faces now ship with the site. The Fontsource packages are dependencies, so the version stays a literal Renovate can see, and app.css declares the @font-face rules itself rather than importing theirs — the package names the variable family "Archivo Variable" and the design calls it Archivo. Latin and Latin Extended only; the five locales need no more. Vite hashes the .woff2 files and emits relative urls, so BASE_PATH needs no help. Written down as a contract: the app fetches nothing from a host it is not served from, and the one outbound request left is the TRMNL webhook, on an explicit click, to a URL the user typed. e2e/self-hosted.spec.ts enforces it by watching the actual network across all three views and the print sheet — grepping the source cannot settle this, since a CDN can come back through app.html, an @import, a component's <img> or a dependency's own stylesheet. It also asserts both faces really load, so falling back to the system stack everywhere cannot pass as compliance. Font notices in THIRD-PARTY-NOTICES.md: the build now redistributes the files.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Anton and Archivo came from
fonts.googleapis.com— the only third party the app talked to. That is a privacy leak before it is a performance one: a stylesheet fetched from another host tells that host who is baking, and it put a server we do not run in front of the first paint of an app that is otherwise entirely local.What changed
src/app.html— thepreconnect/preload-promotes-to-stylesheet /<noscript>block is gone. The shell links no third party at all now.src/app.css— four@font-facerules of our own: Anton and Archivo, Latin and Latin Extended,font-display: swap, the variable face declared across both axes (wght 100 900,font-stretch 62% 125%) solabel-caps' 84 % width still resolves. They are ours rather than the packages' own CSS because Fontsource names the variable familyArchivo Variableand the design calls it Archivo — this way--font-sansand the family assertions inheadings.spec.tsare untouched. The Vietnamese subset the packages also carry is left out; the five locales do not need it.package.json—@fontsource/antonand@fontsource-variable/archivoas dependencies, so the version stays one literal Renovate can see. Vite hashes the.woff2files into_app/immutable/assets/with relativeurl(), soBASE_PATHneeds no help. Checked in bothvite devand the static build.THIRD-PARTY-NOTICES.md— OFL-1.1 attribution for both faces, since the build now redistributes the font files.The contract
The app fetches nothing from a host it is not served from: no backend, no analytics, no CDN, no font server. The one outbound request left in the whole app is the TRMNL webhook, on an explicit click, to a URL the user typed themselves.
e2e/self-hosted.spec.tsenforces it by watching the actual network across all three views and the print sheet. It lives in the browser suite because grepping the source cannot settle this — a CDN can come back throughapp.html, an@importinapp.css, a component's<img>, or a dependency that pulls its own stylesheet; only what the browser fetches tells. A third test asserts both faces really load, so a page that quietly fell back to the system stack everywhere cannot pass as compliance. Verified it bites: putting a Google Fonts<link>back fails it with the three URLs listed.Recorded in
CLAUDE.mdunder Stack & deploy, in the Type section, and in the e2e "what belongs here" list;README.mdgained a matching paragraph.Checks
test-baseline.jsonraised to matchnpm run lintclean; version bumped to 7.0.3 (patch — no user-visible behaviour, no URL schema change)🤖 Generated with Claude Code