Skip to content

Bundler Setup

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

// 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.

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:

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.

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']

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 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:

// 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

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.