Skip to content
On this page

Vite 插件

Vite 的插件系统基于 Rollup 插件接口,并添加了 Vite 独有的钩子。插件是扩展 Vite 功能的主要方式,可以用于处理特定类型的文件、转换代码、注入全局变量等。

插件基础

插件结构

一个基本的 Vite 插件包含一个名称和一个或多个钩子函数:

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    // 插件钩子
    resolveId(id) {
      // ...
    },
    load(id) {
      // ...
    }
  }
}

使用插件

vite.config.js 中使用插件:

javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import myPlugin from './my-plugin'

export default defineConfig({
  plugins: [
    vue(),
    myPlugin()
  ]
})

常用官方插件

@vitejs/plugin-vue

用于支持 Vue 3 单文件组件(SFC)。

bash
npm install @vitejs/plugin-vue -D
javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()]
})

@vitejs/plugin-react

用于支持 React 和 JSX。

bash
npm install @vitejs/plugin-react -D
javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()]
})

@vitejs/plugin-legacy

用于支持旧版浏览器。

bash
npm install @vitejs/plugin-legacy -D
javascript
import { defineConfig } from 'vite'
import legacy from '@vitejs/plugin-legacy'

export default defineConfig({
  plugins: [
    legacy({
      targets: ['defaults', 'not IE 11']
    })
  ]
})

插件钩子

构建阶段钩子

options

在构建开始时调用,用于修改构建选项。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    options(options) {
      // 修改或返回新的选项
      return options
    }
  }
}

buildStart

在构建开始时调用。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    buildStart() {
      console.log('构建开始')
    }
  }
}

resolveId

用于解析模块 ID。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    resolveId(id) {
      if (id === 'virtual:my-module') {
        return id
      }
    }
  }
}

load

用于加载模块内容。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    load(id) {
      if (id === 'virtual:my-module') {
        return 'export const msg = "hello world"'
      }
    }
  }
}

transform

用于转换源代码。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    transform(code, id) {
      if (id.endsWith('.custom')) {
        // 转换自定义文件格式
        return code.replace(/%VERSION%/g, '1.0.0')
      }
    }
  }
}

buildEnd

在构建结束时调用。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    buildEnd() {
      console.log('构建结束')
    }
  }
}

输出阶段钩子

renderStart

在输出阶段开始时调用。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    renderStart() {
      console.log('开始生成输出')
    }
  }
}

为每个输出块添加头部/尾部代码。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    banner(chunk) {
      return '// 版权所有 (c) 2023'
    },
    footer(chunk) {
      return '// 构建完成'
    }
  }
}

Vite 特有钩子

config

在解析 Vite 配置前调用,可以修改配置。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    config(config, { command }) {
      if (command === 'build') {
        config.build.minify = 'terser'
      }
      return config
    }
  }
}

configResolved

在解析 Vite 配置后调用,可以读取最终配置。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    configResolved(resolvedConfig) {
      console.log('基础路径:', resolvedConfig.base)
    }
  }
}

configureServer

在开发服务器配置时调用,可以修改服务器中间件。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        // 自定义中间件逻辑
        console.log(`请求: ${req.url}`)
        next()
      })
    }
  }
}

handleHotUpdate

处理热更新。

javascript
export default function myPlugin() {
  return {
    name: 'my-plugin',
    handleHotUpdate(ctx) {
      console.log('热更新:', ctx.file)
    }
  }
}

实用插件示例

虚拟模块插件

创建一个提供虚拟模块的插件:

javascript
export default function virtualModulePlugin() {
  const virtualModuleId = 'virtual:my-config'
  const resolvedVirtualModuleId = '\0' + virtualModuleId

  return {
    name: 'virtual-module',
    resolveId(id) {
      if (id === virtualModuleId) {
        return resolvedVirtualModuleId
      }
    },
    load(id) {
      if (id === resolvedVirtualModuleId) {
        return `
          export const config = {
            apiUrl: 'https://api.example.com',
            version: '1.0.0'
          }
        `
      }
    }
  }
}

使用该插件:

javascript
// 在代码中使用
import { config } from 'virtual:my-config'

console.log(config.apiUrl) // 输出: https://api.example.com

环境变量注入插件

创建一个注入环境变量的插件:

javascript
export default function envPlugin(options = {}) {
  const { prefix = 'APP_' } = options
  
  return {
    name: 'env',
    config(config) {
      config.define = config.define || {}
      
      // 将环境变量注入到代码中
      Object.keys(process.env).forEach(key => {
        if (key.startsWith(prefix)) {
          config.define[`process.env.${key}`] = JSON.stringify(process.env[key])
        }
      })
    }
  }
}

文件监听插件

创建一个文件监听插件:

javascript
import { readFileSync } from 'fs'

export default function fileWatcherPlugin(filePath) {
  return {
    name: 'file-watcher',
    configureServer(server) {
      server.watcher.add(filePath)
      server.watcher.on('change', (file) => {
        if (file === filePath) {
          // 重新加载文件内容
          const content = readFileSync(filePath, 'utf-8')
          // 触发全页重载
          server.ws.send({
            type: 'full-reload',
            path: '*'
          })
        }
      })
    }
  }
}

社区插件

unplugin-auto-import

自动导入常用的 API。

bash
npm install unplugin-auto-import -D
javascript
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: ['vue', 'vue-router'],
      dts: true
    })
  ]
})

unplugin-vue-components

自动导入 Vue 组件。

bash
npm install unplugin-vue-components -D
javascript
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    Components({
      resolvers: [ElementPlusResolver()]
    })
  ]
})

vite-plugin-pwa

为应用添加 PWA 支持。

bash
npm install vite-plugin-pwa -D
javascript
import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
  plugins: [
    VitePWA({
      registerType: 'autoUpdate',
      manifest: {
        name: 'My App',
        short_name: 'My App',
        theme_color: '#ffffff',
        icons: [
          {
            src: 'pwa-192x192.png',
            sizes: '192x192',
            type: 'image/png'
          }
        ]
      }
    })
  ]
})

插件开发最佳实践

1. 使用插件工厂函数

始终使用工厂函数来创建插件,这样可以接受配置参数:

javascript
export default function myPlugin(options = {}) {
  return {
    name: 'my-plugin',
    // 插件实现
  }
}

2. 提供有意义的插件名称

插件名称应具有描述性且唯一,便于调试:

javascript
export default function myAwesomePlugin() {
  return {
    name: 'my-awesome-plugin', // 易于识别的名称
    // ...
  }
}

3. 合理处理错误

在插件中妥善处理错误,并提供有意义的错误信息:

javascript
export default function errorHandlingPlugin() {
  return {
    name: 'error-handler',
    transform(code, id) {
      try {
        // 转换逻辑
        return transformCode(code)
      } catch (error) {
        this.error({
          message: `转换文件 ${id} 时出错`,
          stack: error.stack
        })
      }
    }
  }
}

4. 优化性能

避免在插件中执行不必要的操作,只在必要时才处理文件:

javascript
export default function optimizedPlugin() {
  return {
    name: 'optimized-plugin',
    transform(code, id) {
      // 快速检查是否需要处理
      if (!id.endsWith('.special')) {
        return // 不处理此文件
      }
      
      // 执行转换
      return processSpecialFile(code)
    }
  }
}

通过了解和使用 Vite 插件系统,您可以根据项目需求扩展 Vite 的功能,创建更加灵活和强大的开发环境。