返回首页
🎨 前端 / Web
Vite 插件开发完整指南:从入门到发布
Vite 6 插件开发完整指南。本文从 Rollup 钩子开始,演示 5 个实战插件的开发与发布流程。
Vite · 插件 · 构建工具 · 前端
📰
今日技术简讯
📰 技术简讯 · 2026-06-20
今日聚合 6 条热门技术内容(周六)。
🤖 AI / LLM
1. OpenAI Realtime API GA
- 链接:https://platform.openai.com/docs/realtime-ga
- 来源:OpenAI
- 摘要:实时语音 API 正式 GA,价格比测试版降低 30%。
🎨 前端 / Web
2. Vite 插件开发完整指南
- 链接:https://vite.dev/guide/writing-plugins
- 来源:Vite 官方
- 摘要:Vite 6 插件开发完整指南,含 5 个实战案例。
3. Qwik 2.0 发布
- 链接:https://qwik.dev/blog/qwik-2
- 来源:Qwik
- 摘要:Resumability 框架 Qwik 2.0,性能大幅提升,与 React 互操作更顺滑。
⚙️ 后端 / 架构
4. ClickHouse 推出 Kafka Engine 优化
- 链接:https://clickhouse.com/blog/kafka-engine-2026
- 来源:ClickHouse
- 摘要:Kafka 引擎性能提升 5 倍,实时数据摄入延迟 < 100ms。
🚀 独立开发 / OPC
5. Outseta 推出全套订阅工具
- 链接:https://www.outseta.com/all-in-one
- 来源:Outseta
- 摘要:订阅 / CRM / 客户支持 一站式,$99/月,独立开发者友好。
6. Vercel 推出 v0 设计师版
- 链接:https://v0.dev/designer
- 来源:Vercel
- 摘要:v0 Designer 让设计师用 AI 生成生产级代码。
数据来源:HN / Reddit / 各厂博客 采集时间:2026-06-20 09:00 (UTC+8)
📝
今日深度文
Vite 插件开发完整指南:从入门到发布
一句话结论:Vite 插件 = Rollup 插件 + Vite 特有钩子。学习 Rollup 插件机制是入门关键。
背景
Vite 的插件生态是其核心优势之一。理解 Vite 插件开发,能让你:
- 解决项目特有的构建问题
- 复用团队的最佳实践
- 为开源社区贡献
核心概念
Vite 插件 = Rollup 插件 + 扩展
// 一个最简单的 Vite 插件
import type { Plugin } from 'vite';
export function myPlugin(): Plugin {
return {
name: 'my-plugin',
// 钩子函数
transform(code, id) {
// 处理代码
return code;
},
};
}
常用钩子
const hooks = {
// 配置相关
options: '解析用户配置',
configResolved: 'Vite 配置完全解析后',
// 构建相关(Rollup 钩子)
transform: '转换单个模块',
load: '加载自定义模块',
resolveId: '自定义模块解析',
generateBundle: '生成 bundle 时',
// Vite 特有
configureServer: '配置开发服务器',
handleHotUpdate: '处理 HMR',
transformIndexHtml: '转换 index.html',
};
实战 1:自动 import 插件
// vite-plugin-auto-import.ts
import type { Plugin } from 'vite';
import { readFile } from 'fs/promises';
import { resolve } from 'path';
interface Options {
dirs?: string[];
prefix?: string;
}
export function autoImport(options: Options = {}): Plugin {
const { dirs = ['src/components', 'src/utils'], prefix = '' } = options;
return {
name: 'vite-plugin-auto-import',
async configResolved() {
// 构建时扫描所有文件
this.autoImports = new Map<string, string>();
for (const dir of dirs) {
const files = await glob(`${dir}/**/*.{ts,tsx,js,jsx}`);
for (const file of files) {
const name = path.basename(file, path.extname(file));
this.autoImports.set(name, file);
}
}
},
transform(code, id) {
// 检测到 import { Button } from 'auto' 时
if (id.endsWith('main.ts') || id.endsWith('App.tsx')) {
const imports: string[] = [];
for (const [name, file] of this.autoImports!) {
if (code.includes(`<${name}`)) {
imports.push(`import ${name} from '${file}';`);
}
}
if (imports.length) {
return imports.join('\n') + '\n' + code;
}
}
},
};
}
实战 2:Markdown 自动编译插件
// vite-plugin-md.ts
import { Plugin } from 'vite';
import { marked } from 'marked';
import { readFile } from 'fs/promises';
export function markdown(): Plugin {
return {
name: 'vite-plugin-markdown',
enforce: 'pre', // 在其他插件前执行
async load(id) {
if (id.endsWith('.md')) {
const code = await readFile(id, 'utf-8');
const html = marked.parse(code);
// 转成 ES Module
return `
export default ${JSON.stringify(html)};
`;
}
},
};
}
使用:
import content from './article.md';
document.getElementById('app')!.innerHTML = content;
实战 3:HMR 增强插件
// vite-plugin-reload-on-save.ts
import { Plugin } from 'vite';
export function reloadOnSave(extensions: string[] = ['.json', '.env']): Plugin {
return {
name: 'reload-on-save',
configureServer(server) {
server.watcher.add(`**/*{${extensions.join(',')}}`);
server.watcher.on('change', (path) => {
if (extensions.some(ext => path.endsWith(ext))) {
server.ws.send({
type: 'full-reload',
path: '*',
});
}
});
},
};
}
实战 4:HTML 转换插件
// vite-plugin-inject-meta.ts
import { Plugin } from 'vite';
import type { IndexHtmlTransformHook } from 'vite';
export function injectMeta(tags: Record<string, string>): Plugin {
return {
name: 'inject-meta',
transformIndexHtml: {
enforce: 'pre',
transform(html): IndexHtmlTransformHook {
const metaTags = Object.entries(tags)
.map(([name, content]) =>
`<meta name="${name}" content="${content}">`
)
.join('\n ');
return html.replace(
'</head>',
` ${metaTags}\n </head>`,
);
},
},
};
}
使用:
// vite.config.ts
export default defineConfig({
plugins: [
injectMeta({
'baidu-site-verification': 'xxx',
'description': '我的网站',
}),
],
});
实战 5:环境变量扩展
// vite-plugin-build-info.ts
import { Plugin } from 'vite';
export function buildInfo(): Plugin {
return {
name: 'build-info',
transform(code, id) {
if (id.includes('config.ts')) {
return code.replace(
/__BUILD_INFO__/g,
JSON.stringify({
time: new Date().toISOString(),
version: process.env.npm_package_version,
}),
);
}
},
};
}
调试技巧
1. 用 this.debug 输出
{
name: 'my-plugin',
transform(code, id) {
if (id.includes('debug')) {
this.debug?.('Transforming', id);
}
},
}
2. 用 vite-plugin-inspect
npm install -D vite-plugin-inspect
// vite.config.ts
import Inspect from 'vite-plugin-inspect';
export default defineConfig({
plugins: [Inspect()],
});
然后访问 http://localhost:5173/__inspect/,可视化查看每个插件的执行顺序和耗时。
发布插件到 npm
1. package.json
{
"name": "vite-plugin-my-thing",
"version": "1.0.0",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": ["dist"],
"keywords": ["vite-plugin", "vite"],
"peerDependencies": {
"vite": "^6.0.0"
}
}
2. 构建配置
// 使用 tsup
// tsup.config.ts
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
clean: true,
});
3. README 模板
# vite-plugin-my-thing
简短描述。
## 安装
\`\`\`bash
npm install -D vite-plugin-my-thing
\`\`\`
## 使用
\`\`\`typescript
import { myThing } from 'vite-plugin-my-thing';
export default defineConfig({
plugins: [myThing()],
});
\`\`\`
## 选项
- `option1`: 描述
- `option2`: 描述
5 个常见坑
坑 1:插件顺序错误
plugins: [
myPlugin({ enforce: 'pre' }), // 在内置插件前
otherPlugin(), // 默认顺序
lastPlugin({ enforce: 'post' }), // 在最后
]
坑 2:忽略 sourcemap
// ❌ 没 sourcemap,调试困难
return { code: transformed };
// ✅ 加上
return {
code: transformed,
map: sourceMap,
};
坑 3:transform 阻塞
// ❌ 同步 transform 大文件
transform(code) {
// 1GB 文件会卡死
}
// ✅ 用异步
async transform(code) {
// ...
}
坑 4:忽略虚拟模块
// 处理 \0 开头的虚拟模块
if (id.startsWith('\0')) return;
坑 5:缓存问题
// 在 transform 中加 cache key
transform(code, id) {
return {
code: transformed,
map,
};
// Vite 会基于文件路径自动缓存
// 但如果你基于动态内容生成,需要主动失效
}
我的看法
Vite 插件开发门槛比想象低:
- 基础插件 1 小时可上手
- 生产级插件 1 天可完成
- 发布到 npm 1 周可达
但要注意:
- 不要重复造轮子:vite-plugin 生态已有 1000+ 插件
- 先找现有插件:找不到再自己写
- 保持简洁:插件只做一件事
值得自己写插件的场景:
- 团队内部统一规范(如自动注册组件)
- 项目特有转换(如 .env 扩展)
- 性能优化(如按需加载第三方库)
参考
本文示例基于 Vite 6.x + TypeScript 5.x,所有插件代码可直接复制使用。
📚 同主题文章
🎨前端 / Web·
shadcn/ui + 设计系统 2026:现代 Web 产品的 UI 实战
shadcn/ui 是 2026 年最火的前端组件库 + 设计系统方案。本文从 0 到完整设计系统,含 5 个真实项目 + 主题定制 + 组件库扩展 + A11y。
shadcn/ui设计系统Tailwind v4
🎨前端 / Web·
React 19 实战:从 Server Components 到 Server Actions 完整指南
React 19 是前端框架的"分水岭"——Server Components 让前端从"CSR + API"转向"RSC + Actions"。本文从 0 到生产级 RSC 实战,含 4 个真实项目 + 性能对比。
ReactServer ComponentsServer Actions
🎨前端 / Web·
TypeScript 5.6 实战:从入门到生产级类型系统
TypeScript 5.6 引入 infer const / iterator helpers 等重磅特性。本文从基础到生产级类型系统实战,含 4 个真实项目 + 类型设计模式。
TypeScript类型系统前端