Vite自定义插件需导出含name、钩子(如transform、resolveId)等属性的对象,遵循Rollup规范并扩展Vite特有钩子;示例实现__APP_VERSION__替换及virtual:app-info虚拟模块注入。

在 Vite 中编写自定义插件,核心是导出一个返回插件对象的函数,该对象包含生命周期钩子(如 configureServer、transform、resolveId 等)和元信息(name、apply)。插件本质是符合 Rollup 插件规范的增强版,同时支持 Vite 特有钩子。
基础结构:一个最简插件示例
比如实现一个在开发时自动注入全局变量 __APP_VERSION__ 的插件:
export default function vitePluginAppVersion(version = 'dev') {
return {
name: 'vite-plugin-app-version', // 必填,唯一标识
enforce: 'pre', // 可选:'pre' | 'post' | undefined,控制执行顺序
transform(code, id) {
if (id.endsWith('.js') || id.endsWith('.ts')) {
return code.replace(/__APP_VERSION__/g, `"${version}"`);
}
}
};
}
然后在 vite.config.ts 中使用:
import { defineConfig } from 'vite';
import vitePluginAppVersion from './plugins/vite-plugin-app-version';
export default defineConfig({
plugins: [vitePluginAppVersion('1.2.0')],
});
常用钩子与适用场景
不同钩子对应不同阶段,选对钩子才能精准干预:
立即学习“Java免费学习笔记(深入)”;
-
configureServer:仅在开发服务器启动时调用,适合添加中间件(如 mock 接口、代理、热更新逻辑) -
transform:源码转换核心钩子,接收文件内容和路径,可修改 AST 或字符串(注意避免破坏 sourcemap) -
resolveId:拦截模块解析过程,可用于别名重写、虚拟模块生成(如virtual:env) -
load:在transform前加载内容,适合读取非标准文件(如 JSON、YAML)并转为 JS 模块 -
buildStart/buildEnd:构建全流程前后触发,适合统计、清理、生成额外产物
处理虚拟模块与按需注入
想提供一个运行时可导入的模块(如 import { version } from 'virtual:app-info'),需配合 resolveId 和 load:
export default function vitePluginVirtualAppInfo({ version }) {
return {
name: 'vite-plugin-virtual-app-info',
resolveId(id) {
if (id === 'virtual:app-info') return '\0virtual:app-info'; // \0 表示虚拟 ID,避免被其他插件处理
},
load(id) {
if (id === '\0virtual:app-info') {
return `export const version = "${version}"; export default { version };`;
}
}
};
}
这样就能在任意模块中安全导入,且不会产生真实文件。
注意事项与最佳实践
- 插件名必须唯一,避免与其他插件冲突;建议加前缀(如
vite-plugin-) - 使用
\0开头的 ID 标识虚拟模块,防止被外部解析或缓存干扰 - 在
transform中做字符串替换要谨慎,优先考虑使用 AST 工具(如acorn+estree-walker)保证准确性 - 开发插件时启用
server.hmr.overlay = false可避免错误遮盖真实报错 - 通过
apply: 'build'或apply: ({ command }) => command === 'serve'控制插件仅在特定命令下生效
不复杂但容易忽略细节。写好一个插件,关键是理解 Vite 的请求流和模块图构建逻辑,再选择合适钩子切入。


















