# @pyyupsk/vite-fonts

> A Vite plugin that downloads and self-hosts web fonts at build time, with zero layout shift and no runtime CDN calls.

A Vite plugin that downloads web fonts at build time and serves them from your own output, instead of calling Google Fonts or another CDN at runtime.

## Features

- Self-hosts fonts from Google Fonts, Bunny Fonts, Fontsource, or [fonts.fasu.dev](https://fonts.fasu.dev).
- Generates `@font-face` CSS with `size-adjust` fallback metrics, which removes layout shift.
- Injects `<link rel="preload">` tags automatically.
- Creates one CSS variable per font family and syncs it with a Tailwind v4 `@theme` block.
- Gives you a type-safe `@pyyupsk/fonts/meta` module, so family keys autocomplete in your editor.
- Caches downloaded font files, so a second build does not redownload them.

## Usage

```typescript
// vite.config.ts
import { fonts } from '@pyyupsk/vite-fonts'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [fonts('Inter')],
})
```

An Astro integration works the same way, through `@pyyupsk/vite-fonts/astro`. It also preloads fonts on nested static pages.

## SSR Frameworks

TanStack Start, React Router and SvelteKit render HTML at request time, so the plugin cannot add preload tags. Since 0.4.0, `@pyyupsk/fonts/meta` exports `preloads`. You render them in the document head:

```tsx
import * as fonts from '@pyyupsk/fonts/meta'

const links = fonts.preloads.map((p) => ({ rel: 'preload', as: 'font', crossOrigin: 'anonymous', ...p }))
```

Since 0.4.1, the preload list covers every subset, for example both Latin and Thai, and keeps the weight range of variable fonts.

## CLI

- `bunx vite-fonts list`: Shows configured fonts and cache info.
- `bunx vite-fonts clean`: Clears the font cache.
