# vite-fonts

Zero-config font optimization for Vite - auto-detect fonts from CSS, download, and self-host with fallback metrics.

Similar to `@nuxt/fonts` but for any Vite project (Vue, React, Svelte, etc.).

## Features

- **Zero Configuration** - Automatically detects `font-family` declarations in your CSS
- **Multiple Providers** - Bunny Fonts, Fontsource, local fonts (Google Fonts opt-in)
- **Self-Hosting** - Downloads and bundles fonts at build time for privacy and performance
- **Fallback Metrics** - Generates adjusted fallback fonts to reduce CLS (Cumulative Layout Shift)
- **Caching** - Persistent file cache for fast rebuilds and offline development
- **Dev Server Support** - Fonts work seamlessly in development mode
- **Blazing Fast** - Built with Rust-based tools (LightningCSS, oxlint, tsgo)

## Installation

```bash
npm install vite-fonts
# or
pnpm add vite-fonts
# or
bun add vite-fonts
```

## Usage

### Basic (Zero Config)

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

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

Then use fonts in your CSS as normal:

```css
body {
  font-family: 'Inter', sans-serif;
}

code {
  font-family: 'Fira Code', monospace;
}
```

The plugin will automatically:
1. Detect the `font-family` declarations
2. Resolve fonts from configured providers (Bunny, Fontsource, local)
3. Download the font files
4. Generate and inject `@font-face` rules
5. Create fallback font metrics to reduce layout shift

### With Configuration

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

export default defineConfig({
  plugins: [
    fonts({
      // Default options for all fonts
      defaults: {
        weights: [400, 700],
        styles: ['normal', 'italic'],
        subsets: ['latin', 'latin-ext'],
        display: 'swap',
      },

      // Explicitly configure specific fonts
      families: {
        'Inter': {
          weights: [400, 500, 600, 700],
          styles: ['normal'],
        },
        'Fira Code': {
          weights: [400, 700],
          provider: 'fontsource',
        },
      },

      // Provider configuration
      providers: {
        bunny: true,      // Bunny Fonts (privacy-focused)
        fontsource: true, // Fontsource (npm packages)
        google: false,    // Google Fonts (opt-in)
        local: true,      // Local fonts in public/
      },

      // Generate fallback font metrics (reduces CLS)
      fallbacks: true,

      // Caching
      cache: true,
      cacheDir: 'node_modules/.cache/vite-fonts',

      // Output
      assetsDir: 'fonts',
      inject: 'inline', // 'inline' | 'external'

      // Debug logging
      debug: false,
    }),
  ],
})
```

## Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `defaults` | `object` | See below | Default font options |
| `defaults.weights` | `number[]` | `[400, 700]` | Font weights to download |
| `defaults.styles` | `string[]` | `['normal']` | Font styles to download |
| `defaults.subsets` | `string[]` | `['latin']` | Unicode subsets |
| `defaults.display` | `string` | `'swap'` | Font display strategy |
| `families` | `object` | `{}` | Per-font configuration |
| `providers` | `object` | See below | Provider configuration |
| `providers.bunny` | `boolean` | `true` | Enable Bunny Fonts |
| `providers.fontsource` | `boolean` | `true` | Enable Fontsource |
| `providers.google` | `boolean` | `false` | Enable Google Fonts |
| `providers.local` | `boolean\|object` | `true` | Enable local fonts |
| `fallbacks` | `boolean` | `true` | Generate fallback metrics |
| `cache` | `boolean` | `true` | Enable font caching |
| `cacheDir` | `string` | `node_modules/.cache/vite-fonts` | Cache directory |
| `assetsDir` | `string` | `'fonts'` | Output directory for fonts |
| `inject` | `string` | `'inline'` | CSS injection method |
| `debug` | `boolean` | `false` | Enable debug logging |

## How It Works

1. **CSS Parsing** - Uses [LightningCSS](https://lightningcss.dev/) (100x faster than PostCSS) to parse your CSS and extract `font-family` declarations.

2. **Font Resolution** - Uses [unifont](https://github.com/unjs/unifont) (same library as `@nuxt/fonts`) to resolve fonts from multiple providers.

3. **Downloading** - Font files are downloaded and cached using [unstorage](https://unstorage.unjs.io/) for fast rebuilds.

4. **Fallback Generation** - Uses [fontaine](https://github.com/unjs/fontaine) to generate adjusted fallback `@font-face` rules that reduce Cumulative Layout Shift (CLS).

5. **Injection** - `@font-face` rules are injected into your HTML, either as an inline `<style>` tag or as an external CSS file.

## Supported Providers

- **[Bunny Fonts](https://fonts.bunny.net/)** - Privacy-focused Google Fonts alternative
- **[Fontsource](https://fontsource.org/)** - Self-hostable open source fonts via npm
- **[Google Fonts](https://fonts.google.com/)** - Opt-in, disabled by default
- **Local** - Font files in your `public/` directory

## Development

This project uses bleeding-edge tooling for maximum performance:

```bash
# Install dependencies
bun install

# Run development
bun run dev

# Run tests
bun run test

# Lint
bun run lint

# Type check (uses tsgo - 10x faster than tsc)
bun run typecheck

# Format
bun run format

# Full CI pipeline
bun run ci
```

### Tooling

| Tool | Purpose |
|------|---------|
| [Bun](https://bun.sh/) | Package manager & runtime |
| [tsdown](https://tsdown.dev/) | Rolldown-powered bundler |
| [tsgo](https://github.com/nicolo-ribaudo/tsgo) | Go-based TypeScript type checker (10x faster) |
| [oxlint](https://oxc.rs/docs/guide/usage/linter.html) | Rust-based linter (100x faster than ESLint) |
| [oxfmt](https://oxc.rs/docs/guide/usage/formatter.html) | Rust-based formatter (30x faster than Prettier) |
| [LightningCSS](https://lightningcss.dev/) | Rust-based CSS parser |
| [Vitest](https://vitest.dev/) | Vite-native test runner |

## Credits

This plugin is built with:
- [unifont](https://github.com/unjs/unifont) - Font provider abstraction
- [fontaine](https://github.com/unjs/fontaine) - Font fallback metrics
- [lightningcss](https://lightningcss.dev/) - CSS parsing
- [unstorage](https://unstorage.unjs.io/) - Caching

Inspired by [@nuxt/fonts](https://fonts.nuxt.com/).

## License

MIT
