Files
clawgod/web/package.json
0chencc 0c40eb5651 fix(web): inline self-hosted fonts to eliminate first-paint flash
Ctrl+F5 / cold loads previously showed a sequence of small flashes:
unstyled text first, SVG icons popping from 300×150 to their icon
size, then the hero h1 layout-shifting when Google Fonts Inter
swapped in. Each one came from a different async resource in the
loading chain — patching them one at a time was a losing game,
because every fix exposed the next link.

Root cause: web fonts are always a separately-fetched resource. No
CSS-only trick (size-adjust override, ascent/descent override) makes
the re-render imperceptible at hero-h1 sizes — at 80 px, even a few-
pixel metric delta is visible.

Replace Google Fonts with @fontsource-variable npm packages and let
Vite's assetsInlineLimit (100 MB) base64-inline the woff2 into the
stylesheet. Hand-written @font-face declarations restricted to the
latin weight-axis subset; the default index.css would have inlined
13 woff2s across cyrillic / greek / vietnamese — ~300 KB of dead
weight on a page that only renders ASCII.

Two related moves stacked in here because they're part of the same
"no async resource between HTML and first paint" rule:
- CSS now loaded via <link rel=stylesheet> in the HTML head, not
  imported through main.ts. Importing through the deferred ES
  module chained CSS behind the JS fetch and produced the same
  unstyled-text flash for the same reason.
- Inline <svg>s gained explicit width / height attributes — without
  them the browser rendered SVGs at the default 300×150 viewport
  before CSS arrived, then snapped them to icon size.

The earlier metric-matched fallback @font-face declarations are
gone — they were a workaround for the async swap, no longer needed
once the font is synchronous with the CSS.

HTML grows from 31 KB / 9 KB gzipped to 150 KB / 99 KB gzipped.
One-time cost; cached after first visit; no third-party DNS or
font-CDN dependency.

Net result: first paint is the finished page on Ctrl+F5.
2026-04-28 22:08:30 +09:00

21 lines
423 B
JSON

{
"name": "clawgod-web",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"typescript": "^5.6.3",
"vite": "^7.0.0",
"vite-plugin-singlefile": "^2.0.3"
},
"dependencies": {
"@fontsource-variable/inter": "^5.2.8",
"@fontsource-variable/jetbrains-mono": "^5.2.8"
}
}