Custom plugins solve code generation, integrations and build-time transforms that no config option covers.
A plugin is an object with a name and hook functions, usually returned from a factory so it can take options.
Rollup-compatible hooks (run in dev and build):
resolveId(source, importer): map an import specifier to an id. Returning an id prefixed with\0marks it as virtual so other plugins leave it alone.load(id): return the code for an id, e.g. generated source for a virtual module.transform(code, id): modify a module's code; return{ code, map }with a source map when possible. Use hook filters (transform: { filter: { id: /\.md$/ }, handler }) so the native bundler can skip calling into JavaScript for irrelevant files, a big speed win with Rolldown.buildStart,generateBundleand other build hooks.
Vite-specific hooks:
config/configResolved: modify or read the final config.configureServer(server): add dev-server middleware (server.middlewares.use) or watch extra files.transformIndexHtml: inject tags intoindex.html.hotUpdate: customize HMR for certain files.
By convention, virtual module ids start with virtual: in user-facing imports. Name plugins vite-plugin-* (or rolldown-plugin-* if bundler-agnostic). Debug with vite-plugin-inspect, which shows every transform step per module.
Example
// vite.config.js
import { defineConfig } from "vite";
function buildInfo() {
const id = "virtual:build-info";
return {
name: "build-info",
resolveId(source) {
if (source === id) return "\0" + id; // virtual module id
},
load(resolved) {
if (resolved === "\0" + id) {
return `export default ${JSON.stringify({ builtAt: new Date().toISOString() })};`;
}
},
transformIndexHtml(html) {
return html.replace("</head>", `<meta name="generator" content="vite"></head>`);
},
};
}
export default defineConfig({ plugins: [buildInfo()] });
// in app code: import info from "virtual:build-info"; info.builtAtRemember
- resolveId + load create virtual modules (
\0prefix) - transform rewrites code; return source maps
- Hook filters let Rolldown skip JS calls for irrelevant files
- Vite-only hooks: configureServer, transformIndexHtml, hotUpdate
Watch out for
- Transforming every file with a regex check inside the hook instead of a hook filter.