Skip to content

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.0
import { 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-vueVue 3 SFC 支持
@vitejs/plugin-reactReact Fast Refresh 支持
@vitejs/plugin-legacy传统浏览器兼容
vite-plugin-svg-iconsSVG 图标
vite-plugin-compressionGzip/Brotli 压缩
vite-plugin-mockMock 数据
vite-plugin-vue-devtoolsVue DevTools
vite-plugin-pwaPWA 支持
unplugin-auto-import自动导入 API
unplugin-vue-components自动导入组件

插件发布规范 ​

  1. 命名:vite-plugin-<name>
  2. package.json 添加 "vite-plugin" 关键词
  3. 导出工厂函数而非对象
json
{
  "name": "vite-plugin-copyright",
  "keywords": ["vite-plugin"],
  "main": "index.js"
}
{
  "name": "vite-plugin-copyright",
  "keywords": ["vite-plugin"],
  "main": "index.js"
}