Vite 插件开发实战:打造属于你的构建工具
2026/4/14 9:03:17 网站建设 项目流程

一、为什么要学 Vite 插件开发?

在使用 Vite 的过程中,你可能会遇到这些场景:

  • 需要在构建时自动生成某些文件
  • 想要自定义模块解析逻辑
  • 需要在开发服务器中添加特定的 API 路由
  • 想要集成特定的代码检查或转换工具

Vite 插件就是解决这些问题的钥匙!

Vite 插件 vs Rollup 插件

Vite 的插件系统基于 Rollup,但做了大量扩展:

特性Rollup 插件Vite 插件
构建阶段✅ 支持✅ 支持
开发服务器❌ 不支持✅ 支持
HMR 热更新❌ 不支持✅ 支持
配置解析❌ 不支持✅ 支持

二、插件基础:Hello World

Vite 插件本质上是一个对象(或返回对象的函数),包含name属性和各种钩子函数:

2.1 最简单的插件

// my-first-plugin.js export default function myFirstPlugin() { return { name: 'my-first-plugin', // 配置解析时调用 config(config, { command }) { console.log('🚀 Vite 模式:', command); // 'serve' 或 'build' return { // 可以返回部分配置,会与用户配置合并 base: command === 'build' ? '/app/' : '/' }; }, // 构建开始时调用 buildStart() { console.log('📦 开始构建...'); }, // 构建结束时调用 buildEnd() { console.log('✅ 构建完成!'); } }; }

使用插件:

// vite.config.js import { defineConfig } from 'vite'; import myFirstPlugin from './my-first-plugin.js'; export default defineConfig({ plugins: [myFirstPlugin()] });

2.2 运行效果

$ npm run dev 🚀 Vite 模式: serve 📦 开始构建... ✅ 构建完成! VITE v5.0.0 ready in 320 ms

三、核心钩子详解

Vite 提供了丰富的钩子函数,覆盖了从配置解析到构建完成的整个生命周期。

3.1 配置相关钩子

export default function configPlugin() { return { name: 'config-plugin', // 1. config - 修改或扩展配置 config(userConfig, { command, mode }) { // command: 'serve' | 'build' // mode: 'development' | 'production' | 自定义 return { resolve: { alias: { '@': '/src' } } }; }, // 2. configResolved - 配置解析完成后 configResolved(resolvedConfig) { // 可以获取最终解析后的配置 console.log('📁 项目根目录:', resolvedConfig.root); console.log('🔧 运行模式:', resolvedConfig.mode); } }; }

3.2 开发服务器钩子

这是 Vite 独有的,Rollup 插件无法使用:

export default function serverPlugin() { return { name: 'server-plugin', // 配置开发服务器 configureServer(server) { // server 是 ViteDevServer 实例 // 添加自定义路由 server.middlewares.use('/api/health', (req, res, next) => { res.end(JSON.stringify({ status: 'ok', time: Date.now() })); }); // 监听文件变化 server.watcher.on('change', (file) => { console.log('📝 文件变化:', file); }); }, // 配置预览服务器(vite preview) configurePreviewServer(server) { server.middlewares.use('/api/version', (req, res) => { res.end(JSON.stringify({ version: '1.0.0' })); }); } }; }

3.3 构建钩子(Rollup 兼容)

export default function buildPlugin() { return { name: 'build-plugin', // 解析模块ID resolveId(source, importer) { if (source === 'virtual-module') { return source; // 返回解析后的ID } }, // 加载模块内容 load(id) { if (id === 'virtual-module') { return 'export const msg = "Hello from virtual module!"'; } }, // 转换代码 transform(code, id) { // 只对 .js 文件进行处理 if (id.endsWith('.js')) { // 简单的代码转换示例 return { code: code.replace(/console\\.log/g, 'console.debug'), map: null // 可以返回 source map }; } } }; }

3.4 完整生命周期图

config → configResolved → configureServer ↓ (开发服务器运行中) ↓ buildStart → resolveId → load → transform ↓ (HMR 触发时重复) ↓ buildEnd → closeBundle

四、实战案例

案例 1:自动生成环境信息文件

开发中经常需要知道当前构建的时间、版本号等信息:

// plugins/build-info-plugin.js import { writeFileSync } from 'fs'; import { resolve } from 'path'; export default function buildInfoPlugin() { return { name: 'build-info', buildStart() { const info = { version: process.env.npm_package_version || '1.0.0', buildTime: new Date().toISOString(), nodeEnv: process.env.NODE_ENV, platform: process.platform }; // 将信息写入 JSON 文件 const outputPath = resolve(process.cwd(), 'public', 'build-info.json'); writeFileSync(outputPath, JSON.stringify(info, null, 2)); console.log('📝 构建信息已生成'); } }; }

使用:

// vite.config.js import buildInfoPlugin from './plugins/build-info-plugin.js'; export default { plugins: [buildInfoPlugin()] };

前端获取:

// App.vue 或任意 JS 文件 fetch('/build-info.json') .then(r => r.json()) .then(info => { console.log('📦 版本:', info.version); console.log('🕐 构建时间:', info.buildTime); });

案例 2:Mock API 服务器

开发时常用的 Mock 数据插件:

// plugins/mock-plugin.js import { readFileSync } from 'fs'; import { resolve } from 'path'; const mockData = { '/api/users': [ { id: 1, name: '张三', role: 'admin' }, { id: 2, name: '李四', role: 'user' } ], '/api/posts': [ { id: 1, title: 'Hello Vite', content: 'Vite 真快!' } ] }; export default function mockPlugin(options = {}) { const { prefix = '/api', delay = 500 } = options; return { name: 'mock-server', configureServer(server) { server.middlewares.use((req, res, next) => { // 只处理 API 请求 if (!req.url.startsWith(prefix)) { return next(); } // 模拟网络延迟 setTimeout(() => { const data = mockData[req.url]; if (data) { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify({ code: 0, data })); } else { res.statusCode = 404; res.end(JSON.stringify({ code: 404, msg: 'Not Found' })); } }, delay); }); } }; }

使用:

// vite.config.js import mockPlugin from './plugins/mock-plugin.js'; export default { plugins: [ mockPlugin({ prefix: '/api', delay: 300 // 模拟 300ms 延迟 }) ] };

案例 3:条件编译(类似 #ifdef)

实现类似 C 语言的条件编译功能:

// plugins/conditional-compile-plugin.js export default function conditionalCompilePlugin(options = {}) { const { env = {} } = options; return { name: 'conditional-compile', transform(code, id) { // 只对 JS/TS/Vue 文件处理 if (!/\\.(js|ts|vue)$/.test(id)) return; // 匹配 //#ifdef KEY ... //#endif const regex = /\\/\\/\\s*#ifdef\\s+(\\w+)\\s*([\\s\\S]*?)\\/\\/\\s*#endif/g; return { code: code.replace(regex, (match, key, content) => { // 如果环境变量存在且为真,保留内容,否则删除 return env[key] ? content : ''; }), map: null }; } }; }

使用:

// vite.config.js import conditionalCompile from './plugins/conditional-compile-plugin.js'; export default { plugins: [ conditionalCompile({ env: { DEBUG: process.env.NODE_ENV === 'development', PRO_FEATURE: false } }) ] };

源代码中:

function initApp() { //#ifdef DEBUG console.log('调试模式启动'); console.log('配置信息:', config); //#endif //#ifdef PRO_FEATURE loadProModules(); //#endif startApp(); }

构建后(DEBUG=true, PRO_FEATURE=false):

function initApp() { console.log('调试模式启动'); console.log('配置信息:', config); startApp(); }

五、进阶技巧

5.1 虚拟模块

创建不对应真实文件的模块:

// plugins/virtual-module-plugin.js const virtualModuleId = 'virtual:app-config'; const resolvedVirtualModuleId = '\\0' + virtualModuleId; export default function virtualModulePlugin() { return { name: 'virtual-module', resolveId(id) { if (id === virtualModuleId) { return resolvedVirtualModuleId; } }, load(id) { if (id === resolvedVirtualModuleId) { return ` export const appName = 'My Awesome App'; export const version = '${process.env.npm_package_version}'; export const features = { darkMode: true, i18n: true }; `; } } }; }

使用:

import { appName, version, features } from 'virtual:app-config'; console.log(appName); // 'My Awesome App'

5.2 HMR 热更新支持

让插件支持热更新:

export default function hmrPlugin() { return { name: 'hmr-plugin', handleHotUpdate({ server, modules, timestamp }) { // 自定义 HMR 处理逻辑 // 过滤特定模块 const filtered = modules.filter(m => !m.id.includes('node_modules')); console.log('🔄 热更新模块:', filtered.map(m => m.id)); // 返回模块列表,Vite 会继续处理 return filtered; } }; }

5.3 插件排序

控制插件执行顺序:

export default { plugins: [ { ...myPlugin(), enforce: 'pre' // 'pre' | 'post',默认 normal } ] };

六、发布你的插件

6.1 插件项目结构

vite-plugin-awesome/ ├── src/ │ └── index.js # 插件入口 ├── package.json ├── README.md └── LICENSE

6.2 package.json 配置

{ "name": "vite-plugin-awesome", "version": "1.0.0", "description": "An awesome Vite plugin", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", "files": ["dist"], "scripts": { "build": "rollup -c", "prepublishOnly": "npm run build" }, "peerDependencies": { "vite": "^4.0.0 || ^5.0.0" }, "keywords": ["vite", "plugin", "vite-plugin"], "license": "MIT" } 6.3 发布到 npm

6.3 发布到 npm

npm login npm publish

七、常用插件推荐

插件功能
@vitejs/plugin-vueVue 单文件组件支持
@vitejs/plugin-reactReact Fast Refresh
vite-plugin-pwaPWA 支持
unplugin-auto-import自动导入 API
vite-plugin-svg-iconsSVG 图标雪碧图
vite-plugin-mockMock 数据服务

八、总结

Vite 插件开发并不复杂,核心要点:

必须掌握

  • 插件基本结构(name + hooks)
  • 常用钩子:configtransformconfigureServer
  • 虚拟模块的使用

进阶技能

  • HMR 热更新处理
  • 开发服务器中间件
  • 构建流程控制

最佳实践

  • 插件选项设计要灵活
  • 提供详细的文档和示例
  • 处理好错误边界

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询