Vite 插件
插件基础
Vite 插件扩展自 Rollup 插件接口,并添加了 Vite 特有的钩子。
基本结构
ts
interface Plugin {
name: string // 插件名称
enforce?: 'pre' | 'post' // 执行顺序控制
apply?: 'serve' | 'build' | Function // 应用环境
// Rollup 通用钩子
resolveId(id, importer, options)
load(id)
transform(code, id)
// Vite 特有钩子
config(config, env) // 修改 Vite 配置
configResolved(config) // 配置被解析后
configureServer(server) // 配置开发服务器
transformIndexHtml(html) // 转换 HTML
handleHotUpdate(ctx) // HMR 处理
}interface Plugin {
name: string // 插件名称
enforce?: 'pre' | 'post' // 执行顺序控制
apply?: 'serve' | 'build' | Function // 应用环境
// Rollup 通用钩子
resolveId(id, importer, options)
load(id)
transform(code, id)
// Vite 特有钩子
config(config, env) // 修改 Vite 配置
configResolved(config) // 配置被解析后
configureServer(server) // 配置开发服务器
transformIndexHtml(html) // 转换 HTML
handleHotUpdate(ctx) // HMR 处理
}简单插件示例
ts
// vite-plugin-copyright.js
function vitePluginCopyright() {
return {
name: 'vite-plugin-copyright',
enforce: 'pre',
// 向 HTML 注入内容
transformIndexHtml(html) {
return html.replace('</head>', '<meta name="author" content="your-name"></head>')
},
// 转换代码
transform(code, id) {
if (id.endsWith('.js')) {
return `/* Copyright 2026 */\n${code}`
}
},
// 构建完成后输出信息
writeBundle() {
console.log('🎉 Build complete!')
},
}
}
export default vitePluginCopyright// vite-plugin-copyright.js
function vitePluginCopyright() {
return {
name: 'vite-plugin-copyright',
enforce: 'pre',
// 向 HTML 注入内容
transformIndexHtml(html) {
return html.replace('</head>', '<meta name="author" content="your-name"></head>')
},
// 转换代码
transform(code, id) {
if (id.endsWith('.js')) {
return `/* Copyright 2026 */\n${code}`
}
},
// 构建完成后输出信息
writeBundle() {
console.log('🎉 Build complete!')
},
}
}
export default vitePluginCopyright使用插件
ts
// vite.config.ts
import vitePluginCopyright from './vite-plugin-copyright'
export default defineConfig({
plugins: [
vue(),
vitePluginCopyright(),
],
})// vite.config.ts
import vitePluginCopyright from './vite-plugin-copyright'
export default defineConfig({
plugins: [
vue(),
vitePluginCopyright(),
],
})常用钩子详解
config / configResolved
ts
{
// 修改配置(在解析前)
config(config, { mode, command }) {
return {
resolve: {
alias: { '@': '/src' },
},
}
},
// 配置已被解析
configResolved(resolvedConfig) {
console.log('最终配置:', resolvedConfig)
},
}{
// 修改配置(在解析前)
config(config, { mode, command }) {
return {
resolve: {
alias: { '@': '/src' },
},
}
},
// 配置已被解析
configResolved(resolvedConfig) {
console.log('最终配置:', resolvedConfig)
},
}configureServer
ts
{
configureServer(server) {
// 添加自定义中间件
server.middlewares.use((req, res, next) => {
if (req.url === '/api/health') {
res.end('ok')
} else {
next()
}
})
// 监听请求
server.httpServer?.on('request', (req) => {
console.log('请求:', req.url)
})
},
}{
configureServer(server) {
// 添加自定义中间件
server.middlewares.use((req, res, next) => {
if (req.url === '/api/health') {
res.end('ok')
} else {
next()
}
})
// 监听请求
server.httpServer?.on('request', (req) => {
console.log('请求:', req.url)
})
},
}transformIndexHtml
ts
{
transformIndexHtml(html) {
return [
{
tag: 'script',
attrs: { src: '/analytics.js' },
injectTo: 'head',
},
{
tag: 'meta',
attrs: { name: 'description', content: 'My App' },
},
]
},
}{
transformIndexHtml(html) {
return [
{
tag: 'script',
attrs: { src: '/analytics.js' },
injectTo: 'head',
},
{
tag: 'meta',
attrs: { name: 'description', content: 'My App' },
},
]
},
}handleHotUpdate
ts
{
handleHotUpdate(ctx) {
const { file, modules, server } = ctx
// 排除某些文件
if (file.includes('node_modules')) {
return []
}
// 自定义更新
server.ws.send({
type: 'custom',
event: 'special-update',
data: { file },
})
// 返回受影响的模块
return modules.filter(m => m.id?.includes('src'))
},
}{
handleHotUpdate(ctx) {
const { file, modules, server } = ctx
// 排除某些文件
if (file.includes('node_modules')) {
return []
}
// 自定义更新
server.ws.send({
type: 'custom',
event: 'special-update',
data: { file },
})
// 返回受影响的模块
return modules.filter(m => m.id?.includes('src'))
},
}虚拟模块
Vite 支持虚拟模块(只在内存中存在,不写入磁盘):
ts
function vitePluginVirtualModule() {
const virtualModuleId = 'virtual:config'
const resolvedVirtualModuleId = '\0' + virtualModuleId
return {
name: 'vite-plugin-virtual',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `export const config = ${JSON.stringify({ version: '1.0.0' })}`
}
},
}
}function vitePluginVirtualModule() {
const virtualModuleId = 'virtual:config'
const resolvedVirtualModuleId = '\0' + virtualModuleId
return {
name: 'vite-plugin-virtual',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `export const config = ${JSON.stringify({ version: '1.0.0' })}`
}
},
}
}使用:
ts
import { config } from 'virtual:config'
console.log(config.version) // 1.0.0import { config } from 'virtual:config'
console.log(config.version) // 1.0.0插件执行顺序
ts
{
// pre: 先于框架插件执行
enforce: 'pre',
// 默认: 框架插件
// post: 后于框架插件执行
enforce: 'post',
}{
// pre: 先于框架插件执行
enforce: 'pre',
// 默认: 框架插件
// post: 后于框架插件执行
enforce: 'post',
}执行顺序:pre → 默认 → post → 构建工具内置
常用插件
| 插件 | 用途 |
|---|---|
@vitejs/plugin-vue | Vue 3 SFC 支持 |
@vitejs/plugin-react | React Fast Refresh 支持 |
@vitejs/plugin-legacy | 传统浏览器兼容 |
vite-plugin-svg-icons | SVG 图标 |
vite-plugin-compression | Gzip/Brotli 压缩 |
vite-plugin-mock | Mock 数据 |
vite-plugin-vue-devtools | Vue DevTools |
vite-plugin-pwa | PWA 支持 |
unplugin-auto-import | 自动导入 API |
unplugin-vue-components | 自动导入组件 |
插件发布规范
- 命名:
vite-plugin-<name> package.json添加"vite-plugin"关键词- 导出工厂函数而非对象
json
{
"name": "vite-plugin-copyright",
"keywords": ["vite-plugin"],
"main": "index.js"
}{
"name": "vite-plugin-copyright",
"keywords": ["vite-plugin"],
"main": "index.js"
}
Cao Note