Vite (unplugin)
Use SayKit with Vite, Rollup, Rolldown, Webpack, Rspack, esbuild, Farm, or Bun
unplugin-saykit is the universal SayKit build-tool plugin. Powered by unplugin, it ships ready-made entry points for almost every JS bundler.
This page focuses on Vite, but the configuration is the same shape for any bundler, only the import path changes.
Install
pnpm add -D unplugin-saykitAnd the supporting packages SayKit needs:
pnpm add -D @saykit/config @saykit/format-po @saykit/transform-js @saykit/transform-jsxUse
import saykit from 'unplugin-saykit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [saykit()],
});import saykit from 'unplugin-saykit/rollup';
export default {
plugins: [saykit()],
};import { defineConfig } from 'tsdown';
import saykit from 'unplugin-saykit/rolldown';
export default defineConfig({
entry: ['src/entry.ts'],
plugins: [saykit()],
});const saykit = require('unplugin-saykit/webpack').default;
module.exports = {
plugins: [saykit()],
};
const saykit = require('unplugin-saykit/rspack').default;
module.exports = {
plugins: [saykit()],
};import saykit from 'unplugin-saykit/esbuild';
import { build } from 'esbuild';
await build({
plugins: [saykit()],
});
import saykit from 'unplugin-saykit/farm';
export default {
plugins: [saykit()],
};import saykit from 'unplugin-saykit/bun';
await Bun.build({
plugins: [saykit()],
});
The plugin takes no options, everything it needs lives in your saykit.config.ts.
What it does
For every file in your bucket's include globs, the plugin asks the configured transformers to rewrite the source. Macros like say`Hello, ${name}!` become small say.call({ id: '...', name }) runtime invocations.
For every import that matches a bucket's output template, e.g. import en from './locales/en.po', the plugin parses the file with the bucket's formatter and emits a JS module exporting the compiled catalogue. There is no .po file at runtime; just plain JS objects.
Plugin ordering
The plugin uses enforce: 'pre' so it runs before most other transforms. That matters because macros need to be visible, if a previous transform mangles or wraps them, extraction may miss messages.
If you have a custom plugin that lowers tagged templates (e.g. to function calls), make sure SayKit's plugin runs first.
Bundler-specific notes
Vite
saykit() plugs in cleanly alongside @vitejs/plugin-react and other Vite plugins, including TanStack Start. Drop it into the plugins array and you're done.
Rolldown / tsdown
Used by the Carbon example to bundle for Cloudflare Workers. See the Carbon integration.
Webpack / Rspack
Should work out of the box, though watch mode varies by bundler. For Next.js, prefer babel-plugin-saykit instead.
esbuild
Sufficient for libraries but limited: esbuild's plugin API can't always produce the same dev-server experience as Vite. Combine with Vite/Rolldown when possible.
Next
- Configuration: tell the plugin what to look at
- Babel plugin: when you need Babel instead