# Bundler Setup

> Bundler-specific configuration for getting Tegaki running, especially Vite.

Source: https://tegaki.ink/guides/bundlers/

Tegaki's font bundles use the ESM import-attributes syntax to load their assets:

```ts
// inside tegaki/fonts/<family>/bundle.ts (and any bundle the generator produces)
import fontUrl from './<family>.ttf' with { type: 'url' };
import glyphData from './glyphData.json' with { type: 'json' };
```

Most bundlers handle this transparently. The note below covers Vite, where two `optimizeDeps` settings are needed for development to behave like production.

## Vite

In **dev mode on Vite 7 and earlier**, the esbuild pre-bundler copies Tegaki's font bundle modules into `/node_modules/.vite/deps/` but leaves the `.ttf` files behind, so the bundle's relative font URL now points to a file that isn't there. The dev server answers that request with your `index.html`, and the browser rejects it as a font. Excluding `tegaki` from pre-bundling sends the imports through Vite's normal asset pipeline, where the URLs resolve correctly. Vite 8's Rolldown-based pre-bundler rewrites these URLs itself, so it doesn't need this setting (though adding it does no harm).

Add to `vite.config.ts`:

```ts
import { defineConfig } from 'vite';

export default defineConfig({
  // ...
  optimizeDeps: {
    exclude: ['tegaki'],
  },
});
```

After changing this, fully restart the dev server (and consider deleting `node_modules/.vite/deps/` once) so Vite re-runs its pre-bundling pass against the new config.

Production builds (Rollup) need no setting; this only affects `vite dev` and `vite preview`.

### Symptoms this fixes

| Symptom in the browser | What's happening | Fix |
| --- | --- | --- |
| Text is invisible but can be selected, or only appears with `showOverlay`. Console shows `Failed to decode downloaded font: …/node_modules/.vite/deps/<family>.ttf` / `OTS parsing error: invalid sfntVersion`, a `NetworkError: A network error occurred` or a `[tegaki] Failed to load font` warning. | The `.ttf` URL broke during pre-bundling, so the dev server returns HTML instead of the font. Older `tegaki` versions stop drawing at this point; newer ones keep drawing with the fallback font's spacing. | `optimizeDeps.exclude: ['tegaki']` |

## Astro

Vite turns a bundle's font URLs into public asset URLs only in client code. On the server it leaves `new URL('./font.ttf', import.meta.url)` as it stands, and that evaluates to a `file://` path on the build machine. The [`tegaki/astro`](https://tegaki.ink/frameworks/astro/) component renders on the server and passes that bundle to the browser, which refuses to load a local file: the handwriting still draws, but in a fallback font's widths. The Tegaki integration makes Vite emit the fonts and resolve their URLs on the server as well:

```js
// astro.config.mjs
import { defineConfig } from 'astro/config';
import tegaki from 'tegaki/astro/integration';

export default defineConfig({
  integrations: [tegaki()],
});
```

| Symptom | What's happening | Fix |
| --- | --- | --- |
| The build logs `[tegaki] The font of "…" resolved to a local file`, and the browser console shows `Not allowed to load local resource: file:///…/.prerender/chunks/<family>.ttf`. The text draws with the wrong letter spacing. | The server evaluated the bundle's font URL as a path on disk. | Add `tegaki()` to `integrations` |

## Other bundlers

Webpack, Rollup, Parcel, and esbuild's standalone build mode all handle `with { type: 'url' }` natively in the configurations Tegaki has been tested with. If one breaks, open an issue and its notes can go here.
