自定义插件开发指南
Vite.js 的插件系统基于 Rollup 插件机制扩展,允许开发者通过钩子函数干预构建流程。自定义插件可以扩展构建能力,例如转换代码、处理静态资源或修改模块解析逻辑。下面从插件结构、常用钩子到实战案例逐步展开。
插件基本结构
一个 Vite 插件需要导出一个函数或对象,包含名称和核心钩子函数。最简单的插件形式如下:
// vite-plugin-example.js
export default function myPlugin() {
return {
name: 'vite-plugin-example',
// 插件钩子将在这里定义
transform(code, id) {
if (id.endsWith('.custom')) {
return { code: code.replace(/foo/g, 'bar') }
}
}
}
}
插件配置通过 vite.config.js
引入:
import myPlugin from './vite-plugin-example'
export default {
plugins: [myPlugin()]
}
核心钩子详解
config 钩子
在解析 Vite 配置前执行,可修改最终配置。接收原始配置和 env
对象:
config(config, { mode }) {
if (mode === 'development') {
config.server.port = 3001
}
}
transformIndexHtml
专门处理 HTML 入口文件的钩子:
transformIndexHtml(html) {
return html.replace(
'<title>Default Title</title>',
'<title>Customized Title</title>'
)
}
resolveId
自定义模块解析逻辑。以下示例将 virtual:module
重定向到真实路径:
resolveId(source) {
if (source === 'virtual:module') {
return '\0' + source // 添加虚拟模块标记
}
}
load
加载虚拟模块内容:
load(id) {
if (id === '\0virtual:module') {
return 'export const msg = "来自虚拟模块"'
}
}
虚拟模块实战
创建提供环境变量的虚拟模块:
// vite-plugin-env.js
export default function envPlugin(envVars) {
const virtualModuleId = 'virtual:env'
return {
name: 'vite-plugin-env',
resolveId(id) {
if (id === virtualModuleId) {
return '\0' + virtualModuleId
}
},
load(id) {
if (id === '\0' + virtualModuleId) {
return `export default ${JSON.stringify(envVars)}`
}
}
}
}
使用方式:
// vite.config.js
import envPlugin from './vite-plugin-env'
export default {
plugins: [
envPlugin({
API_URL: 'https://api.example.com'
})
]
}
// 组件中引用
import env from 'virtual:env'
console.log(env.API_URL)
热更新处理
通过 handleHotUpdate
实现自定义 HMR 逻辑:
handleHotUpdate({ file, server }) {
if (file.endsWith('.data')) {
server.ws.send({
type: 'custom',
event: 'data-update',
data: { changed: file }
})
}
}
客户端监听事件:
if (import.meta.hot) {
import.meta.hot.on('data-update', (data) => {
console.log('文件变更:', data.changed)
})
}
静态资源转换
通过 transform
处理特定资源类型。以下示例将 .txt
文件转为 JS 模块:
transform(code, id) {
if (id.endsWith('.txt')) {
return {
code: `export default ${JSON.stringify(code)}`,
map: null
}
}
}
插件配置选项
推荐使用工厂函数接收用户配置:
// vite-plugin-options.js
export default function(options = {}) {
return {
name: 'vite-plugin-options',
config() {
console.log('接收到的配置:', options)
}
}
}
// 配置示例
plugins: [
require('./vite-plugin-options')({
featureFlags: ['new-header', 'dark-mode']
})
]
性能优化技巧
- 使用
enforce: 'pre'
让插件在核心插件前执行:
return {
name: 'vite-plugin-early',
enforce: 'pre'
}
- 通过
apply
控制插件运行环境:
apply: 'build' // 或 'serve'
- 缓存转换结果:
transform(code, id) {
if (hasCache(id)) {
return cache.get(id)
}
// ...处理逻辑
}
调试技巧
在插件中插入调试断点:
configResolved(config) {
debugger
// 运行时会在此处暂停
}
通过 server
实例访问开发服务器信息:
configureServer(server) {
server.httpServer?.once('listening', () => {
console.log('服务器端口:', server.config.server.port)
})
}
复杂示例:Markdown 转换
实现将 .md
文件转为 Vue 组件的完整插件:
// vite-plugin-md.js
import { compile } from 'markdown-to-jsx-compiler'
export default function mdPlugin() {
return {
name: 'vite-plugin-md',
transform(code, id) {
if (!id.endsWith('.md')) return
const jsx = compile(code)
return {
code: `
<script setup>
const content = ${JSON.stringify(jsx)}
</script>
<template>
<div v-html="content" />
</template>
`,
map: null
}
}
}
}
插件交互
多个插件间的数据共享可通过 meta
对象实现:
// 插件A写入数据
transform(code, id) {
this.meta.sharedData = { version: '1.0' }
}
// 插件B读取数据
configResolved(config) {
console.log('共享数据:', config.plugins
.find(p => p.name === 'plugin-a')
?.meta.sharedData)
}
构建阶段扩展
修改 Rollup 输出的钩子示例:
generateBundle(options, bundle) {
for (const [fileName, chunk] of Object.entries(bundle)) {
if (fileName.endsWith('.js')) {
chunk.code = `/* 构建时间: ${new Date().toISOString()} */\n${chunk.code}`
}
}
}
错误处理规范
推荐的错误抛出方式:
transform(code, id) {
try {
// 转换逻辑
} catch (err) {
this.error('转换失败', {
line: err.line,
column: err.column
})
}
}
类型提示支持
为插件添加 TypeScript 类型定义:
// types/vite-plugin-example.d.ts
import { Plugin } from 'vite'
declare interface PluginOptions {
prefix?: string
}
export declare function myPlugin(options?: PluginOptions): Plugin
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:常用社区插件生态介绍
下一篇:插件执行顺序控制