Custom Plugin Development Guide
The plugin system of Vite.js is based on the Rollup plugin mechanism, allowing developers to intervene in the build process through hook functions. Custom plugins can extend build capabilities, such as transforming code, handling static assets, or modifying module resolution logic. Below, we will expand step by step from plugin structure, commonly used hooks to practical examples.
Basic Plugin Structure
A Vite plugin needs to export a function or object containing a name and core hook functions. The simplest form of a plugin is as follows:
// vite-plugin-example.js
export default function myPlugin() {
return {
name: 'vite-plugin-example',
// Plugin hooks will be defined here
transform(code, id) {
if (id.endsWith('.custom')) {
return { code: code.replace(/foo/g, 'bar') }
}
}
}
}
The plugin configuration is introduced via vite.config.js
:
import myPlugin from './vite-plugin-example'
export default {
plugins: [myPlugin()]
}
Core Hooks Explained
config Hook
Executed before resolving the Vite configuration, allowing modification of the final configuration. Receives the original configuration and an env
object:
config(config, { mode }) {
if (mode === 'development') {
config.server.port = 3001
}
}
transformIndexHtml
A hook specifically for processing HTML entry files:
transformIndexHtml(html) {
return html.replace(
'<title>Default Title</title>',
'<title>Customized Title</title>'
)
}
resolveId
Custom module resolution logic. The following example redirects virtual:module
to a real path:
resolveId(source) {
if (source === 'virtual:module') {
return '\0' + source // Add virtual module marker
}
}
load
Load virtual module content:
load(id) {
if (id === '\0virtual:module') {
return 'export const msg = "From virtual module"'
}
}
Virtual Module Example
Creating a virtual module that provides environment variables:
// 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)}`
}
}
}
}
Usage:
// vite.config.js
import envPlugin from './vite-plugin-env'
export default {
plugins: [
envPlugin({
API_URL: 'https://api.example.com'
})
]
}
// Reference in components
import env from 'virtual:env'
console.log(env.API_URL)
Hot Module Reloading (HMR) Handling
Implement custom HMR logic via handleHotUpdate
:
handleHotUpdate({ file, server }) {
if (file.endsWith('.data')) {
server.ws.send({
type: 'custom',
event: 'data-update',
data: { changed: file }
})
}
}
Client-side event listening:
if (import.meta.hot) {
import.meta.hot.on('data-update', (data) => {
console.log('File changed:', data.changed)
})
}
Static Asset Transformation
Process specific asset types via transform
. The following example converts .txt
files into JS modules:
transform(code, id) {
if (id.endsWith('.txt')) {
return {
code: `export default ${JSON.stringify(code)}`,
map: null
}
}
}
Plugin Configuration Options
It is recommended to use a factory function to receive user configurations:
// vite-plugin-options.js
export default function(options = {}) {
return {
name: 'vite-plugin-options',
config() {
console.log('Received options:', options)
}
}
}
// Configuration example
plugins: [
require('./vite-plugin-options')({
featureFlags: ['new-header', 'dark-mode']
})
]
Performance Optimization Tips
- Use
enforce: 'pre'
to make the plugin execute before core plugins:
return {
name: 'vite-plugin-early',
enforce: 'pre'
}
- Control the plugin's runtime environment via
apply
:
apply: 'build' // or 'serve'
- Cache transformation results:
transform(code, id) {
if (hasCache(id)) {
return cache.get(id)
}
// ...processing logic
}
Debugging Tips
Insert debugging breakpoints in the plugin:
configResolved(config) {
debugger
// Execution will pause here
}
Access development server information via the server
instance:
configureServer(server) {
server.httpServer?.once('listening', () => {
console.log('Server port:', server.config.server.port)
})
}
Complex Example: Markdown Transformation
A complete plugin to convert .md
files into Vue components:
// 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
}
}
}
}
Plugin Interaction
Data sharing between multiple plugins can be achieved via the meta
object:
// Plugin A writes data
transform(code, id) {
this.meta.sharedData = { version: '1.0' }
}
// Plugin B reads data
configResolved(config) {
console.log('Shared data:', config.plugins
.find(p => p.name === 'plugin-a')
?.meta.sharedData)
}
Build Phase Extension
Example of modifying Rollup output hooks:
generateBundle(options, bundle) {
for (const [fileName, chunk] of Object.entries(bundle)) {
if (fileName.endsWith('.js')) {
chunk.code = `/* Build time: ${new Date().toISOString()} */\n${chunk.code}`
}
}
}
Error Handling Standards
Recommended way to throw errors:
transform(code, id) {
try {
// Transformation logic
} catch (err) {
this.error('Transformation failed', {
line: err.line,
column: err.column
})
}
}
Type Hint Support
Add TypeScript type definitions for the plugin:
// 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
上一篇:常用社区插件生态介绍
下一篇:插件执行顺序控制