# Vite User Guide

**Vite v8.0.8** — Next-generation frontend build tool powered by native ES modules. Created by Evan You, Vite delivers lightning-fast dev server startup, instant Hot Module Replacement, and optimized production builds via Rolldown.

This guide covers everything you need to install, configure, and use Vite effectively across all supported frameworks and environments.

---

## 1. Quick Start

### Create a New Project

The fastest way to start is with `create-vite`, Vite's official scaffolding tool:

```bash
npm create vite@latest my-app
```

This launches an interactive prompt to select a framework and variant. To skip the prompts, pass a template directly:

```bash
npm create vite@latest my-app -- --template react-ts
```

Expected output:

```
Scaffolding project in /path/to/my-app...

Done. Now run:

  cd my-app
  npm install
  npm run dev
```

### Start Development

```bash
cd my-app
npm install
npm run dev
```

Expected output:

```
  VITE v8.0.8  ready in 237 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help
```

Open `http://localhost:5173/` in your browser. Edit any source file and watch changes appear instantly.

### Build for Production

```bash
npm run build
```

Expected output:

```
vite v8.0.8 building for production...
✓ 42 modules transformed.
dist/index.html                  0.46 kB │ gzip:  0.30 kB
dist/assets/index-BfH3kQ2f.css   1.42 kB │ gzip:  0.74 kB
dist/assets/index-DiwrgTda.js  143.36 kB │ gzip: 46.10 kB
✓ built in 1.23s
```

### Preview the Build

```bash
npm run preview
```

Expected output:

```
  ➜  Local:   http://localhost:4173/
  ➜  Network: use --host to expose
```

> [!TIP]
> The `create-vite` CLI is also available as `cva`. Both binary names work identically: `npx cva my-app --template vue-ts`.

---

## 2. Installation

### System Requirements

| Requirement | Version |
|---|---|
| Node.js | `^20.19.0` or `>=22.12.0` |
| Package manager | npm, yarn, pnpm, or bun |
| OS | Windows, macOS, Linux |

> [!IMPORTANT]
> Vite v8 requires Node.js 20.19.0+ or 22.12.0+. Older Node.js versions (16, 18, odd-numbered) are not supported. Check your version with `node --version`.

### Install via Package Manager

#### npm

```bash
npm create vite@latest my-project
cd my-project
npm install
```

#### yarn

```bash
yarn create vite my-project
cd my-project
yarn
```

#### pnpm

```bash
pnpm create vite my-project
cd my-project
pnpm install
```

#### bun

```bash
bun create vite my-project
cd my-project
bun install
```

### Add Vite to an Existing Project

Install Vite as a dev dependency:

```bash
npm install -D vite
```

Create a minimal `index.html` at the project root:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>
```

Add scripts to `package.json`:

```json
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}
```

### Scaffolding Templates

`create-vite` ships with templates for every major framework:

| Framework | Templates |
|---|---|
| Vanilla | `vanilla`, `vanilla-ts` |
| Vue | `vue`, `vue-ts` |
| React | `react`, `react-ts`, `react-compiler`, `react-compiler-ts` |
| Preact | `preact`, `preact-ts` |
| Lit | `lit`, `lit-ts` |
| Svelte | `svelte`, `svelte-ts` |
| Solid | `solid`, `solid-ts` |
| Qwik | `qwik`, `qwik-ts` |
| Ember | `ember` (TypeScript/JavaScript via ember-cli) |
| Angular | `angular` |
| Marko | `marko` (via marko run) |

Community-maintained variants are also available during interactive scaffolding:

| Framework | Community variants |
|---|---|
| Vue | custom-create-vue, Nuxt, Vike |
| React | RSC, React Router, TanStack Router, RedwoodSDK, Vike |
| Svelte | SvelteKit |
| Solid | TanStack Router, Vike |
| Qwik | Qwik City |
| Angular | Analog |

### create-vite CLI Options

| Option | Description |
|---|---|
| `-t, --template NAME` | Use a specific template (skip framework prompt) |
| `-i, --immediate` | Install dependencies and start dev server automatically |
| `--interactive / --no-interactive` | Force or disable interactive prompts |
| `--overwrite` | Overwrite existing target directory |
| `-h, --help` | Display help |

Example with all options:

```bash
npm create vite@latest my-app -- --template react-ts --immediate --overwrite
```

This creates the project, installs dependencies, and starts the dev server in one command.

---

## 3. Configuration

### Config File

Vite reads configuration from `vite.config.js` (or `vite.config.ts`) at the project root. Use the `defineConfig` helper for IntelliSense:

```javascript
import { defineConfig } from 'vite'

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

TypeScript config files work out of the box:

```typescript
import { defineConfig } from 'vite'

export default defineConfig({
  // full type support
})
```

### Essential Options

#### Base Path

Set the public base path for deployment to a subdirectory:

```javascript
export default defineConfig({
  base: '/my-app/',
})
```

#### Public Directory

Static assets in `publicDir` are served at root and copied to the build output as-is:

```javascript
export default defineConfig({
  publicDir: 'public', // default
})
```

Files in `public/` are accessible at `/filename` — they are never processed by Vite.

#### Resolve Aliases

Map import paths to directories:

```javascript
import { defineConfig } from 'vite'
import path from 'node:path'

export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '~components': path.resolve(__dirname, './src/components'),
    },
  },
})
```

Usage in source:

```javascript
import App from '@/App.vue'
import Button from '~components/Button.jsx'
```

#### Plugins

Add plugins as an array:

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

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

#### Compile-Time Constants

Replace global constants at build time:

```javascript
export default defineConfig({
  define: {
    __APP_VERSION__: JSON.stringify('1.2.3'),
    'process.env.NODE_ENV': JSON.stringify('production'),
  },
})
```

Use in source code:

```javascript
console.log(`Running version ${__APP_VERSION__}`)
```

### Dev Server Configuration

```javascript
export default defineConfig({
  server: {
    host: '0.0.0.0',        // listen on all interfaces
    port: 3000,              // custom port
    strictPort: true,        // fail if port is taken
    open: true,              // open browser on start
    cors: true,              // enable CORS
    headers: {               // custom response headers
      'X-Custom-Header': 'value',
    },
    hmr: {
      overlay: true,         // show error overlay (default)
    },
    forwardConsole: {
      enabled: true,         // forward browser console to terminal
    },
    fs: {
      strict: true,          // restrict file serving to workspace
      allow: [
        '/path/to/allowed/dir',
      ],
    },
  },
})
```

> [!NOTE]
> `server.fs.strict` restricts file access to the workspace root by default. Use `server.fs.allow` to whitelist additional directories (e.g., monorepo siblings or symlinked packages).

### Build Configuration

```javascript
export default defineConfig({
  build: {
    outDir: 'dist',                // output directory (default)
    assetsInlineLimit: 4096,       // inline assets < 4KB as base64
    sourcemap: true,               // generate source maps
    cssCodeSplit: true,            // CSS code splitting (default)
    manifest: true,                // generate manifest.json
    emptyOutDir: true,             // clear outDir before build
    watch: null,                   // set to {} for watch mode
    ssr: false,                    // SSR build mode
    rollupOptions: {
      // Rolldown options passthrough
      input: 'index.html',
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
        },
      },
    },
  },
})
```

### Library Mode

Build a reusable library instead of an application:

```javascript
import { defineConfig } from 'vite'
import path from 'node:path'

export default defineConfig({
  build: {
    lib: {
      entry: path.resolve(__dirname, 'src/index.ts'),
      name: 'MyLib',
      fileName: 'my-lib',
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
        },
      },
    },
  },
})
```

### Preview Server Configuration

```javascript
export default defineConfig({
  preview: {
    port: 4173,
    headers: {
      'Cache-Control': 'public, max-age=600',
    },
  },
})
```

### CSS Configuration

```javascript
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/styles/variables" as *;`,
      },
      less: {
        modifyVars: {
          'primary-color': '#1DA57A',
        },
        javascriptEnabled: true,
      },
    },
  },
})
```

### JSON Handling

```javascript
export default defineConfig({
  json: {
    namedExports: true,   // allow named imports from .json (default)
    stringify: 'auto',    // stringify large JSON for performance (default)
  },
})
```

### TypeScript / JSX Transpilation

Vite v8 uses oxc by default for TypeScript and JSX transpilation. To use esbuild instead:

```javascript
export default defineConfig({
  oxc: false, // disable oxc, fall back to esbuild
  esbuild: {
    banner: '/* built with esbuild */',
    footer: '/* end */',
  },
})
```

### Conditional Config

Export a function for environment-aware configuration:

```javascript
export default defineConfig(({ command, mode }) => {
  if (command === 'serve') {
    return {
      // dev-specific config
      server: { port: 3000 },
    }
  } else {
    return {
      // build-specific config
      build: { sourcemap: true },
    }
  }
})
```

### Specifying a Config File

Override the default config file path:

```bash
vite --config my-config.js
```

> [!TIP]
> For the complete configuration reference including all nested options and their defaults, see the **Vite Admin Guide**.

---

## 4. Core Usage

### Dev Server

Start the development server:

```bash
vite
# or equivalently:
vite dev
vite serve
```

The dev server serves your project root as a web server with native ES module support. When you import a module in your source, the browser fetches it directly — no bundling step. This is what makes Vite's startup nearly instant regardless of application size.

#### Hot Module Replacement (HMR)

Vite provides out-of-the-box HMR for:

- **Vue** single-file components (via `@vitejs/plugin-vue`)
- **React** components (via `@vitejs/plugin-react` or `@vitejs/plugin-react-swc`)
- **Svelte** components (via `@sveltejs/vite-plugin-svelte`)
- **CSS / PostCSS / Sass / Less / Stylus** — all CSS changes apply without full page reload
- **JSX / TSX** — with appropriate framework plugins

The HMR error overlay displays compile errors directly in the browser. Disable it with:

```javascript
export default defineConfig({
  server: {
    hmr: {
      overlay: false,
    },
  },
})
```

#### HMR API

For custom HMR handling in modules, use the `import.meta.hot` API:

```javascript
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    // handle the updated module
  })

  import.meta.hot.dispose(() => {
    // cleanup side effects
  })
}
```

`import.meta.hot` is `undefined` in production builds and tree-shaken away.

#### Forward Console

Vite v8 can forward `console.log`, `console.warn`, and `console.error` calls from the browser to your server terminal:

```javascript
export default defineConfig({
  server: {
    forwardConsole: {
      enabled: true,
    },
  },
})
```

This is useful for debugging without switching to browser DevTools.

### Production Builds

Build your application for production:

```bash
vite build
```

Vite v8 uses **Rolldown** as the production bundler (replacing Rollup from earlier versions). Rolldown is a Rust-based bundler that provides significantly faster build times while maintaining Rollup plugin API compatibility.

The build produces optimized output in `dist/` by default:

- JavaScript is minified and tree-shaken
- CSS is extracted, minified, and code-split
- Assets below `assetsInlineLimit` (4KB default) are inlined as base64
- Assets above the limit are hashed and output to `dist/assets/`

#### Watch Mode

Rebuild on file changes:

```bash
vite build --watch
```

Or configure in `vite.config.js`:

```javascript
export default defineConfig({
  build: {
    watch: {},
  },
})
```

#### Build Targets

Specify browser targets:

```bash
vite build --target es2022
```

### Preview Server

After building, preview the production output locally:

```bash
vite preview
```

This starts a static file server serving `dist/`. It is not intended for production use — use a proper web server (nginx, Caddy, etc.) to serve your built files in production.

### Dependency Pre-Bundling

Vite automatically pre-bundles dependencies from `node_modules` on first dev server start. This:

1. Converts CommonJS and UMD packages to ESM
2. Consolidates packages with many internal modules into a single request (e.g., `lodash-es` has 600+ modules)

Pre-bundled dependencies are cached in `node_modules/.vite/`. Vite re-bundles when:

- Package manager lockfile changes (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `bun.lockb`)
- Relevant fields in `vite.config.js` change
- Patches in `patches/` folder change

Force a re-bundle:

```bash
vite --force
```

Or:

```bash
vite optimize
```

> [!NOTE]
> The `vite optimize` command explicitly runs the dependency pre-bundling step. This is primarily useful for debugging — in normal development, Vite handles pre-bundling automatically.

---

## 5. Common Tasks

### CSS Processing

#### Plain CSS

Import CSS directly in JavaScript modules:

```javascript
import './style.css'
```

Vite handles `@import` inlining, URL rebasing, and PostCSS automatically (if a PostCSS config is present).

#### CSS Modules

Any file ending in `.module.css` is treated as a CSS Module:

```css
/* button.module.css */
.button {
  background: blue;
  color: white;
}

.primary {
  background: darkblue;
}
```

```javascript
import styles from './button.module.css'

document.getElementById('btn').className = styles.button
// renders as: class="button_abc123"
```

#### Sass / SCSS

Install the preprocessor:

```bash
npm install -D sass
```

Use `.scss` or `.sass` files directly:

```javascript
import './styles/app.scss'
```

Configure global variables or mixins:

```javascript
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/styles/variables" as *;`,
      },
    },
  },
})
```

#### Less

```bash
npm install -D less
```

```javascript
import './styles/app.less'
```

#### Stylus

```bash
npm install -D stylus
```

```javascript
import './styles/app.styl'
```

#### LightningCSS

Vite supports LightningCSS as an alternative CSS transformer and minifier, providing significantly faster CSS processing.

#### CSS Code Splitting

In production builds, Vite automatically extracts CSS used by async chunks into separate files. They load in parallel with the chunk's JavaScript — no flash of unstyled content.

Disable CSS code splitting:

```javascript
export default defineConfig({
  build: {
    cssCodeSplit: false, // bundle all CSS into one file
  },
})
```

### TypeScript

Vite supports TypeScript out of the box. In v8, **oxc** is the default transpiler (replacing esbuild from earlier versions).

Import `.ts` and `.tsx` files directly:

```typescript
// main.ts
import { createApp } from './app'
createApp('#root')
```

> [!IMPORTANT]
> Vite performs transpilation only — it does not run type checking. Run `tsc --noEmit` separately (or use `vue-tsc` for Vue projects) to type-check your code during CI or as a parallel process.

### JSX and TSX

JSX is supported in `.jsx` and `.tsx` files. Framework-specific JSX transforms require the corresponding plugin:

- **React**: `@vitejs/plugin-react`
- **Vue**: `@vitejs/plugin-vue-jsx`
- **Preact**: `@preact/preset-vite`
- **Solid**: `vite-plugin-solid`

### Static Assets

Import static assets to get their resolved URL:

```javascript
import imgUrl from './image.png'

document.getElementById('hero').src = imgUrl
// In dev: /src/image.png
// In build: /assets/image-a1b2c3d4.png
```

#### Supported Asset Types

Vite recognizes these file extensions as static assets:

| Category | Extensions |
|---|---|
| Images | `apng`, `bmp`, `png`, `jpg`, `jpeg`, `jfif`, `pjpeg`, `pjp`, `gif`, `svg`, `ico`, `webp`, `avif`, `cur`, `jxl` |
| Media | `mp4`, `webm`, `ogg`, `mp3`, `wav`, `flac`, `aac`, `opus`, `mov`, `m4a`, `vtt` |
| Fonts | `woff`, `woff2`, `eot`, `ttf`, `otf` |
| Other | `webmanifest`, `pdf`, `txt` |

Add custom asset types:

```javascript
export default defineConfig({
  assetsInclude: ['**/*.gltf', '**/*.hdr'],
})
```

#### Asset Inline Limit

Assets smaller than `assetsInlineLimit` (default: 4096 bytes / 4KB) are inlined as base64 data URLs. Larger assets are emitted as files with content hashes.

```javascript
export default defineConfig({
  build: {
    assetsInlineLimit: 8192, // 8KB
  },
})
```

### Import Suffixes

Vite supports special URL suffixes to control how assets are imported:

| Suffix | Effect | Example |
|---|---|---|
| `?raw` | Import as raw string | `import shader from './frag.glsl?raw'` |
| `?url` | Import as URL (skip inlining) | `import iconUrl from './icon.svg?url'` |
| `?inline` | Force inline as data URL | `import img from './large.png?inline'` |
| `?no-inline` | Force file emission (skip inline) | `import tiny from './dot.png?no-inline'` |
| `?worker` | Import as Web Worker | `import Worker from './worker.js?worker'` |
| `?worker&inline` | Inline Worker as base64 blob | `import Worker from './worker.js?worker&inline'` |
| `?worker&url` | Worker as URL | `import workerUrl from './worker.js?worker&url'` |
| `?sharedworker` | Import as SharedWorker | `import SW from './sw.js?sharedworker'` |
| `?sharedworker&inline` | Inline SharedWorker | `import SW from './sw.js?sharedworker&inline'` |
| `?sharedworker&url` | SharedWorker as URL | `import swUrl from './sw.js?sharedworker&url'` |
| `?url&inline` | URL with inline hint | `import u from './file.txt?url&inline'` |
| `?url&no-inline` | URL without inline | `import u from './file.txt?url&no-inline'` |

#### Raw Imports

Import file contents as a string:

```javascript
import vertexShader from './shaders/vertex.glsl?raw'
import license from '../LICENSE?raw'

console.log(vertexShader)
// outputs the raw GLSL source
```

### Web Workers

Import a script as a Web Worker:

```javascript
import MyWorker from './worker.js?worker'

const worker = new MyWorker()
worker.postMessage({ cmd: 'start' })
worker.onmessage = (e) => {
  console.log('Result:', e.data)
}
```

Inline the worker (useful when you cannot serve separate files):

```javascript
import InlineWorker from './worker.js?worker&inline'
const worker = new InlineWorker()
```

SharedWorker usage:

```javascript
import SharedWorker from './shared.js?sharedworker'
const shared = new SharedWorker()
```

### WebAssembly

Import `.wasm` files with the `?init` suffix:

```javascript
import init from './processor.wasm?init'

const instance = await init()
const result = instance.exports.process(42)
```

### Glob Import

Dynamically import multiple modules matching a glob pattern:

```javascript
const modules = import.meta.glob('./modules/*.js')
// returns:
// {
//   './modules/foo.js': () => import('./modules/foo.js'),
//   './modules/bar.js': () => import('./modules/bar.js'),
// }

// Lazy-load a specific module:
const foo = await modules['./modules/foo.js']()
```

Eager loading (import all at once):

```javascript
const modules = import.meta.glob('./modules/*.js', { eager: true })
// All modules are already imported
```

Named imports for tree-shaking:

```javascript
const setups = import.meta.glob('./modules/*.js', {
  import: 'setup',
})
// Each module's `setup` export is available as a lazy loader
```

Import as raw strings:

```javascript
const templates = import.meta.glob('./templates/*.html', {
  query: '?raw',
  import: 'default',
})
```

Multiple patterns:

```javascript
const modules = import.meta.glob([
  './components/**/*.vue',
  './pages/**/*.vue',
])
```

Negative patterns (exclusions):

```javascript
const modules = import.meta.glob([
  './components/**/*.vue',
  '!./components/internal/**',
])
```

### Dynamic Import with Variables

Vite supports dynamic imports with template literal variables:

```javascript
const page = 'home'
const module = await import(`./pages/${page}.js`)
```

Variables in dynamic imports are limited to one level of depth. Vite analyzes the possible matches at build time and generates code to load them.

### Environment Variables

#### `.env` Files

Vite loads environment variables from `.env` files using `dotenv` and `dotenv-expand`:

| File | Purpose | Loaded when |
|---|---|---|
| `.env` | Base variables | Always |
| `.env.local` | Local overrides (gitignored) | Always |
| `.env.development` | Development variables | `vite dev` |
| `.env.production` | Production variables | `vite build` |
| `.env.development.local` | Local dev overrides | `vite dev` |
| `.env.production.local` | Local prod overrides | `vite build` |

#### Exposing Variables to Client Code

Only variables prefixed with `VITE_` are exposed to client code:

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

Access in source:

```javascript
console.log(import.meta.env.VITE_API_URL)
// → "https://api.example.com"
```

> [!WARNING]
> Never put secrets or credentials in `VITE_*` variables. They are embedded verbatim in your client bundle and visible to anyone inspecting your JavaScript.

#### Built-In Environment Variables

| Variable | Type | Description |
|---|---|---|
| `import.meta.env.MODE` | `string` | `'development'` or `'production'` (or custom mode) |
| `import.meta.env.BASE_URL` | `string` | The `base` config value |
| `import.meta.env.PROD` | `boolean` | `true` in production |
| `import.meta.env.DEV` | `boolean` | `true` in development |
| `import.meta.env.SSR` | `boolean` | `true` in SSR mode |

#### Custom Modes

Use `--mode` to load a custom `.env` file:

```bash
vite build --mode staging
```

This loads `.env.staging` and `.env.staging.local`.

### JSON Imports

Import JSON files with named exports:

```javascript
import pkg from './package.json'
console.log(pkg.version)

// Named imports (tree-shakeable)
import { version, name } from './package.json'
console.log(version)
```

When `json.namedExports` is `true` (default), individual fields can be imported and unused fields are tree-shaken.

When `json.stringify` is `'auto'` (default), large JSON files are serialized as strings for better performance.

### HTML and Multi-Page Apps

Vite uses `index.html` as the entry point. For multi-page apps, create multiple HTML files and configure build inputs:

```
project/
├── index.html
├── about.html
├── contact/
│   └── index.html
└── src/
    ├── main.js
    ├── about.js
    └── contact.js
```

```javascript
import { defineConfig } from 'vite'
import path from 'node:path'

export default defineConfig({
  build: {
    rollupOptions: {
      input: {
        main: path.resolve(__dirname, 'index.html'),
        about: path.resolve(__dirname, 'about.html'),
        contact: path.resolve(__dirname, 'contact/index.html'),
      },
    },
  },
})
```

In each HTML file, reference its module with `<script type="module">`:

```html
<!-- about.html -->
<!DOCTYPE html>
<html>
  <head><title>About</title></head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/about.js"></script>
  </body>
</html>
```

### Server-Side Rendering (SSR)

Vite provides built-in SSR support. Create a server entry:

```javascript
// src/entry-server.js
export function render(url) {
  // render app to HTML string
  return '<div id="app">...</div>'
}
```

Build the SSR bundle:

```bash
vite build --ssr src/entry-server.js
```

The SSR build outputs a CommonJS bundle suitable for server environments.

#### Module Runner

Vite v8 provides a Module Runner for SSR environments, allowing efficient server-side module execution with HMR support during development.

### Source Maps

Enable source maps for production debugging:

```bash
vite build --sourcemap
```

Options:

```javascript
export default defineConfig({
  build: {
    sourcemap: true,       // generate .map files
    // or: 'inline'        // inline source maps
    // or: 'hidden'        // .map files without sourceMappingURL
  },
})
```

### Build Manifest

Generate a manifest file mapping original filenames to hashed output:

```javascript
export default defineConfig({
  build: {
    manifest: true,
  },
})
```

Produces `dist/.vite/manifest.json`:

```json
{
  "src/main.js": {
    "file": "assets/main-BfH3kQ2f.js",
    "src": "src/main.js",
    "isEntry": true,
    "css": ["assets/main-DiwrgTda.css"]
  }
}
```

This is essential for server-rendered apps that need to reference the correct hashed filenames.

### Public Directory

Files in `public/` are served at the root path and copied to `dist/` unchanged:

```
public/
├── favicon.ico
├── robots.txt
└── images/
    └── og-image.png
```

Reference them with absolute paths (no import needed):

```html
<link rel="icon" href="/favicon.ico" />
<img src="/images/og-image.png" />
```

> [!CAUTION]
> Do not import files from `public/` in JavaScript — they are not processed by Vite's module graph. Always use absolute URL paths like `/filename` instead.

---

## 6. Troubleshooting

### Error: `Cannot find module` or `Failed to resolve import`

**Cause:** A dependency is missing or an import path is incorrect.

**Solution:**
1. Run `npm install` to ensure all dependencies are installed
2. Check for typos in the import path
3. Verify `resolve.alias` mappings in `vite.config.js`
4. Clear the dependency cache: `vite --force`

**Prevention:** Use TypeScript or IDE extensions that validate import paths at edit time.

### Error: `Pre-transform error` / `[plugin:vite:import-analysis] Failed to resolve import`

**Cause:** Vite cannot resolve an imported module during dev server operation.

**Solution:**
1. Check that the package is listed in `dependencies` or `devDependencies`
2. For monorepo packages, ensure they are properly linked
3. Try clearing pre-bundled dependencies:

```bash
rm -rf node_modules/.vite
npm run dev
```

**Prevention:** Keep `package.json` in sync with actual imports.

### Error: Port already in use

**Cause:** Another process is using the default port (5173 for dev, 4173 for preview).

**Solution:**
```bash
vite --port 3000
```

Or use `--strictPort` to fail instead of auto-incrementing:

```bash
vite --strictPort --port 5173
```

**Prevention:** Configure a consistent port in `vite.config.js`.

### HMR Not Working or Stops After Save

**Cause:** Several possibilities including circular dependencies, missing HMR boundary, or file system watcher issues.

**Solution:**
1. Check the terminal for error messages
2. For circular dependency issues (especially with TypeScript), refactor to break the cycle
3. On WSL2 or networked drives, try polling mode by setting `server.watch.usePolling: true`
4. Ensure your framework plugin is up to date

**Prevention:** Avoid circular imports. Keep framework plugins updated to match your Vite version.

> [!NOTE]
> HMR may stop functioning after saving a TypeScript file that introduces a circular dependency. Vite detects these cycles but cannot always recover gracefully. Breaking the circular dependency resolves the issue.

### CSS Ordering Differs Between Dev and Production

**Cause:** In development, CSS is loaded as individual modules via `<style>` tags. In production, CSS is extracted and combined, which can change cascade order.

**Solution:**
1. Avoid relying on CSS import order for specificity conflicts
2. Use more specific selectors or CSS Modules to isolate styles
3. Explicitly control order with a single entry CSS file that `@import`s in the correct sequence

**Prevention:** Use CSS Modules, scoped styles, or a CSS-in-JS solution to avoid cascade ordering issues.

### `vite build` Produces Empty or Incorrect Output

**Cause:** Entry point misconfiguration or `emptyOutDir` clearing a non-default output path.

**Solution:**
1. Verify `index.html` exists at the project root (or configure `build.rollupOptions.input`)
2. Check that `build.outDir` is correct
3. Ensure `<script type="module" src="...">` in your HTML points to an existing file

### Dependency Pre-Bundling Fails or Loops

**Cause:** A dependency has unusual packaging, or Vite cannot detect all dependencies upfront.

**Solution:**
1. Force re-bundling: `vite --force`
2. Manually include or exclude packages:

```javascript
export default defineConfig({
  optimizeDeps: {
    include: ['problematic-package'],
    exclude: ['package-with-its-own-esm'],
  },
})
```

### Error: `[vite] Internal server error: Missing "./package.json" export in "some-package"`

**Cause:** The dependency's `exports` field in `package.json` does not include `./package.json`.

**Solution:** Add the package to `optimizeDeps.include` to force pre-bundling, which resolves the export map.

### Build Fails with `Unexpected token` in a Dependency

**Cause:** A dependency contains syntax that the current transpiler cannot handle (e.g., newer ECMAScript features in a CJS package).

**Solution:**
1. Add the package to `optimizeDeps.include`
2. If using oxc and it fails, try disabling it for the affected file:

```javascript
export default defineConfig({
  optimizeDeps: {
    include: ['legacy-package'],
  },
})
```

### Plugin Errors Are Hidden or Swallowed

**Cause:** Some plugin errors may not surface clearly in the console.

**Solution:**
1. Run with debug logging: `vite --debug`
2. Check if the plugin has a `configResolved` hook that might be silencing errors
3. Try removing plugins one by one to isolate the issue
4. Update the plugin to its latest version

### Legacy Browser Support

For projects that must support older browsers (IE11, older Safari), use the official legacy plugin:

```bash
npm install -D @vitejs/plugin-legacy
```

```javascript
import legacy from '@vitejs/plugin-legacy'

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

> [!WARNING]
> `@vitejs/plugin-legacy` v8.0.1 may encounter issues with esbuild 0.27.7 or later. Pin your esbuild version if you experience build failures with this plugin.

---

## 7. FAQ

### CLI Reference

#### `vite` / `vite dev` / `vite serve`

Start the development server.

```bash
vite [options]
```

| Flag | Description |
|---|---|
| `--host [host]` | Bind to specific host (`0.0.0.0` for all interfaces) |
| `--port <port>` | Set port number |
| `--open [path]` | Open browser on start |
| `--cors` | Enable CORS |
| `--strictPort` | Fail if port is in use (instead of trying next) |
| `--force` | Force dependency re-bundling |
| `--config <file>` | Use specified config file |
| `--base <path>` | Public base path |
| `--logLevel <level>` | Log level: `info`, `warn`, `error`, `silent` |
| `--clearScreen` | Allow/disallow clearing the terminal screen |
| `--mode <mode>` | Set env mode (loads `.env.<mode>`) |
| `--debug [feat]` | Show debug logs (optionally for specific features) |
| `--filter <filter>` | Filter debug logs |

#### `vite build`

Build for production.

```bash
vite build [options]
```

| Flag | Description |
|---|---|
| `--outDir <dir>` | Output directory (default: `dist`) |
| `--assetsInlineLimit <n>` | Asset inline threshold in bytes (default: 4096) |
| `--ssr [entry]` | Build for SSR with given entry |
| `--sourcemap` | Generate source maps |
| `--minify [minifier]` | Enable/disable minification |
| `--manifest [name]` | Generate build manifest |
| `--ssrManifest [name]` | Generate SSR manifest |
| `--emptyOutDir` | Clear output directory before build |
| `--watch` | Rebuild on file changes |
| `--target <target>` | Transpilation target |
| `--config <file>` | Use specified config file |
| `--base <path>` | Public base path |
| `--logLevel <level>` | Log level |
| `--clearScreen` | Allow/disallow clearing the terminal screen |
| `--mode <mode>` | Set env mode |

#### `vite preview`

Preview the production build locally.

```bash
vite preview [options]
```

Accepts `--host`, `--port`, `--strictPort`, `--open`, `--config`, `--base`, `--logLevel`, `--clearScreen`, and `--mode`.

#### `vite optimize`

Run dependency pre-bundling explicitly.

```bash
vite optimize [options]
```

Accepts `--force`, `--config`, and `--logLevel`.

---

**Q: What is the difference between Vite and traditional bundlers like webpack?**

Traditional bundlers process your entire application upfront before serving anything. Vite takes a different approach: it serves source files directly via native ES modules during development, only transforming individual files on demand. The result is near-instant dev server startup regardless of project size. For production, Vite uses Rolldown to produce optimized bundles.

**Q: Does Vite support CommonJS dependencies?**

Yes. Vite's dependency pre-bundling step automatically converts CommonJS and UMD packages to ESM. This happens transparently during dev server startup. In rare cases involving conditional CJS modules, you may need to add the dependency to `optimizeDeps.include`.

**Q: Can I use Vite without a framework?**

Absolutely. The `vanilla` and `vanilla-ts` templates create a plain JavaScript/TypeScript project with no framework. Vite works as a general-purpose dev server and bundler for any web project.

**Q: How do I deploy a Vite app?**

Run `vite build` to produce a `dist/` directory with static files. Deploy these to any static hosting provider: Netlify, Vercel, Cloudflare Pages, GitHub Pages, AWS S3 + CloudFront, or any web server capable of serving static files.

**Q: How do I add HTTPS to the dev server?**

Configure the `server.https` option with your certificate and key files in `vite.config.js`. For local development, tools like `mkcert` can generate trusted local certificates.

**Q: What is `import.meta.glob` and when should I use it?**

`import.meta.glob` is Vite's way of importing multiple modules matching a file pattern. Common use cases: auto-registering Vue components, loading all route modules, collecting markdown files for a blog. It replaces webpack's `require.context`.

**Q: What changed in Vite v8 compared to earlier versions?**

Key changes in v8:
- **Rolldown replaces Rollup** as the production bundler
- **oxc replaces esbuild** as the default TypeScript/JSX transpiler
- Node.js minimum version raised to `^20.19.0` or `>=22.12.0`
- Module Preload Polyfill for legacy browsers
- Forward Console feature to pipe browser logs to the terminal

**Q: How do I handle environment-specific configuration?**

Use the `--mode` flag to load different `.env` files. Create `.env.development`, `.env.production`, `.env.staging`, etc. Variables with the `VITE_` prefix are exposed to client code; all others remain server-side only.

**Q: My vendor bundle is too large. How do I split it?**

Use `build.rollupOptions.output.manualChunks` to control code splitting:

```javascript
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          charts: ['d3', 'chart.js'],
        },
      },
    },
  },
})
```

**Q: Can I use Vite for a library instead of an application?**

Yes. Use `build.lib` to configure library mode. Vite will output ESM and UMD/CJS formats, externalize dependencies, and handle proper module exports. See the Library Mode section in this guide.

**Q: How do I handle monorepo setups?**

Vite works in monorepos. Use `server.fs.allow` to whitelist directories outside the project root. For linked packages, ensure they are properly listed in `optimizeDeps.include` if pre-bundling has trouble resolving them.

**Q: Is there a way to analyze my bundle size?**

Use `rollup-plugin-visualizer` (compatible with Vite via the plugin system):

```bash
npm install -D rollup-plugin-visualizer
```

```javascript
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [visualizer({ open: true })],
})
```

This generates an interactive treemap of your bundle after building.

---

_Generated May 2026 from vitejs/vite at 66f3194. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
