fix(public): load Google Fonts without render-blocking via same-origin fonts.js - #20
Conversation
…n fonts.js The Google Fonts css2 stylesheet was fetched render-blocking on every public page: a <link rel="stylesheet"> in the homepage head and an @import chain inside shared.css for the shared pages (audit, agents, pricing, specimen, brief-requested). All six pages now preload the same css2 URL as a style resource, promote it through the same-origin public/fonts.js script, and keep a <noscript> fallback; shared.css no longer @imports the stylesheet, and src/worker.js registers /fonts.js in its PUBLIC_ASSET_PATHS allow-list. An inline onload swap is deliberately not used: the production CSP (script-src 'self', no unsafe-inline) blocks inline event handlers, so the promotion must come from a same-origin served script. scripts/check- site.mjs gains static source guards asserting the blocking shape cannot return on any of the six pages and that /fonts.js is served; the worker and UI suites cover the allow-list and the promotion script contract. docs/evidence/render-blocking-fonts-2026-08-08.md records the local Chromium measurement (static copies, simulated CDN delay, production CSP header) and explicitly states it is not CI proof and not a hosted/live claim. No deployment or live before/after improvement is claimed. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
nish3451 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
📝 WalkthroughWalkthroughThe change replaces blocking Google Fonts imports with preloads and deferred same-origin stylesheet promotion across six public pages. It adds worker routing, static validation, worker tests, and measurement evidence for the new loading path. ChangesGoogle Fonts loading
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant fonts.js
participant GoogleFonts
Browser->>GoogleFonts: Preconnect and preload stylesheet
Browser->>fonts.js: Load deferred same-origin script
fonts.js->>Browser: Append stylesheet link from preload URL
Browser->>GoogleFonts: Reuse preloaded stylesheet
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
scripts/check-site.mjs (2)
437-443: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAssert that the promotion script reuses the preload URL.
The guard checks the selector, stylesheet relation, and append operation. It does not check
link.href = preload.href. A script that loads another URL, or no URL, would pass the check.Suggested guard
- if (!fontScript.includes('link.rel = "stylesheet"') || !fontScript.includes('document.head.appendChild(link)')) { + if ( + !fontScript.includes("link.href = preload.href") || + !fontScript.includes('link.rel = "stylesheet"') || + !fontScript.includes("document.head.appendChild(link)") + ) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/check-site.mjs` around lines 437 - 443, Extend the fontScript validation in the existing promotion-script checks to require assignment of the preload URL via link.href = preload.href. Keep the current selector, stylesheet relation, and document.head.appendChild(link) assertions unchanged, and add a failure message for scripts that do not reuse preload.href.
454-458: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winMake the inline-handler guard independent of attribute order.
The regular expression only matches
data-fonts-cssbeforeonload. A tag withonloadbeforedata-fonts-cssbypasses the check.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/check-site.mjs` around lines 454 - 458, Update the inline-handler validation in the page HTML check so it detects both data-fonts-css and onload attributes regardless of their order within the same link tag. Preserve the existing failure message and page validation behavior.docs/evidence/render-blocking-fonts-2026-08-08.md (1)
97-99: 🚀 Performance & Scalability | 🔵 TrivialAdd a post-deployment browser smoke check.
The receipt explicitly limits proof to local static copies and source checks. Before treating the change as verified in production, check the deployed six pages for a successful
/fonts.jsresponse, the production CSP, and non-blockingcss2loading.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/evidence/render-blocking-fonts-2026-08-08.md` around lines 97 - 99, Extend the verification documented in the Limitation section with a post-deployment browser smoke check covering all six deployed pages. Validate successful /fonts.js responses, the production CSP, and non-blocking css2 loading before claiming production verification, while retaining the existing distinction between local evidence and live deployment evidence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/evidence/render-blocking-fonts-2026-08-08.md`:
- Line 53: Update the reproduction script’s result object to include a
fontsReady field populated from document.fonts.status, so the reported
font-readiness claim is directly reproducible; otherwise remove the fontsReady
claim from the evidence document.
---
Nitpick comments:
In `@docs/evidence/render-blocking-fonts-2026-08-08.md`:
- Around line 97-99: Extend the verification documented in the Limitation
section with a post-deployment browser smoke check covering all six deployed
pages. Validate successful /fonts.js responses, the production CSP, and
non-blocking css2 loading before claiming production verification, while
retaining the existing distinction between local evidence and live deployment
evidence.
In `@scripts/check-site.mjs`:
- Around line 437-443: Extend the fontScript validation in the existing
promotion-script checks to require assignment of the preload URL via link.href =
preload.href. Keep the current selector, stylesheet relation, and
document.head.appendChild(link) assertions unchanged, and add a failure message
for scripts that do not reuse preload.href.
- Around line 454-458: Update the inline-handler validation in the page HTML
check so it detects both data-fonts-css and onload attributes regardless of
their order within the same link tag. Preserve the existing failure message and
page validation behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ab2a132c-622f-403f-a4ee-c213f147fe30
📒 Files selected for processing (12)
docs/evidence/render-blocking-fonts-2026-08-08.mdpublic/agents.htmlpublic/audit.htmlpublic/brief-requested.htmlpublic/fonts.jspublic/index.htmlpublic/pricing.htmlpublic/shared.csspublic/specimen.htmlscripts/check-site.mjsscripts/test-agent-worker.mjssrc/worker.js
💤 Files with no reviewable changes (1)
- public/shared.css
|
|
||
| ### Fonts still load, stylesheet still applies | ||
|
|
||
| Both states, all six pages: `fontsReady: "loaded"`, `karla: true`, `fraunces: true`, `sheetApplied: true` in the fixed state. First paint uses the fallback stack and swaps in via the existing `display=swap` in the URL. No CSP violations in the fixed state (the single console error on `brief-requested.html` is the pre-existing `gtag/js?id=AW-XXXXXXXXX` placeholder, present in both states). |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Make the font-readiness claim reproducible.
The receipt reports fontsReady: "loaded", but the reproduction script does not return a fontsReady field. Add fontsReady: document.fonts.status to the result or remove that claim.
Suggested fix
return { fcp, css2End, renderBlockingStatus: rbs,
+ fontsReady: document.fonts.status,
waitedForCss2: fcp !== null && css2End !== null ? fcp >= css2End : null,Also applies to: 85-89
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/evidence/render-blocking-fonts-2026-08-08.md` at line 53, Update the
reproduction script’s result object to include a fontsReady field populated from
document.fonts.status, so the reported font-readiness claim is directly
reproducible; otherwise remove the fontsReady claim from the evidence document.
…6e942a (#24) The render-blocking receipt documented a limitation: the live deployment was never measured. This closes that gap by recording a real-Chromium measurement of the six deployed tinystudio.io pages (2026-08-09): the Google Fonts css2 stylesheet is non-blocking everywhere, first paint does not wait for it, the only render-blocking resources are the site's own same-origin stylesheets, and fonts still load and apply. Dogfood finding b8f6046e942a (render-blocking resources on home) is verified resolved on the deployed site; the code fix and CI enforcement were merged as PRs #20 and #23.
…6e942a (#25) The render-blocking receipt documented a limitation: the live deployment was never measured. This closes that gap by recording a real-Chromium measurement of the six deployed tinystudio.io pages (2026-08-09): the Google Fonts css2 stylesheet is non-blocking everywhere, first paint does not wait for it, the only render-blocking resources are the site's own same-origin stylesheets, and fonts still load and apply. Dogfood finding b8f6046e942a (render-blocking resources on home) is verified resolved on the deployed site; the code fix and CI enforcement were merged as PRs #20 and #23.
…t current main and live (#35) The code-side fix (PR #20) and CI enforcement (PR #23) for dogfood finding b8f6046e942a ("Render-blocking resources on home") are already merged in origin/main. This lane re-verified the guarantee still holds after the subsequent page edits (heading hierarchy, apple-touch icon, schema.org, meta descriptions, canonical URLs, internal-link cleanup, App Store citation): - npm run check:render-blocking passes on all six pages (real Chromium, production CSP, css2 delayed 2500ms): css2 non-blocking, first paint never waits for it, no render-blocking resources other than the site's own same-origin stylesheets. - Fresh live measurement of the deployed pages confirms the same: css2 non-blocking on all six pages, only same-origin stylesheets render-block, fonts still load and apply under the production CSP. Nothing further to change; the receipt now records the closeout on the current head so the finding cannot be re-opened by tracker drift.
…t current main and live (#69) The code-side fix (PR #20) and CI enforcement (PR #23) for dogfood finding b8f6046e942a ("Render-blocking resources on home") are merged in origin/main; this lane re-verified the guarantee on the current head (536b3c9, 2026-08-10) after the commits that landed since the 2026-08-09 closeout (sitemap, preferred source pages, Agent Desk de-index, tap targets, CI runners): - npm run check:render-blocking passes on all six pages (real Chromium, production CSP, css2 delayed 2500ms): css2 non-blocking, first paint never waits for it, no render-blocking resources other than the site's own same-origin stylesheets, promoted sheet applied. - Fresh live measurement of the deployed pages confirms the same: css2 non-blocking on all six pages, only same-origin stylesheets render-block, fonts still load and apply under the production CSP. - Full npm test (82 tests) passes on this head. The receipt now records the re-verification on the current head so the tracker item can close.
What
The Google Fonts css2 stylesheet was fetched render-blocking on every public page — a
<link rel="stylesheet">in the homepage head and an@importchain insideshared.cssfor the shared pages (audit, agents, pricing, specimen, brief-requested). This change makes all six pages load the same css2 URL non-blocking through a same-origin, CSP-safe promotion path:rel="preload" as="style" data-fonts-css), loads the same-originpublic/fonts.jspromotion script (defer), and keeps a<noscript>stylesheet fallback so fonts still work without JavaScript.shared.cssno longer@imports the Google Fonts stylesheet.src/worker.jsregisters/fonts.jsin itsPUBLIC_ASSET_PATHSallow-list (the worker 404s any unlisted asset-like path).onloadswap is deliberately not used: the production CSP (script-src 'self', nounsafe-inline) blocks inline event handlers, so a same-origin served script is the promotion vehicle that works under the live CSP.Guards and evidence
scripts/check-site.mjsgains static source guards: the blocking shape (font stylesheet link outside<noscript>,@importchain, missing preload/script/fallback, missing/fonts.jsallow-list entry) failsnpm run checkon any of the six pages. These are source-string guards, not network-timing tests — CI has no browser.scripts/test-agent-worker.mjscovers that the worker serves/fonts.jsand 404s unlisted asset-like paths.docs/evidence/render-blocking-fonts-2026-08-08.mdrecords the local Chromium measurement (render-blocking status and first-paint vs css2 response under a simulated 1500ms CDN delay and the exact production CSP header, fonts still verified to load). The receipt states its own limits.intended-outcome: six public pages (index, audit, agents, pricing, specimen, brief-requested) load the Google Fonts stylesheet without render-blocking, through a same-origin CSP-safe
public/fonts.jspromotion path, with a no-JS fallback retained.verify:
npm run checkandnpm testpass locally via test-gate;git diff --checkclean;sgscanshows only baseline warnings; the browser receipt is local/static CSP-proxy evidence only — live deployment and live adoption remain unverified, and this PR does not claim the product is deployed or that live AI/search/performance improved.Summary by CodeRabbit
Performance
Bug Fixes
Tests