Emit self-hosted fonts by importing from JS, not CSS @import

Firefox's console was spammed with "downloadable font: download failed
status=2147746065" for every @fontsource family — Inter, Alfa Slab One,
JetBrains Mono. Root cause: the built CSS referenced
./files/inter-latin-400-normal.woff2 but no font files were ever emitted
to build/client/_app/immutable/assets/.

Vite's CSS `@import` inlines the imported file's *text* but doesn't
crawl the resulting url() references to emit their assets. Since
tokens.css was doing `@import '@fontsource/inter/400.css'` and being
pulled into +layout.svelte via a Svelte <style> @import, the fonts
lived entirely in CSS space where Vite's asset emission never saw them.

Moved the @fontsource imports into src/lib/ui/styles/fonts.ts and
side-effect-import that module from +layout.svelte's <script>. JS
imports go through the module graph, so Vite walks the CSS, sees the
url() references, and emits the woff/woff2 binaries.

Verified: build now emits 80 font files (14 subsets × 5-6 weights)
into build/client/_app/immutable/assets/ and the CSS url()s resolve
to the correct hashed filenames in the same directory.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-09-12 12:08:17 -04:00
co-authored by Claude Opus 4.7
parent dd4314df72
commit c3c799a409
3 changed files with 24 additions and 8 deletions
+5 -8
View File
@@ -1,14 +1,11 @@
/* Electric Cherry — design tokens.
Named after the perk-a-cola from Mob of the Dead (CoD Zombies):
deep cherry-red art-deco label + electric cyan discharge. */
deep cherry-red art-deco label + electric cyan discharge.
@import '@fontsource/alfa-slab-one/400.css';
@import '@fontsource/inter/400.css';
@import '@fontsource/inter/500.css';
@import '@fontsource/inter/600.css';
@import '@fontsource/inter/700.css';
@import '@fontsource/jetbrains-mono/400.css';
@import '@fontsource/jetbrains-mono/500.css';
Font @import chains live in src/lib/ui/styles/fonts.ts and are pulled
in by +layout.svelte via JS import — Vite's CSS `@import` inlines the
text but doesn't emit the url()-referenced woff files as assets, so
we need the JS module graph to see them. */
:root {
/* Cherry — surfaces + primary */