Skip to content

Ship the fonts as assets instead of base64 - #93

Draft
librowski wants to merge 1 commit into
ds2-nav-buttonfrom
ds2-font-assets
Draft

Ship the fonts as assets instead of base64#93
librowski wants to merge 1 commit into
ds2-nav-buttonfrom
ds2-font-assets

Conversation

@librowski

Copy link
Copy Markdown
Collaborator

Fonts stop being base64-inlined. Vite's library mode inlines every asset unconditionally (assetsInlineLimit has no effect there), so the built stylesheets carried 382 KB of font payload.

What changed — the @font-face rules are generated after Vite finishes, from the fontsource metadata, and the files are copied into dist/assets:

  • Poppins 400 and 600 latin stay inlined — the only weights typography.css declares — so ordinary text needs no extra request and shows no swap flash.
  • Every other face (Poppins 300/500/700, all latin-ext, Inter) is a .woff2 fetched on demand.
  • Each face now carries unicode-range, which the per-subset fontsource stylesheets omit. Without it a browser has to consider both subsets; with it, a document without extended latin never fetches those files.
  • The legacy .woff source is gone — that duplication is why twelve faces produced twenty-four payloads.

Sizesui/dist/index.css 509 KB → 150 KB, sdk/dist/style.css 591 KB → 230 KB, ui/dist/styles.css 7 KB → 32 KB (it now carries the two inlined faces). Ten .woff2 files ship in each package's dist/assets.

Why the SDK is in scope — it bundles the UI stylesheet into its own, so it carried the same payload; it now appends the generated block and copies the assets, reading them as artifacts from the UI build rather than importing its build code.

New gatecheck-built-css fails when a stylesheet references an asset missing from dist. That is the failure mode this arrangement invites, and the one an earlier font change hit only on a clean CI install. Verified by deleting a file and watching the build fail.

For consumers — imports are unchanged, and the subpath path finally works as documented: styles.css now really does bring the typefaces. Two caveats, both in the changeset: a Content-Security-Policy naming font-src needs 'self' (or the serving origin) rather than data:, and the dist layout has to survive copying, since the stylesheets reference ./assets/*.woff2. Bundlers handle that themselves.

overview.mdx gains a short section listing what each style surface provides and what it does not — which also closes the gap a reviewer flagged on the typography PR, where subpath consumers were told to add styles.css for typography that then rendered in a system font.

Verified: ui/sdk lint and typecheck, build:ui, build:lib, stylelint, all test suites, docs build, demo build, and the asset gate proven by removing a font file.

The library inlined twelve font faces as base64 because Vite's library
mode inlines every asset unconditionally, so the built stylesheet
carried 382 KB of fonts: index.css was 509 KB and the SDK stylesheet,
which bundles it, 591 KB.

The faces are generated after Vite finishes, from the fontsource
metadata, and copied into dist/assets. Poppins 400 and 600 latin stay
inlined - the only weights the typography classes declare - so the
common text needs no extra request. Everything else is fetched on
demand, and each face now carries the unicode-range the per-subset
fontsource files omit, so a document without extended latin skips
those files entirely. The legacy woff source is gone.

index.css is 150 KB, the SDK stylesheet 230 KB, and dist gains ten
woff2 files. A new gate fails the build when a stylesheet references
an asset that is not in dist - the failure mode this arrangement
invites, and the one a previous font change hit only on clean CI.

Consumers keep their imports; a Content-Security-Policy naming
font-src needs 'self' rather than 'data:', and the dist layout has to
survive copying.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant