Browse docs

Tooling

Build: Vite Plugin & CLI

ReactVanilla

Reads stift.config.ts and emits the generated runtime + type augmentation consumed by createStift.

Vite plugin

// vite.config.ts
import { stiftPlugin } from '@secundus-studio/stift-vite-plugin'

export default defineConfig({
  plugins: [stiftPlugin({ devtools: { allowFileWrites: true } })],
})
pnpm add @secundus-studio/stift-vite-plugin@0.4.0

First wired in the Quickstart.

Generated files (into src/ by default)

  • stift.gen.d.ts — augments @secundus-studio/stift-core@0.4.0 (Register) so message keys, RegisteredLocale, and currencies narrow to your real locales/**. Flows through useConfig(), useLocale(), t().
  • virtual:stift/runtime — createStiftRuntime() returns { config, catalog, fetchCatalog, source }; spread it into createStift(...).

Both regenerate whenever the config or locales/** change. Each locale×namespace compiles to a binary .dat pack (msgpack/cbor + compression per security) plus a catalog.json of content hashes — the same bytes in dev (served through dev-server middleware) and prod, so dev/prod are byte-identical.

CLI

The stift bin covers non-Vite flows: generate (one-shot typegen + pack compile), watch (rebuild on locale/config change), compile (packs only).

Devtools write bridge

  • allowFileWrites: true (Vite plugin) plus allowFileWrites: true (devtools plugin factory) mount the /__stift_devtools/write bridge so the panel's inline editor persists into locales/**.
  • With the default false the route is never mounted — zero code path can write to disk.
  • Keep it off in prod; the whole devtools surface is gated by import.meta.env.DEV anyway.

On a panel write: the file lands in locales/** (server logs [stift] devtools write: <locale>/<ns>#<key> -> <file>), the plugin recompiles the changed namespace(s) and invalidates the virtual modules, and the write is recorded in a suppression set before any watcher tick fires — the watcher skips its refresh and suppresses the full page reload, so the edit lands in place with no refresh. Manual IDE edits are not suppressed: they hit the watcher and full-reload as usual.

Next