Files
gt-agent-company/.agents/skills/vite/references/advanced-plugin-api.md
sexygoat 3c62cc1cd1 first
2026-03-31 18:41:52 +08:00

4.1 KiB

name, description
name description
advanced-plugin-api Creating Vite plugins, hooks, virtual modules, and client-server communication

Plugin API

Vite plugins extend Rolldown's plugin interface with Vite-specific hooks.

Basic Plugin Structure

export default function myPlugin(options = {}) {
  return {
    name: 'vite-plugin-my-plugin',
    
    // Hooks...
  }
}

Naming Conventions

  • Vite-only plugins: vite-plugin-*
  • Rollup-compatible: rollup-plugin-*
  • Framework-specific: vite-plugin-vue-*, vite-plugin-react-*

Universal Hooks (from Rolldown)

Called on server start:

  • options - Modify Rolldown options
  • buildStart - Build starting

Called per module request:

  • resolveId - Resolve import paths
  • load - Load module content
  • transform - Transform module code

Called on server close:

  • buildEnd
  • closeBundle

Vite-Specific Hooks

config

Modify config before resolution:

{
  name: 'modify-config',
  config(config, { command, mode }) {
    if (command === 'build') {
      return {
        resolve: {
          alias: { foo: 'bar' }
        }
      }
    }
  }
}

configResolved

Access final resolved config:

{
  name: 'read-config',
  configResolved(config) {
    this.config = config
  }
}

configureServer

Add dev server middleware:

{
  name: 'configure-server',
  configureServer(server) {
    // Before Vite's middlewares
    server.middlewares.use((req, res, next) => {
      // Handle request
      next()
    })
    
    // Return function to run after Vite's middlewares
    return () => {
      server.middlewares.use((req, res, next) => {
        // Post middleware
      })
    }
  }
}

transformIndexHtml

Transform HTML files:

{
  name: 'html-transform',
  transformIndexHtml(html) {
    return html.replace(/<title>(.*?)<\/title>/, '<title>New Title</title>')
  }
}

Inject tags:

{
  name: 'html-inject',
  transformIndexHtml() {
    return {
      tags: [
        {
          tag: 'script',
          attrs: { src: '/inject.js' },
          injectTo: 'body'  // 'head' | 'body' | 'head-prepend' | 'body-prepend'
        }
      ]
    }
  }
}

handleHotUpdate

Custom HMR handling:

{
  name: 'custom-hmr',
  handleHotUpdate({ file, server, modules }) {
    if (file.endsWith('.custom')) {
      server.ws.send({
        type: 'custom',
        event: 'custom-update',
        data: { file }
      })
      return []  // Prevent default HMR
    }
  }
}

Virtual Modules

Provide build-time information to source code:

export default function myPlugin() {
  const virtualModuleId = 'virtual:my-module'
  const resolvedId = '\0' + virtualModuleId

  return {
    name: 'virtual-module',
    
    resolveId(id) {
      if (id === virtualModuleId) {
        return resolvedId
      }
    },
    
    load(id) {
      if (id === resolvedId) {
        return `export const msg = "from virtual module"`
      }
    }
  }
}

Usage:

import { msg } from 'virtual:my-module'

Client-Server Communication

Server to Client

{
  configureServer(server) {
    server.ws.on('connection', () => {
      server.ws.send('my:greetings', { msg: 'hello' })
    })
  }
}

Client receives:

if (import.meta.hot) {
  import.meta.hot.on('my:greetings', (data) => {
    console.log(data.msg)
  })
}

Client to Server

// Client
if (import.meta.hot) {
  import.meta.hot.send('my:from-client', { msg: 'Hey!' })
}

// Server (in plugin)
{
  configureServer(server) {
    server.ws.on('my:from-client', (data, client) => {
      console.log(data.msg)
      client.send('my:reply', { msg: 'Got it!' })
    })
  }
}

Transform with Filtering

{
  name: 'transform-js',
  transform: {
    filter: {
      id: /\.js$/  // Only .js files
    },
    handler(code, id) {
      return transformCode(code)
    }
  }
}

Path Normalization

Use POSIX separators for cross-platform compatibility:

import { normalizePath } from 'vite'

normalizePath('foo\\bar')  // 'foo/bar'