# Vite Plugin API: Extend Vite Build Tool

# Vite Plugin API: Extend Vite Build Tool

## Overview

The Vite Plugin API allows developers to extend Vite's build capabilities by hooking into its core processes. Vite plugins are based on Rollup's plugin interface with Vite-specific extensions.

## Core Concepts

### Plugin Structure

```javascript
export default function myPlugin(options = {}) {
  return {
    name: 'my-plugin', // required, used for warnings and errors
    apply: 'build', // 'build' | 'serve' | function
    enforce: 'pre', // 'pre' | 'post'
    
    // Vite-specific hooks
    config(config, env) {},
    configResolved(resolvedConfig) {},
    configureServer(server) {},
    transformIndexHtml(html) {},
    handleHotUpdate(ctx) {},
    
    // Rollup hooks
    resolveId(id) {},
    load(id) {},
    transform(code, id) {},
  }
}
```

## Key Hooks

### Universal Hooks

| Hook | Purpose | Timing |
|------|---------|--------|
| `config` | Modify Vite config | Before resolution |
| `configResolved` | Store final config | After resolution |
| `apply` | Conditional plugin application | Plugin initialization |
| `enforce` | Hook execution order | Plugin initialization |

### Vite-Specific Hooks

#### `configureServer(server)`
Customize dev server:
```javascript
configureServer(server) {
  return () => {
    server.middlewares.use('/custom', (req, res) => {
      res.end('Custom response')
    })
  }
}
```

#### `transformIndexHtml(html)`
Transform `index.html`:
```javascript
transformIndexHtml(html) {
  return html.replace(
    /<title>(.*?)<\/title>/,
    `<title>Modified: $1</title>`
  )
}
```

#### `handleHotUpdate(ctx)`
Handle HMR updates:
```javascript
handleHotUpdate(ctx) {
  if (ctx.file.endsWith('.custom')) {
    console.log(`${ctx.file} changed, full reload`)
    ctx.server.ws.send({
      type: 'full',
      event: 'special',
      event_payload: {},
    })
    return []
  }
}
```

### Rollup Hooks

#### `resolveId(id)`
Custom module resolution:
```javascript
resolveId(id) {
  if (id === 'virtual-module') {
    return id
  }
}
```

#### `load(id)`
Custom module loading:
```javascript
load(id) {
  if (id === 'virtual-module') {
    return 'export default "virtual content"'
  }
}
```

#### `transform(code, id)`
Transform module code:
```javascript
transform(code, id) {
  if (id.endsWith('.custom')) {
    return {
      code: transformedCode,
      map: null
    }
  }
}
```

## Practical Examples

### Virtual Module Plugin

```javascript
export default function virtualModulePlugin() {
  const virtualModuleId = 'virtual-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"`
      }
    }
  }
}
```

### Framework Integration Plugin

```javascript
export default function frameworkPlugin() {
  return {
    name: 'framework-plugin',
    
    resolveId(id) {
      if (id.endsWith('.framework')) {
        return id
      }
    },
    
    load(id) {
      if (id.endsWith('.framework')) {
        const content = fs.readFileSync(id, 'utf-8')
        return compileFramework(content)
      }
    },
    
    transform(code, id) {
      if (id.endsWith('.framework')) {
        return {
          code: optimizeCode(code),
          map: null
        }
      }
    }
  }
}
```

### Environment-Specific Plugin

```javascript
export default function envPlugin() {
  let config

  return {
    name: 'env-plugin',
    apply: 'build',
    enforce: 'pre',
    
    configResolved(resolvedConfig) {
      config = resolvedConfig
    },
    
    transform(code, id) {
      if (config.command === 'build') {
        return code.replace(
          /process\.env\.NODE_ENV/g,
          JSON.stringify(config.env.NODE_ENV)
        )
      }
    }
  }
}
```

## Advanced Patterns

### Conditional Plugin Application

```javascript
apply: 'build', // only during build
apply: 'serve', // only during dev
apply: (config, env) => env.command === 'build' && config.build.ssr
```

### Plugin Ordering

```javascript
{
  enforce: 'pre',  // runs before core plugins
  // ... plugin code
}

{
  enforce: 'post', // runs after core plugins
  // ... plugin code
}
```

### Accessing Resolved Config

```javascript
configResolved(resolvedConfig) {
  this.config = resolvedConfig
}
```

## Best Practices

1. **Use `\0` prefix** for virtual modules to avoid conflicts
2. **Store config** in `configResolved` hook for later use
3. **Return null** from hooks when not applicable
4. **Use `apply`** to limit plugin scope
5. **Document hook order** with `enforce`
6. **Handle both dev and build** modes appropriately
7. **Provide source maps** for better debugging

## Common Use Cases

- Custom file format compilation
- Virtual modules
- Framework integration
- Build optimization
- Development server customization
- Asset processing
- Code generation
- Environment variable injection

The Vite Plugin API provides powerful extensibility while maintaining simplicity and performance.
