二、第一个 Vite Plugin
2.1 创建基础 Plugin
export default function examplePlugin() {
return {
name: 'vite-plugin-example',
config(config) {
console.log('config hook');
return {
define: {
__PLUGIN_VERSION__: '"1.0.0"'
}
};
},
configResolved(config) {
console.log('configResolved hook');
},
transform(code, id) {
console.log('transform:', id);
return code;
}
};
}
2.2 在 Vite 配置中使用
import { defineConfig } from 'vite';
import examplePlugin from './plugins/vite-plugin-example';
export default defineConfig({
plugins: [
examplePlugin()
]
});
三、核心钩子详解
3.1 config 和 configResolved
export default function configPlugin() {
return {
name: 'config-plugin',
config(config, { command, mode }) {
console.log('Command:', command);
console.log('Mode:', mode);
return {
server: {
port: 3000
},
build: {
outDir: 'dist'
}
};
},
configResolved(config) {
console.log('Final config:', config);
}
};
}
3.2 configureServer 开发服务器
export default function devServerPlugin() {
return {
name: 'dev-server-plugin',
configureServer(server) {
server.middlewares.use((req, res, next) => {
console.log('Request:', req.url);
next();
});
server.middlewares.use('/api/hello', (req, res) => {
res.end('Hello from Vite Plugin!');
});
server.ws.on('connection', (ws) => {
ws.send('Welcome!');
});
}
};
}
3.3 transformIndexHtml 转换 HTML
export default function htmlPlugin() {
return {
name: 'html-plugin',
transformIndexHtml(html) {
return html.replace(
'<head>',
`<head>
<meta name="plugin-version" content="1.0.0">
`
);
}
transformIndexHtml(html) {
return {
html,
tags: [
{
tag: 'script',
attrs: { src: '/custom-script.js' },
injectTo: 'head'
}
]
};
}
};
}
四、Rollup 钩子在 Vite 中的应用
4.1 resolveId 解析模块
export default function resolvePlugin() {
return {
name: 'resolve-plugin',
resolveId(source, importer) {
if (source === 'virtual:my-module') {
return '\0virtual:my-module';
}
return null;
}
};
}
4.2 load 加载模块
export default function loadPlugin() {
return {
name: 'load-plugin',
load(id) {
if (id === '\0virtual:my-module') {
return `
export const message = 'Hello from virtual module!';
export const version = '1.0.0';
`;
}
return null;
}
};
}
4.3 transform 转换代码
export default function transformPlugin() {
return {
name: 'transform-plugin',
transform(code, id) {
if (!id.endsWith('.js')) return;
const transformedCode = code.replace(
/console\.log\(/g,
'console.log("[Plugin] "'
);
return {
code: transformedCode,
map: null
};
}
};
}
五、实战案例一:虚拟模块
5.1 创建虚拟模块 Plugin
export default function virtualModulePlugin() {
const virtualModuleId = 'virtual:env-info';
const resolvedVirtualModuleId = '\0' + virtualModuleId;
return {
name: 'vite-plugin-virtual',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId;
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `
export const NODE_ENV = '${process.env.NODE_ENV || 'development'}';
export const VERSION = '${process.env.npm_package_version || '1.0.0'}';
export const BUILD_TIME = '${new Date().toISOString()}';
`;
}
}
};
}
5.2 使用虚拟模块
import { NODE_ENV, VERSION, BUILD_TIME } from 'virtual:env-info';
console.log('Environment:', NODE_ENV);
console.log('Version:', VERSION);
console.log('Build Time:', BUILD_TIME);
六、实战案例二:处理自定义文件
6.1 处理 .yaml 文件
import yaml from 'js-yaml';
export default function yamlPlugin() {
return {
name: 'vite-plugin-yaml',
transform(code, id) {
if (id.endsWith('.yaml') || id.endsWith('.yml')) {
try {
const data = yaml.load(code);
return {
code: `export default ${JSON.stringify(data)};`
};
} catch (e) {
this.error(e.message);
}
}
}
};
}
6.2 使用 YAML 文件
app:
name: My App
version: 1.0.0
database:
host: localhost
port: 5432
import config from './config.yaml';
console.log(config.app.name);
console.log(config.database.port);
七、实战案例三:热更新处理
7.1 自定义 HMR
export default function hmrPlugin() {
return {
name: 'vite-plugin-hmr',
handleHotUpdate({ file, server, modules }) {
console.log('File changed:', file);
if (file.endsWith('.special')) {
server.ws.send({
type: 'custom',
event: 'special-update',
data: { file }
});
return [];
}
return modules;
}
};
}
7.2 客户端接收 HMR
if (import.meta.hot) {
import.meta.hot.on('special-update', (data) => {
console.log('Special update:', data);
});
}
八、插件开发技巧
8.1 区分开发与生产环境
export default function envPlugin() {
let isDev;
return {
name: 'env-plugin',
configResolved(config) {
isDev = config.command === 'serve';
},
transform(code, id) {
if (isDev) {
return code + '\nconsole.log("Dev only");';
} else {
return code;
}
}
};
}
8.2 插件排序
export default defineConfig({
plugins: [
pluginA(),
pluginB(),
]
});
export default function plugin() {
return {
name: 'my-plugin',
enforce: 'pre',
};
}
九、调试与测试
9.1 调试 Plugin
import createDebug from 'debug';
const debug = createDebug('vite-plugin-example');
export default function debugPlugin() {
return {
name: 'debug-plugin',
transform(code, id) {
debug('Transforming:', id);
return code;
}
};
}
9.2 测试 Plugin
import { createServer } from 'vite';
import myPlugin from '../index.js';
test('plugin works', async () => {
const server = await createServer({
plugins: [myPlugin()]
});
await server.close();
});
十、最佳实践
- 命名规范:使用
vite-plugin- 前缀
- TypeScript:使用 TS 开发,提供类型
- 文档:完善的 README
- 测试:提供单元测试
- 兼容性:考虑不同 Vite 版本