All skills
antfu avatar

/vite

@d02c484 official
by Anthony Fuantfu/skills5.9k stars
335

Vite build tool configuration, plugin API, SSR, and Vite 8 Rolldown migration. Use when working with Vite projects, vite.config.ts, Vite plugins, or building libraries/SSR apps with Vite.

Use this Skill: https://skilld.dev/gh/antfu/skills/vite

This session only. Nothing lands on disk.

referencescore-plugin-api.md

≈1.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Vite Plugin API

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

Basic Structure

function myPlugin(): Plugin {
  return {
    name: 'my-plugin',
    // hooks...
  }
}

Vite-Specific Hooks

config

Modify config before resolution:

const plugin = () => ({
  name: 'add-alias',
  config: () => ({
    resolve: {
      alias: { foo: 'bar' },
    },
  }),
})

configResolved

Access final resolved config:

const plugin = () => {
  let config: ResolvedConfig
  return {
    name: 'read-config',
    configResolved(resolvedConfig) {
      config = resolvedConfig
    },
    transform(code, id) {
      if (config.command === 'serve') { /* dev */ }
    },
  }
}

configureServer

Add custom middleware to dev server:

const plugin = () => ({
  name: 'custom-middleware',
  configureServer(server) {
    server.middlewares.use((req, res, next) => {
      // handle request
      next()
    })
  },
})

Return function to run after internal middlewares:

configureServer(server) {
  return () => {
    server.middlewares.use((req, res, next) => {
      // runs after Vite's middlewares
    })
  }
}

transformIndexHtml

Transform HTML entry files:

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

Inject tags:

transformIndexHtml() {
  return [
    { tag: 'script', attrs: { src: '/inject.js' }, injectTo: 'body' },
  ]
}

handleHotUpdate

Custom HMR handling:

handleHotUpdate({ server, modules, timestamp }) {
  server.ws.send({ type: 'custom', event: 'special-update', data: {} })
  return [] // empty = skip default HMR
}

Virtual Modules

Serve virtual content without files on disk:

const plugin = () => {
  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'

Convention: prefix user-facing path with virtual:, prefix resolved id with \0.

Plugin Ordering

Use enforce to control execution order:

{
  name: 'pre-plugin',
  enforce: 'pre',  // runs before core plugins
}

{
  name: 'post-plugin',
  enforce: 'post', // runs after build plugins
}

Order: Alias → enforce: 'pre' → Core → User (no enforce) → Build → enforce: 'post' → Post-build

Conditional Application

{
  name: 'build-only',
  apply: 'build',  // or 'serve'
}

// Function form:
{
  apply(config, { command }) {
    return command === 'build' && !config.build.ssr
  }
}

Rolldown Hooks (dev + build)

These come from Rolldown and are per-environment (this.environment available):

  • resolveId(id, importer) - Resolve import paths
  • load(id) - Load module content
  • transform(code, id) - Transform module code
transform(code, id) {
  if (id.endsWith('.custom')) {
    return { code: compile(code), map: null }
  }
}

Hook Filters (Vite 8)

Prefer the object form with filter + handler for transform/resolveId/load — filtering runs in Rust, avoiding a JS call per module:

import { exactRegex } from '@rolldown/pluginutils' // also from 'rolldown/filter'

const plugin = () => ({
  name: 'transform-file',
  transform: {
    filter: { id: /\.custom$/ },
    handler(code, id) {
      return { code: compile(code), map: null }
    },
  },
})

@rolldown/pluginutils exports helpers like exactRegex and prefixRegex.

Per-Environment vs Global Hooks (Vite 8)

  • Global (called once, no this.environment): config, configResolved, configureServer, configurePreviewServer, closeServer, closePreviewServer, buildApp.
  • Per-environment (called per environment, expose this.environment): all Rolldown hooks, transformIndexHtml, handleHotUpdate/hotUpdate, configEnvironment, applyToEnvironment.

Cleanup Hooks (Vite 8)

closeServer({ reason }) runs after the dev server is torn down (reason is 'restart' or 'close'); closePreviewServer() is the preview equivalent. Use to dispose resources created in configureServer.

{
  name: 'close-server',
  configureServer(server) { this.resource = createResource() },
  async closeServer({ reason }) {
    if (reason === 'close') await this.resource.dispose()
  },
}

Plugin Context Meta (Vite 8)

  • this.meta.viteVersion — current Vite version string.
  • this.meta.rolldownVersion — only defined on Rolldown-powered Vite (8+); use it to branch behavior.

Output Bundle Metadata

During build, Vite augments Rolldown output objects with viteMetadata — inspect emitted CSS/assets without build.manifest:

{
  name: 'output-metadata',
  enforce: 'post',
  generateBundle(_, bundle) {
    for (const output of Object.values(bundle)) {
      const css = output.viteMetadata?.importedCss       // Set<string>
      const assets = output.viteMetadata?.importedAssets  // Set<string>
    }
  },
}

Referencing Emitted Assets

this.emitFile({ type: 'asset', ... }) returns a referenceId; resolve its final URL later:

  • In JS: import.meta.ROLLDOWN_FILE_URL_<referenceId>
  • In CSS/HTML: __VITE_ASSET__<referenceId>__

Client-Server Communication

Server to client:

configureServer(server) {
  server.ws.send('my:event', { msg: 'hello' })
}

Client side:

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

Client to server:

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

// Server
server.ws.on('my:from-client', (data, client) => {
  client.send('my:ack', { msg: 'Got it!' })
})
<!-- Source references: - https://vite.dev/guide/api-plugin -->

Source: SKILL.md on GitHub

No alerts3d5 checks · Risk SAFE
  • Gen Agent Trust Hub3d

    This skill provides comprehensive documentation and reference material for the Vite build tool, including Vite 8 migration guidance, plugin API details, and server-side rendering configurations. No security issues were detected.

  • Socket3d

    No alerts

  • Snyk3d

    Risk: LOW · No issues

  • Runlayer6mo

    1/8 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at d02c484. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 4 days ago
Other metadata
metadata
{
  "author": "Anthony Fu",
  "version": "2026.9.25",
  "source": "Generated from https://github.com/vitejs/vite, scripts at https://github.com/antfu/skills"
}

README badge

README badge for antfu/skills/vite

Vite is a next-generation frontend build tool with a fast dev server using native ESM and HMR, optimized production builds, and Vite 8 support for Rolldown-powered bundling. Use this skill when configuring vite.config.ts, developing Vite plugins, or building libraries and SSR applications.

Generated from the current SKILL.md.

Does this skill cover Vite 8 and Rolldown?
Yes. The skill is based on Vite 8 beta and includes migration guidance for Rolldown bundler and Oxc transformer changes.
What does this skill help with?
Configuration (vite.config.ts), plugin API, asset imports, SSR setup, library mode, and Vite 8 migration patterns.
Does this cover framework-specific setups like React or Vue?
The skill documents official plugins like @vitejs/plugin-react and @vitejs/plugin-vue, but focuses on core Vite configuration and APIs, not framework-specific best practices.
Is CommonJS supported?
No. The skill prefers ESM and encourages avoiding CommonJS in Vite projects.

Generated from the current SKILL.md. These answers refresh after source changes.