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:
@@ -0,0 +1,16 @@
|
||||
// Font imports for the Electric Cherry design system.
|
||||
//
|
||||
// These live in a JS module (not a CSS `@import` chain) because Vite's
|
||||
// CSS processor inlines @import'd CSS as text but doesn't crawl its
|
||||
// url() references to emit the referenced woff/woff2 files as build
|
||||
// assets. Importing the CSS from JS puts it on the module graph, which
|
||||
// Vite *does* walk, so the font binaries end up in
|
||||
// build/client/_app/immutable/assets/files/.
|
||||
|
||||
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';
|
||||
@@ -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 */
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
import { startServerStream } from '$ui/stores/servers.js';
|
||||
import { page } from '$app/stores';
|
||||
import BrandMark from '$ui/components/BrandMark.svelte';
|
||||
// Side-effect import — puts @fontsource CSS on Vite's module graph so
|
||||
// the referenced woff/woff2 files get emitted into the build.
|
||||
import '$ui/styles/fonts.js';
|
||||
|
||||
interface Props { children: import('svelte').Snippet }
|
||||
let { children }: Props = $props();
|
||||
|
||||
Reference in New Issue
Block a user