Plugins & virtual modules
Extend the build with a nowaki.config.mjs. Plugins run in a Node host during dev and build (never in the production request path) and stay out of the way when unused.
The config
// nowaki.config.mjs
export default {
plugins: [
{
name: "my-plugin",
transform(code, id) { /* return new code or null */ },
resolveId(source, importer) { /* claim a specifier or return null */ },
load(id) { /* return source for a virtual id or null */ },
},
],
};Transform hook
transform(code, id) runs before oxc on every transformable source. Return new code, or null to leave it unchanged (the fast path).
transform(code, id) {
if (!code.includes("__BUILD_DATE__")) return null;
return code.replaceAll("__BUILD_DATE__", JSON.stringify(new Date().toISOString()));
}Virtual modules v0.9
Provide modules that don't exist on disk. resolveId claims a bare specifier;load returns its source. Useful for generated config, build info, or a routes manifest.
{
name: "build-info",
resolveId(source) {
return source === "virtual:build-info" ? source : null;
},
load(id) {
if (id !== "virtual:build-info") return null;
return `export const builtAt = ${Date.now()};`;
},
}// any island
import { builtAt } from "virtual:build-info";On the client the generated source is bundled inline into the island chunk; for SSR it's inlined as a self-contained data: module. Resolution only calls into the plugin when the normal resolver fails, so there's no overhead for ordinary imports. (For SSR, keep virtual modules self-contained — they shouldn't have relative imports.)
The .tsrx bridge
If @tsrx/preact is installed, .tsrx files are compiled to standard JSX before joining the oxc pipeline — an optional, app-level dependency.