Plugins
Plugins extend both the dev server and the build. The API is intentionally close to the Rollup/Vite shape, so the ecosystem's mental model carries over — but every type is Vantris-owned, and the bundler (Rolldown) is never exposed.
Referencing plugins
Plugins are listed in the config by string — a package name or a path to a local file:
// vantris.config.ts
import { defineConfig } from "vantris";
export default defineConfig({
plugins: ["@vantris/react", "./plugins/my-plugin"],
});Each string is loaded from the project root, and its default export is used — a plugin object (typically wrapped in definePlugin) or a function returning one.
Passing options to a plugin
Because plugins are referenced by string, you can't call a factory with options inline. Instead, wrap the plugin in a tiny local module and reference that file. See @vantris/react → With options.
Authoring a plugin
A plugin is a plain object with a name and one or more optional hooks, authored with the typed definePlugin helper:
// plugins/my-plugin.ts
import { definePlugin } from "vantris";
export default definePlugin({
name: "my-plugin",
enforce: "pre", // optional: "pre" | "post"
// Read or amend the config (returned partials are deep-merged).
config: (config, env) => ({ define: { __BUILT_AT__: Date.now() } }),
// Provide a module's source instead of reading disk (virtual modules, codegen).
load(id) {
if (id.endsWith("version.ts")) return `export const version = "1.0.0";`;
return null;
},
// Rewrite a module's code. Runs in dev and build.
transform(code, id) {
if (id.endsWith(".tsx")) return `${code}\n// touched by my-plugin`;
return null;
},
// Customise HMR for a change (e.g. framework Fast Refresh).
handleHotUpdate(ctx) {
/* ctx.file, ctx.modules, ctx.server.send(event, data), … */
},
});The hooks
| Hook | Runs in | Purpose |
|---|---|---|
config | dev + build | Read or amend the user config (partials deep-merged). |
configResolved | dev + build | Read the fully resolved config. |
configureServer | dev only | Access the running dev server (URL + HMR engine). |
transformIndexHtml | dev + build | Rewrite the HTML entry document. |
buildStart | build | Before the module pipeline starts. |
resolveId | dev + build | Resolve an import to a module id (incl. virtual). |
load | dev + build | Provide a module's source. |
transform | dev + build | Rewrite a module's code. |
buildEnd | build | After the module pipeline finishes. |
handleHotUpdate | dev only | Customise HMR for a change. |
resolveId / load / transform run in both dev and build — resolveId can redirect an import to a virtual module whose source comes from load. Full signatures on the Plugin API page.
Ordering with enforce
Plugins run in the order pre → normal → post, through one container shared by the dev server and the bundler:
definePlugin({ name: "runs-first", enforce: "pre", /* … */ });
definePlugin({ name: "runs-normal", /* … */ });
definePlugin({ name: "runs-last", enforce: "post", /* … */ });Within the same bucket, plugins run in the order they're listed in plugins.
The plugin context
Pipeline hooks (resolveId/load/transform, buildStart/buildEnd) run with a this PluginContext — resolve, emitFile, addWatchFile, warn, error, meta. In the build, this is backed by the bundler's own rich context; in dev, Vantris provides the same surface (a few build-only methods throw).
Where to go next
- Plugin API — every hook, signature, and return type.
- Plugin Context — the
thisyour hooks receive. - Writing a Plugin — a guided, practical walkthrough.
- @vantris/react — the first official plugin.