返回 Skills
antfu/skills· MIT 内容可用

vite

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.

安装

与 skills.sh 相同的 Command / Prompt 安装方式


name: vite description: 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. metadata: author: Anthony Fu version: "2026.1.31" source: Generated from https://github.com/vitejs/vite, scripts at https://github.com/antfu/skills

Vite

Based on Vite 8 beta (Rolldown-powered). Vite 8 uses Rolldown bundler and Oxc transformer.

Vite is a next-generation frontend build tool with fast dev server (native ESM + HMR) and optimized production builds.

Preferences

  • Use TypeScript: prefer vite.config.ts
  • Always use ESM, avoid CommonJS

Core

TopicDescriptionReference
Configurationvite.config.ts, defineConfig, conditional configs, loadEnvcore-config
Featuresimport.meta.glob, asset queries (?raw, ?url), import.meta.env, HMR APIcore-features
Plugin APIVite-specific hooks, virtual modules, plugin orderingcore-plugin-api

Build & SSR

TopicDescriptionReference
Build & SSRLibrary mode, SSR middleware mode, ssrLoadModule, JavaScript APIbuild-and-ssr

Advanced

TopicDescriptionReference
Environment APIVite 6+ multi-environment support, custom runtimesenvironment-api
Rolldown MigrationVite 8 changes: Rolldown bundler, Oxc transformer, config migrationrolldown-migration

Quick Reference

CLI Commands

vite              # Start dev server
vite build        # Production build
vite preview      # Preview production build
vite build --ssr  # SSR build

Common Config

import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [],
  resolve: { alias: { '@': '/src' } },
  server: { port: 3000, proxy: { '/api': 'http://localhost:8080' } },
  build: { target: 'esnext', outDir: 'dist' },
})

Official Plugins

  • @vitejs/plugin-vue - Vue 3 SFC support
  • @vitejs/plugin-vue-jsx - Vue 3 JSX
  • @vitejs/plugin-react - React with Oxc/Babel
  • @vitejs/plugin-react-swc - React with SWC
  • @vitejs/plugin-legacy - Legacy browser support

附带文件

GENERATION.md
# Generation Info

- **Source:** `sources/vite`
- **Git SHA:** `c47015eba4f0de255218c35769628d87152216ca`
- **Generated:** 2026-01-31
references/build-and-ssr.md
---
name: vite-build-ssr
description: Vite library mode, multi-page apps, JavaScript API, and SSR guidance
---

# Build and SSR

## Library Mode

Build a library for distribution:

```ts
// vite.config.ts
import { resolve } from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: resolve(import.meta.dirname, 'lib/main.ts'),
      name: 'MyLib',
      fileName: 'my-lib',
    },
    rolldownOptions: {
      external: ['vue', 'react'],
      output: {
        globals: {
          vue: 'Vue',
          react: 'React',
        },
      },
    },
  },
})
```

### Multiple Entries

```ts
build: {
  lib: {
    entry: {
      'my-lib': resolve(import.meta.dirname, 'lib/main.ts'),
      secondary: resolve(import.meta.dirname, 'lib/secondary.ts'),
    },
    name: 'MyLib',
  },
}
```

### Output Formats

- Single entry: `es` and `umd`
- Multiple entries: `es` and `cjs`

### Package.json Setup

```json
{
  "name": "my-lib",
  "type": "module",
  "files": ["dist"],
  "main": "./dist/my-lib.umd.cjs",
  "module": "./dist/my-lib.js",
  "exports": {
    ".": {
      "import": "./dist/my-lib.js",
      "require": "./dist/my-lib.umd.cjs"
    },
    "./style.css": "./dist/my-lib.css"
  }
}
```

## Multi-Page App

```ts
export default defineConfig({
  build: {
    rolldownOptions: {
      input: {
        main: resolve(import.meta.dirname, 'index.html'),
        nested: resolve(import.meta.dirname, 'nested/index.html'),
      },
    },
  },
})
```

## SSR Development

**Note:** Vite's SSR support is **low-level** and designed mostly for meta-framework authors, not application developers. If you need SSR for your app, use a Vite-based meta-framework instead:

- **Nuxt** (Vue) - https://nuxt.com
- **SvelteKit** (Svelte) - https://svelte.dev/docs/kit
- **SolidStart** (Solid) - https://start.solidjs.com
- **TanStack Start** (React) - https://tanstack.com/start

These frameworks build on top of Vite's SSR primitives so you don't have to wire them up yourself.

**Need a server?** Consider [Nitro](https://nitro.build) -- think of it as "Vite for servers." Nitro provides a portable, framework-agnostic server layer with file-based API routing, auto-imports, and deployment presets for dozens of platforms (Node.js, Deno, Bun, Cloudflare Workers, Vercel, Netlify, etc.). It integrates naturally with Vite and is what powers Nuxt's server engine. See the [Nitro docs](https://nitro.build) for more details.

## JavaScript API

### createServer

```ts
import { createServer } from 'vite'

const server = await createServer({
  configFile: false,
  root: import.meta.dirname,
  server: { port: 1337 },
})

await server.listen()
server.printUrls()
```

### build

```ts
import { build } from 'vite'

await build({
  root: './project',
  build: { outDir: 'dist' },
})
```

### preview

```ts
import { preview } from 'vite'

const previewServer = await preview({
  preview: { port: 8080, open: true },
})
previewServer.printUrls()
```

### resolveConfig

```ts
import { resolveConfig } from 'vite'

const config = await resolveConfig({}, 'build')
```

### loadEnv

```ts
import { loadEnv } from 'vite'

const env = loadEnv('development', process.cwd(), '')
// Loads all env vars (empty prefix = no filtering)
```

<!--
Source references:
- https://vite.dev/guide/build
- https://vite.dev/guide/api-javascript
- https://nitro.build
-->
references/core-config.md
---
name: vite-config
description: Vite configuration patterns using vite.config.ts
---

# Vite Configuration

## Basic Setup

```ts
// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  // config options
})
```

Vite auto-resolves `vite.config.ts` from project root. Supports ES modules syntax regardless of `package.json` type.

## Conditional Config

Export a function to access command and mode:

```ts
export default defineConfig(({ command, mode, isSsrBuild, isPreview }) => {
  if (command === 'serve') {
    return { /* dev config */ }
  } else {
    return { /* build config */ }
  }
})
```

- `command`: `'serve'` during dev, `'build'` for production
- `mode`: `'development'` or `'production'` (or custom via `--mode`)

## Async Config

```ts
export default defineConfig(async ({ command, mode }) => {
  const data = await fetchSomething()
  return { /* config */ }
})
```

## Using Environment Variables in Config

`.env` files are loaded **after** config resolution. Use `loadEnv` to access them in config:

```ts
import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ mode }) => {
  // Load env files from cwd, include all vars (empty prefix)
  const env = loadEnv(mode, process.cwd(), '')
  
  return {
    define: {
      __APP_ENV__: JSON.stringify(env.APP_ENV),
    },
    server: {
      port: env.APP_PORT ? Number(env.APP_PORT) : 5173,
    },
  }
})
```

## Key Config Options

### resolve.alias

```ts
export default defineConfig({
  resolve: {
    alias: {
      '@': '/src',
      '~': '/src',
    },
  },
})
```

### define (Global Constants)

```ts
export default defineConfig({
  define: {
    __APP_VERSION__: JSON.stringify('1.0.0'),
    __API_URL__: 'window.__backend_api_url',
  },
})
```

Values must be JSON-serializable or single identifiers. Non-strings auto-wrapped with `JSON.stringify`.

### plugins

```ts
import vue from '@vitejs/plugin-vue'

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

Plugins array is flattened; falsy values ignored.

### server.proxy

```ts
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
})
```

### build.target

Default: Baseline Widely Available browsers. Customize:

```ts
export default defineConfig({
  build: {
    target: 'esnext', // or 'es2020', ['chrome90', 'firefox88']
  },
})
```

## TypeScript Intellisense

For plain JS config files:

```js
/** @type {import('vite').UserConfig} */
export default {
  // ...
}
```

Or use `satisfies`:

```ts
import type { UserConfig } from 'vite'

export default {
  // ...
} satisfies UserConfig
```

<!--
Source references:
- https://vite.dev/config/
- https://vite.dev/guide/
-->
references/core-features.md
---
name: vite-features
description: Vite-specific import patterns and runtime features
---

# Vite Features

## Glob Import

Import multiple modules matching a pattern:

```ts
const modules = import.meta.glob('./dir/*.ts')
// { './dir/foo.ts': () => import('./dir/foo.ts'), ... }

for (const path in modules) {
  modules[path]().then((mod) => {
    console.log(path, mod)
  })
}
```

### Eager Loading

```ts
const modules = import.meta.glob('./dir/*.ts', { eager: true })
// Modules loaded immediately, no dynamic import
```

### Named Imports

```ts
const modules = import.meta.glob('./dir/*.ts', { import: 'setup' })
// Only imports the 'setup' export from each module

const defaults = import.meta.glob('./dir/*.ts', { import: 'default', eager: true })
```

### Multiple Patterns

```ts
const modules = import.meta.glob(['./dir/*.ts', './another/*.ts'])
```

### Negative Patterns

```ts
const modules = import.meta.glob(['./dir/*.ts', '!**/ignored.ts'])
```

### Custom Queries

```ts
const svgRaw = import.meta.glob('./icons/*.svg', { query: '?raw', import: 'default' })
const svgUrls = import.meta.glob('./icons/*.svg', { query: '?url', import: 'default' })
```

## Asset Import Queries

### URL Import

```ts
import imgUrl from './img.png'
// Returns resolved URL: '/src/img.png' (dev) or '/assets/img.2d8efhg.png' (build)
```

### Explicit URL

```ts
import workletUrl from './worklet.js?url'
```

### Raw String

```ts
import shaderCode from './shader.glsl?raw'
```

### Inline/No-Inline

```ts
import inlined from './small.png?inline'    // Force base64 inline
import notInlined from './large.png?no-inline'  // Force separate file
```

### Web Workers

```ts
import Worker from './worker.ts?worker'
const worker = new Worker()

// Or inline:
import InlineWorker from './worker.ts?worker&inline'
```

Preferred pattern using constructor:

```ts
const worker = new Worker(new URL('./worker.ts', import.meta.url), {
  type: 'module',
})
```

## Environment Variables

### Built-in Constants

```ts
import.meta.env.MODE      // 'development' | 'production' | custom
import.meta.env.BASE_URL  // Base URL from config
import.meta.env.PROD      // true in production
import.meta.env.DEV       // true in development
import.meta.env.SSR       // true when running in server
```

### Custom Variables

Only `VITE_` prefixed vars exposed to client:

```
# .env
VITE_API_URL=https://api.example.com
DB_PASSWORD=secret  # NOT exposed to client
```

```ts
console.log(import.meta.env.VITE_API_URL) // works
console.log(import.meta.env.DB_PASSWORD)  // undefined
```

### Mode-specific Files

```
.env                # always loaded
.env.local          # always loaded, gitignored
.env.[mode]         # only in specified mode
.env.[mode].local   # only in specified mode, gitignored
```

### TypeScript Support

```ts
// vite-env.d.ts
interface ImportMetaEnv {
  readonly VITE_API_URL: string
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}
```

### HTML Replacement

```html
<p>Running in %MODE%</p>
<script>window.API = "%VITE_API_URL%"</script>
```

## CSS Modules

Any `.module.css` file treated as CSS module:

```ts
import styles from './component.module.css'
element.className = styles.button
```

With camelCase conversion:

```ts
// .my-class -> myClass (if css.modules.localsConvention configured)
import { myClass } from './component.module.css'
```

## JSON Import

```ts
import pkg from './package.json'
import { version } from './package.json'  // Named import with tree-shaking
```

## HMR API

```ts
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    // Handle update
  })
  
  import.meta.hot.dispose((data) => {
    // Cleanup before module is replaced
  })
  
  import.meta.hot.invalidate()  // Force full reload
}
```

<!--
Source references:
- https://vite.dev/guide/features
- https://vite.dev/guide/env-and-mode
- https://vite.dev/guide/assets
- https://vite.dev/guide/api-hmr
-->
references/core-plugin-api.md
---
name: vite-plugin-api
description: Vite plugin authoring with Vite-specific hooks
---

# Vite Plugin API

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

## Basic Structure

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

## Vite-Specific Hooks

### config

Modify config before resolution:

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

### configResolved

Access final resolved config:

```ts
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:

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

Return function to run **after** internal middlewares:

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

### transformIndexHtml

Transform HTML entry files:

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

Inject tags:

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

### handleHotUpdate

Custom HMR handling:

```ts
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:

```ts
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:

```ts
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:

```ts
{
  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

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

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

## Universal Hooks (from Rolldown)

These work in both dev and build:

- `resolveId(id, importer)` - Resolve import paths
- `load(id)` - Load module content
- `transform(code, id)` - Transform module code

```ts
transform(code, id) {
  if (id.endsWith('.custom')) {
    return { code: compile(code), map: null }
  }
}
```

## Client-Server Communication

Server to client:

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

Client side:

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

Client to server:

```ts
// 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
-->
references/environment-api.md
---
name: vite-environment-api
description: Vite 6+ Environment API for multiple runtime environments
---

# Environment API (Vite 6+)

The Environment API formalizes multiple runtime environments beyond the traditional client/SSR split.

## Concept

Before Vite 6: Two implicit environments (`client` and `ssr`).

Vite 6+: Configure as many environments as needed (browser, node server, edge server, etc.).

## Basic Configuration

For SPA/MPA, nothing changes—options apply to the implicit `client` environment:

```ts
export default defineConfig({
  build: { sourcemap: false },
  optimizeDeps: { include: ['lib'] },
})
```

## Multiple Environments

```ts
export default defineConfig({
  build: { sourcemap: false },  // Inherited by all environments
  optimizeDeps: { include: ['lib'] },  // Client only
  environments: {
    // SSR environment
    server: {},
    // Edge runtime environment
    edge: {
      resolve: { noExternal: true },
    },
  },
})
```

Environments inherit top-level config. Some options (like `optimizeDeps`) only apply to `client` by default.

## Environment Options

```ts
interface EnvironmentOptions {
  define?: Record<string, any>
  resolve?: EnvironmentResolveOptions
  optimizeDeps: DepOptimizationOptions
  consumer?: 'client' | 'server'
  dev: DevOptions
  build: BuildOptions
}
```

## Custom Environment Instances

Runtime providers can define custom environments:

```ts
import { customEnvironment } from 'vite-environment-provider'

export default defineConfig({
  environments: {
    ssr: customEnvironment({
      build: { outDir: '/dist/ssr' },
    }),
  },
})
```

Example: Cloudflare's Vite plugin runs code in `workerd` runtime during development.

## Backward Compatibility

- `server.moduleGraph` returns mixed client/SSR view
- `ssrLoadModule` still works
- Existing SSR apps work unchanged

## When to Use

- **End users**: Usually don't need to configure—frameworks handle it
- **Plugin authors**: Use for environment-aware transformations
- **Framework authors**: Create custom environments for their runtime needs

## Plugin Environment Access

Plugins can access environment in hooks:

```ts
{
  name: 'env-aware',
  transform(code, id, options) {
    if (options?.ssr) {
      // SSR-specific transform
    }
  },
}
```

<!--
Source references:
- https://vite.dev/guide/api-environment
- https://vite.dev/blog/announcing-vite6
-->
references/rolldown-migration.md
---
name: vite-rolldown
description: Vite 8 Rolldown bundler and Oxc transformer migration
---

# Rolldown Migration (Vite 8)

Vite 8 replaces esbuild+Rollup with Rolldown, a unified Rust-based bundler.

## What Changed

| Before (Vite 7) | After (Vite 8) |
|-----------------|----------------|
| esbuild (dev transform) | Oxc Transformer |
| esbuild (dep pre-bundling) | Rolldown |
| Rollup (production build) | Rolldown |
| `rollupOptions` | `rolldownOptions` |
| `esbuild` option | `oxc` option |

## Performance Impact

- 10-30x faster than Rollup for production builds
- Matches esbuild's dev performance
- Unified behavior between dev and build

## Config Migration

### rollupOptions → rolldownOptions

```ts
// Before (Vite 7)
export default defineConfig({
  build: {
    rollupOptions: {
      external: ['vue'],
      output: { globals: { vue: 'Vue' } },
    },
  },
})

// After (Vite 8)
export default defineConfig({
  build: {
    rolldownOptions: {
      external: ['vue'],
      output: { globals: { vue: 'Vue' } },
    },
  },
})
```

### esbuild → oxc

```ts
// Before (Vite 7)
export default defineConfig({
  esbuild: {
    jsxFactory: 'h',
    jsxFragment: 'Fragment',
  },
})

// After (Vite 8)
export default defineConfig({
  oxc: {
    jsx: {
      runtime: 'classic',
      pragma: 'h',
      pragmaFrag: 'Fragment',
    },
  },
})
```

### JSX Configuration

```ts
export default defineConfig({
  oxc: {
    jsx: {
      runtime: 'automatic',  // or 'classic'
      importSource: 'react', // for automatic runtime
    },
    jsxInject: `import React from 'react'`,  // auto-inject
  },
})
```

### Custom Transform Targets

```ts
export default defineConfig({
  oxc: {
    include: ['**/*.ts', '**/*.tsx'],
    exclude: ['node_modules/**'],
  },
})
```

## Plugin Compatibility

Most Vite plugins work unchanged. Rolldown supports Rollup's plugin API.

If a plugin only works during build:

```ts
{
  ...rollupPlugin(),
  enforce: 'post',
  apply: 'build',
}
```

## New Capabilities

Rolldown unlocks features not possible before:

- Full bundle mode (experimental)
- Module-level persistent cache
- More flexible chunk splitting
- Module Federation support

## Gradual Migration

For large projects, migrate via `rolldown-vite` first:

```bash
# Step 1: Test with rolldown-vite
pnpm add -D rolldown-vite

# Replace vite import in config
import { defineConfig } from 'rolldown-vite'

# Step 2: Once stable, upgrade to Vite 8
pnpm add -D vite@8
```

## Overriding Vite in Frameworks

When framework depends on older Vite:

```json
{
  "pnpm": {
    "overrides": {
      "vite": "8.0.0"
    }
  }
}
```

<!--
Source references:
- https://vite.dev/blog/announcing-vite8-beta
- https://vite.dev/blog/announcing-vite7
- https://vite.dev/config/shared-options#oxc
-->
    vite | Prompt Minder