---
# === IDENTITY ===
id: software/migrations/webpack-to-vite/2026
canonical_question: "How do I migrate from Webpack to Vite?"
aliases:
  - "Webpack to Vite migration guide"
  - "convert Webpack project to Vite"
  - "replace Webpack with Vite"
  - "switch from Webpack to Vite"
  - "migrate webpack.config.js to vite.config.js"
  - "Webpack 5 to Vite 6 migration"
  - "Webpack 5 to Vite 7 migration"
  - "move build tooling from Webpack to Vite"
entity_type: software_reference
domain: software > migrations > webpack_to_vite
region: global
jurisdiction: global
temporal_scope: 2020-2026

# === VERIFICATION ===
last_verified: 2026-05-17
confidence: 0.94
version: 2.1
first_published: 2026-02-17

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: evolving
  last_breaking_change: "Vite 8.0 (2026-03-12) — Rolldown replaces esbuild+Rollup; build.rollupOptions → build.rolldownOptions; optimizeDeps.esbuildOptions deprecated → rolldownOptions; esbuild option deprecated → oxc; default target Chrome 111/Firefox 114/Safari 16.4"
  next_review: 2026-11-13
  change_sensitivity: medium

# === CONSTRAINTS ===
constraints:
  - "Vite 7 and Vite 8 require Node.js 20.19+ or 22.12+ — Node 18 reached EOL and is no longer supported"
  - "All source code must use ESM (import/export) — CommonJS require() is not supported in Vite's module graph"
  - "Environment variables exposed to client code must use the VITE_ prefix — never shim process.env globally as it leaks all server env vars to the browser bundle"
  - "index.html must be at the project root (not in public/ or src/) — Vite uses it as the entry point instead of html-webpack-plugin"
  - "Vite 8 (Mar 2026) replaces esbuild+Rollup with Rolldown+Oxc — build.rollupOptions becomes build.rolldownOptions and optimizeDeps.esbuildOptions becomes optimizeDeps.rolldownOptions (compat layer auto-converts but will be removed)"
  - "Webpack Module Federation has no first-party Vite equivalent — use @module-federation/vite (Lib Type federation) or @originjs/vite-plugin-federation; expect rough edges in dev server"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User is migrating from Create React App (CRA) and wants the Next.js path instead of Vite"
    use_instead: "software/migrations/cra-to-nextjs/2026"
  - condition: "User needs a Webpack-compatible alternative with better performance (not Vite)"
    use_instead: "Rspack or Turbopack — drop-in Webpack replacements that keep webpack.config.js"
  - condition: "Project depends on Webpack Module Federation, custom loaders, or SPFx and cannot refactor"
    use_instead: "Keep Webpack 5 or evaluate Rspack (Module Federation-compatible)"

# === AGENT HINTS ===
inputs_needed:
  - key: framework
    question: "Which frontend framework is the project using?"
    type: choice
    options: ["React", "Vue 2", "Vue 3", "Svelte", "Vanilla JS/TS", "Angular"]
  - key: cjs_usage
    question: "Does the project use CommonJS require() or module.exports in source files?"
    type: choice
    options: ["Yes — extensively", "A few files", "No — already ESM"]
  - key: webpack_plugins
    question: "Does the project rely on Webpack-specific features like Module Federation or custom loaders?"
    type: choice
    options: ["Yes — Module Federation", "Yes — custom loaders/plugins", "No — standard setup"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/migrations/webpack-to-vite/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-05-17)"

# === RELATED UNITS ===
related_kos:
  related_to:
    - id: "software/migrations/javascript-to-typescript/2026"
      label: "JavaScript to TypeScript Migration"
    - id: "software/migrations/jquery-to-react/2026"
      label: "jQuery to React Migration"
  alternative_to:
    - id: "software/migrations/cra-to-nextjs/2026"
      label: "Create React App to Next.js Migration"
  often_confused_with:
    - id: "software/migrations/angular-to-react/2026"
      label: "Angular to React Migration (framework swap, not build-tool swap)"

# === SOURCES (9 authoritative sources) ===
# Types: official_docs, technical_blog, rfc_spec, academic_paper, community_resource, industry_report
# Reliability: high, moderate_high, moderate, moderate_low, low, authoritative
sources:
  - id: src1
    title: "Configuring Vite"
    author: Vite
    url: https://vite.dev/config/
    type: official_docs
    published: 2025-11-25
    reliability: authoritative
  - id: src2
    title: "What We Learned Migrating From Webpack to Vite"
    author: Neon
    url: https://neon.com/blog/from-webpack-to-vite
    type: technical_blog
    published: 2025-08-12
    reliability: high
  - id: src3
    title: "webpack-to-vite: Automated Conversion Tool"
    author: Origin.js
    url: https://github.com/originjs/webpack-to-vite
    type: community_resource
    published: 2024-06-15
    reliability: moderate_high
  - id: src4
    title: "Migrating your app from Webpack to Vite"
    author: Stormkit
    url: https://www.stormkit.io/blog/migrating-your-app-from-webpack-to-vite
    type: technical_blog
    published: 2024-03-20
    reliability: high
  - id: src5
    title: "How to Migrate from Webpack to Vite?"
    author: GeeksforGeeks
    url: https://www.geeksforgeeks.org/javascript/how-to-migrate-from-webpack-to-vite/
    type: community_resource
    published: 2025-01-10
    reliability: moderate_high
  - id: src6
    title: "Migrating a Webpack project to Vite"
    author: Malcolm Crum
    url: https://malcolmcrum.com/blog/2023/03/10/migrate-webpack-to-vite.html
    type: technical_blog
    published: 2023-03-10
    reliability: high
  - id: src7
    title: "A Guide to Migrating from Webpack to Vite"
    author: SitePoint
    url: https://www.sitepoint.com/webpack-vite-migration/
    type: technical_blog
    published: 2025-05-15
    reliability: high
  - id: src8
    title: "Migration from v7 — Vite"
    author: Vite
    url: https://vite.dev/guide/migration
    type: official_docs
    published: 2025-09-01
    reliability: authoritative
  - id: src9
    title: "Vite 8.0 is out!"
    author: Vite
    url: https://vite.dev/blog/announcing-vite8
    type: official_docs
    published: 2026-03-12
    reliability: authoritative
  - id: src10
    title: "Webpack to Vite Migration: Large Codebases 2026"
    author: PkgPulse
    url: https://www.pkgpulse.com/blog/webpack-to-vite-migration-large-codebases-2026
    type: technical_blog
    published: 2026-04-08
    reliability: high
---

# How to Migrate from Webpack to Vite

## How do I migrate from Webpack to Vite?

## TL;DR

- **Bottom line**: Replace `webpack.config.js` with `vite.config.js`, swap Webpack loaders for Vite plugins or built-in features, convert `process.env` to `import.meta.env`, move your `index.html` to the project root, and convert any CommonJS `require()` calls to ESM `import` statements.
- **Key tool/command**: `npm install vite @vitejs/plugin-react --save-dev && npx vite`
- **Watch out for**: CommonJS `require()` calls and dynamic `require.context()` patterns that Vite cannot handle natively -- these must be converted to `import.meta.glob()` or ESM imports.
- **Works with**: Vite 6.x/7.x/8.x (Vite 8 released 2026-03-12 with Rolldown bundler), React 18+/19, Vue 2/3, Svelte, Node.js 20.19+ or 22.12+ (Vite 7/8), any project currently using Webpack 4 or 5.

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- Vite 7 and Vite 8 require Node.js 20.19+ or 22.12+ -- Node 18 reached EOL and is no longer supported. If the project must stay on Node 18, pin Vite 6.x. [src8, src9]
- All source code must use ESM (`import`/`export`) -- CommonJS `require()` is not supported in Vite's module graph. Convert before migrating. [src3, src6]
- Environment variables exposed to client code must use the `VITE_` prefix -- never shim `process.env` globally as it leaks all server env vars to the browser bundle. [src2, src4]
- `index.html` must be at the project root (not in `public/` or `src/`) -- Vite uses it as the entry point instead of `html-webpack-plugin`. [src4, src5]
- Vite 8 (Mar 2026) replaces esbuild+Rollup with a single Rust bundler (Rolldown) and uses Oxc for JS transforms. `build.rollupOptions` becomes `build.rolldownOptions`, `optimizeDeps.esbuildOptions` becomes `optimizeDeps.rolldownOptions`, and the `esbuild` config option becomes `oxc`. A compat layer auto-converts during the transition but will be removed. [src9]
- Webpack Module Federation has no first-party Vite equivalent -- use `@module-federation/vite` (preferred in 2026, shares the `@module-federation/runtime`) or `@originjs/vite-plugin-federation`. Both still have dev-server rough edges. [src7, src10]

## Quick Reference

| Webpack Config/Feature | Vite Equivalent | Example |
|---|---|---|
| `entry` (string) | `build.rolldownOptions.input` (Vite 8) / `build.rollupOptions.input` (Vite ≤7) | `input: { main: 'src/main.js' }` |
| `output.path` | `build.outDir` | `build: { outDir: 'dist' }` |
| `output.publicPath` | `base` | `base: '/my-app/'` |
| `output.filename` | `build.rolldownOptions.output.entryFileNames` (Vite 8) | `entryFileNames: 'assets/[name]-[hash].js'` |
| `output.chunkFilename` | `build.rolldownOptions.output.chunkFileNames` (Vite 8) | `chunkFileNames: 'assets/[name]-[hash].js'` |
| `devServer.port` | `server.port` | `server: { port: 3000 }` |
| `devServer.proxy` | `server.proxy` | `server: { proxy: { '/api': 'http://localhost:8080' } }` |
| `devServer.https` | `server.https` | `server: { https: true }` (or `@vitejs/plugin-basic-ssl`) |
| `resolve.alias` | `resolve.alias` | `resolve: { alias: { '@': '/src' } }` |
| `resolve.extensions` | `resolve.extensions` | `resolve: { extensions: ['.js', '.ts', '.jsx'] }` |
| `DefinePlugin` | `define` | `define: { __APP_VERSION__: JSON.stringify('1.0') }` |
| `process.env.NODE_ENV` | `import.meta.env.MODE` | Automatic in Vite (`development`/`production`) |
| `process.env.REACT_APP_*` | `import.meta.env.VITE_*` | Prefix env vars with `VITE_` in `.env` files |
| `copy-webpack-plugin` | `publicDir` (default: `public/`) | Static files in `public/` are copied to `dist/` automatically |
| `css-loader` + `style-loader` | Built-in CSS support | `import './style.css'` works out of the box |
| `sass-loader` | Built-in (install `sass`) | `npm install sass -D` -- no loader config needed |
| `postcss-loader` | Built-in (auto-detects `postcss.config.js`) | Just keep your PostCSS config file |
| `file-loader` / `url-loader` | Built-in asset handling | `import logo from './logo.png'` returns URL |
| `html-webpack-plugin` | `index.html` at project root | Move `index.html` to root, add `<script type="module" src="/src/main.js">` |
| `MiniCssExtractPlugin` | Built-in CSS code splitting | Automatic in production builds |
| `HotModuleReplacementPlugin` | Built-in HMR | Automatic with framework plugins |
| `require.context()` | `import.meta.glob()` | `const modules = import.meta.glob('./modules/*.js')` |
| `require()` (dynamic) | `new URL('./path', import.meta.url).href` | For asset URLs in ESM context |
| `webpack-bundle-analyzer` | `rollup-plugin-visualizer` | `import { visualizer } from 'rollup-plugin-visualizer'` |
| `babel-loader` | Built-in Oxc (Vite 8) / esbuild (Vite ≤7) | Oxc handles JSX/TSX transformation in Vite 8; `@vitejs/plugin-react` v6 drops Babel entirely |
| `ts-loader` | Built-in Oxc (Vite 8) / esbuild (Vite ≤7) | No loader needed; native TS transpilation |
| `ProvidePlugin` | `vite-plugin-inject` or manual imports | Replace global shimming with explicit imports |
| `splitVendorChunkPlugin` (deprecated Vite 7) | `build.rolldownOptions.output.manualChunks` (Vite 8) | Define manual chunk splitting (object form removed in Vite 8 — use function form) |
| `tsconfig.compilerOptions.paths` | Built-in `tsconfig` paths (Vite 8) | Vite 8 reads `tsconfig` paths natively; pre-Vite 8 needs `vite-tsconfig-paths` plugin |
| `ModuleFederationPlugin` | `@module-federation/vite` | `federation({ name: 'host', remotes: { app1: '...' } })` — preferred over `@originjs/vite-plugin-federation` in 2026 |

## Decision Tree

```
START
├── Is the project using CommonJS (require/module.exports) extensively?
│   ├── YES → First convert to ESM imports/exports, then proceed with migration
│   └── NO ↓
├── Is the project using Vue CLI (vue-cli-service)?
│   ├── YES → Use `npx @originjs/webpack-to-vite` automated tool, then fix remaining issues
│   └── NO ↓
├── Is the project using Create React App (react-scripts)?
│   ├── YES → See CRA to Vite migration (simpler path with fewer config decisions)
│   └── NO ↓
├── Does the project rely on Webpack-specific APIs (require.context, module.hot)?
│   ├── YES → Replace require.context with import.meta.glob, remove module.hot (Vite HMR is automatic)
│   └── NO ↓
├── Does the project use Webpack Module Federation?
│   ├── YES → Evaluate vite-plugin-federation or keep Webpack for federated entry points
│   └── NO ↓
├── Does the project have complex Webpack plugins with no Vite equivalent?
│   ├── YES → Check for Rollup-compatible plugin or write a custom Vite plugin (Rollup plugin API)
│   └── NO ↓
├── Is this a React project?
│   ├── YES → Install @vitejs/plugin-react, create vite.config.js, update scripts
│   └── NO ↓
├── Is this a Vue project?
│   ├── YES → Install @vitejs/plugin-vue, create vite.config.js, update scripts
│   └── NO ↓
└── DEFAULT → Install vite, create minimal vite.config.js, move index.html to root, update scripts
```

## Step-by-Step Guide

### 1. Audit your Webpack configuration

Catalog all loaders, plugins, and custom configuration in your `webpack.config.js`. Identify which ones have built-in Vite equivalents (most CSS/asset loaders), which need Vite plugins, and which require manual conversion. [src3, src7]

```bash
# List all Webpack dependencies in your project
npm ls | grep -i webpack
npm ls | grep -i loader
npm ls | grep -i plugin
# Count configuration complexity
cat webpack.config.js | wc -l
```

**Verify**: You have a complete list of every loader and plugin that needs a Vite replacement or removal.

### 2. Install Vite and framework plugin

Install Vite and the official plugin for your framework. Keep Webpack installed during migration so you can compare builds. [src1, src5]

```bash
# For React projects
npm install vite @vitejs/plugin-react --save-dev

# For Vue 3 projects
npm install vite @vitejs/plugin-vue --save-dev

# For Vue 2 projects
npm install vite vite-plugin-vue2 --save-dev

# For Svelte projects
npm install vite @sveltejs/vite-plugin-svelte --save-dev
```

**Verify**: `npx vite --version` prints the installed Vite version without errors.

### 3. Create vite.config.js from your webpack.config.js

Translate your Webpack configuration to the Vite equivalent using the Quick Reference table above. [src1, src3, src4]

```javascript
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      // Webpack: resolve.alias['@'] = path.resolve(__dirname, 'src')
      '@': path.resolve(__dirname, 'src'),
    },
  },
  server: {
    // Webpack: devServer.port = 3000
    port: 3000,
    // Webpack: devServer.proxy
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
      },
    },
  },
  build: {
    // Webpack: output.path = path.resolve(__dirname, 'dist')
    outDir: 'dist',
    // Webpack: devtool = 'source-map'
    sourcemap: true,
  },
  define: {
    // Webpack: new webpack.DefinePlugin({ __APP_VERSION__: ... })
    __APP_VERSION__: JSON.stringify(process.env.npm_package_version),
  },
});
```

**Verify**: `npx vite build --config vite.config.js` does not throw configuration errors (content errors are expected at this stage).

### 4. Move index.html to project root and update it

Vite uses `index.html` at the project root as the entry point (unlike Webpack's `html-webpack-plugin`). Add a `<script type="module">` tag pointing to your entry file. [src4, src5]

```html
<!-- Move from public/index.html or src/index.html to project root -->
<!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="root"></div>
  <!-- Vite entry point: replaces html-webpack-plugin's template injection -->
  <script type="module" src="/src/main.jsx"></script>
</body>
</html>
```

**Verify**: The file is at the project root (same level as `package.json`), and the `src` attribute points to your actual entry file.

### 5. Convert environment variables

Rename all `REACT_APP_*` or custom `process.env.*` variables to `VITE_*` prefix. Replace all `process.env.VARIABLE` references with `import.meta.env.VITE_VARIABLE`. [src2, src4]

```bash
# Rename .env variables
# BEFORE: REACT_APP_API_URL=https://api.example.com
# AFTER:  VITE_API_URL=https://api.example.com

# Find all process.env references to convert
grep -rn "process\.env\." --include='*.js' --include='*.ts' --include='*.jsx' --include='*.tsx' src/
```

```javascript
// BEFORE (Webpack)
const apiUrl = process.env.REACT_APP_API_URL;
const isProd = process.env.NODE_ENV === 'production';

// AFTER (Vite)
const apiUrl = import.meta.env.VITE_API_URL;
const isProd = import.meta.env.PROD;  // Built-in boolean
// Also available: import.meta.env.DEV, import.meta.env.MODE, import.meta.env.BASE_URL
```

**Verify**: `grep -rn "process\.env\." --include='*.js' --include='*.ts' --include='*.jsx' --include='*.tsx' src/` returns zero results.

### 6. Convert CommonJS require() to ESM imports

Vite requires ESM syntax. Replace all `require()` calls with `import` statements and `module.exports` with `export`. [src3, src6]

```javascript
// BEFORE (CommonJS)
const React = require('react');
const logo = require('./logo.png');
const modules = require.context('./modules', true, /\.js$/);
module.exports = { App };

// AFTER (ESM)
import React from 'react';
import logo from './logo.png';
const modules = import.meta.glob('./modules/**/*.js');  // Vite's require.context replacement
export { App };
```

**Verify**: `grep -rn "require(" --include='*.js' --include='*.ts' --include='*.jsx' --include='*.tsx' src/` returns zero results (excluding node_modules and test files).

### 7. Rename .jsx/.tsx files if needed

Vite is stricter than Webpack about file extensions. Any file that contains JSX syntax must have a `.jsx` or `.tsx` extension -- `.js` files with JSX will fail. [src2, src7]

```bash
# Find .js files containing JSX syntax
grep -rln "<[A-Z][a-zA-Z]*" --include='*.js' src/ | head -20

# Rename them (example for a single file)
git mv src/components/App.js src/components/App.jsx

# Batch rename (careful — verify before running)
find src -name '*.js' -exec grep -l '<[A-Z]' {} \; | while read f; do
  git mv "$f" "${f%.js}.jsx"
done
```

**Verify**: `npx vite build` does not throw JSX-related parse errors.

### 8. Update package.json scripts and remove Webpack

Replace Webpack scripts with Vite commands and uninstall all Webpack dependencies. [src5, src7]

```json
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint src/"
  }
}
```

```bash
# Remove Webpack and all related packages
npm uninstall webpack webpack-cli webpack-dev-server \
  html-webpack-plugin mini-css-extract-plugin css-loader \
  style-loader file-loader url-loader babel-loader ts-loader \
  sass-loader postcss-loader webpack-bundle-analyzer \
  copy-webpack-plugin
# Remove config files
rm webpack.config.js webpack.dev.js webpack.prod.js
```

**Verify**: `npm run dev` starts the Vite dev server; `npm run build` produces output in `dist/`. Application loads without console errors.

## Code Examples

### JavaScript/React: Complete vite.config.js replacing a typical webpack.config.js

> Full script: [javascript-react-complete-vite-config-js-replacing.js](scripts/javascript-react-complete-vite-config-js-replacing.js) (67 lines)

```javascript
// Input:  A React project with Webpack using aliases, proxy, env vars, SCSS, and SVG
// Output: Equivalent Vite configuration
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';
# ... (see full script)
```

### TypeScript: Migrating Webpack require.context to Vite import.meta.glob

> Full script: [typescript-migrating-webpack-require-context-to-vi.ts](scripts/typescript-migrating-webpack-require-context-to-vi.ts) (37 lines)

```typescript
// Input:  Webpack project using require.context for dynamic module loading
// Output: Equivalent Vite pattern using import.meta.glob
// ============================================================
// BEFORE: Webpack require.context (auto-import all route modules)
// ============================================================
# ... (see full script)
```

### Node.js: Migration script to automate environment variable renaming

> Full script: [node-js-migration-script-to-automate-environment-v.js](scripts/node-js-migration-script-to-automate-environment-v.js) (52 lines)

```javascript
// Input:  A project with REACT_APP_* env vars in .env files and process.env.* in source
// Output: Converted VITE_* env vars and import.meta.env.* references
import { readFileSync, writeFileSync, readdirSync, statSync } from 'fs';
import { join, extname } from 'path';
// Step 1: Rename env vars in .env files
# ... (see full script)
```

## Anti-Patterns

### Wrong: Keeping process.env references and shimming with define

```javascript
// ❌ BAD — Shimming process.env globally to avoid refactoring
// vite.config.js
export default defineConfig({
  define: {
    'process.env': process.env,  // Leaks ALL env vars to client bundle!
  },
});
```

### Correct: Use Vite's import.meta.env with VITE_ prefix

```javascript
// ✅ GOOD — Only VITE_-prefixed vars are exposed to client code
// .env
// VITE_API_URL=https://api.example.com
// SECRET_KEY=abc123  ← NOT exposed to client (no VITE_ prefix)

// src/config.js
const apiUrl = import.meta.env.VITE_API_URL;
const mode = import.meta.env.MODE;  // 'development' or 'production'
```

### Wrong: Copying webpack.config.js structure into vite.config.js

```javascript
// ❌ BAD — Manually configuring things Vite handles automatically
export default defineConfig({
  plugins: [
    react(),
    // Don't need these — Vite handles them natively:
    cssPlugin(),          // Vite has built-in CSS support
    assetPlugin(),        // Vite has built-in asset handling
    htmlPlugin(),         // Vite uses index.html at root
    hotReloadPlugin(),    // Vite has built-in HMR
  ],
  // Don't configure loaders — Vite has no loader concept
  module: { rules: [] },  // This isn't even valid Vite config
});
```

### Correct: Minimal Vite config — let defaults work

```javascript
// ✅ GOOD — Vite needs very little configuration for most projects
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  // CSS, assets, HMR, HTML all work out of the box
  // Only add config for what you actually need to customize
});
```

### Wrong: Using require() in source code with Vite

```javascript
// ❌ BAD — CommonJS require doesn't work in Vite's ESM-first architecture
const logo = require('./assets/logo.png');
const config = require('./config.json');
const modules = require.context('./plugins', true, /\.js$/);
```

### Correct: Use ESM imports and import.meta.glob

```javascript
// ✅ GOOD — ESM imports for static assets and modules
import logo from './assets/logo.png';
import config from './config.json';
const modules = import.meta.glob('./plugins/**/*.js', { eager: true });
```

### Wrong: Defining global as empty object to fix Node.js polyfill errors

```javascript
// ❌ BAD — Breaks libraries that actually use global
export default defineConfig({
  define: {
    global: {},  // This causes "global is not an object" errors at runtime
  },
});
```

### Correct: Properly polyfill global for browser context

```javascript
// ✅ GOOD — Define global as window for browser compatibility
export default defineConfig({
  define: {
    global: 'globalThis',  // globalThis works in both Node and browser
  },
});
```

### Wrong: Using the deprecated Sass legacy API with Vite 7

```javascript
// ❌ BAD — Sass legacy API was removed in Vite 7
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        api: 'legacy',  // This option no longer exists in Vite 7
      },
    },
  },
});
```

### Correct: Use the modern Sass API (Vite 7 default)

```javascript
// ✅ GOOD — Modern Sass API is the only option in Vite 7
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "@/styles/variables" as *;`,
        // No 'api' option needed — modern API is the default
      },
    },
  },
});
```

## Common Pitfalls

- **Circular import dependencies in dev mode**: Vite's native ESM dev server exposes circular dependencies that Webpack's bundling hides. Symptoms: `undefined` imports, runtime errors only in dev. Fix: Run `npx madge src/index.tsx --circular` to find cycles, then extract shared code into separate modules. [src6]
- **Missing file extensions in imports**: Vite requires explicit `.vue` extensions and may require other extensions depending on configuration. Fix: Add extensions to all imports or configure `resolve.extensions` in `vite.config.js`, but prefer explicit extensions. [src3]
- **`global is not defined` errors**: Libraries that reference Node.js `global` object fail in Vite's browser ESM context. Fix: Add `define: { global: 'globalThis' }` to `vite.config.js`. [src4]
- **CSS Modules require `.module.css` naming**: Webpack's `css-loader` with `modules: true` works on any `.css` file, but Vite requires the `.module.css` suffix convention. Fix: Rename `style.css` to `style.module.css` for files using CSS Modules. [src3]
- **Broken default exports from CommonJS dependencies**: Some npm packages use `module.exports = X` which Vite handles differently than Webpack. Symptoms: `X is not a function` or `X.default is not a function`. Fix: Use `import X from 'package'` and if needed, add `const Lib = (X as any).default || X` as a fallback. [src6]
- **Top-level `this` references in legacy code**: Code that uses `this` at module top level (where it refers to `globalThis` in scripts but `undefined` in ESM). Fix: Replace `this` with `globalThis` or configure `esbuild: { define: { this: 'window' } }` in `vite.config.js`. [src4]
- **`process.env` not defined at runtime**: Vite does not inject `process.env` by default unlike Webpack's `DefinePlugin`. Fix: Replace all `process.env.*` with `import.meta.env.*` using `VITE_` prefix. [src2]
- **Production build works differently than dev**: Vite uses esbuild in dev but Rollup in production. Some code may work in dev but fail in prod or vice versa. Fix: Always test with `vite build && vite preview` before deploying. [src4]
- **JSX in .js files fails**: Unlike Webpack with Babel, Vite's esbuild only processes JSX in `.jsx`/`.tsx` files by default. Fix: Rename files containing JSX to `.jsx` or `.tsx` extensions. [src2, src7]
- **`optimizeDeps.entries` treated as globs in Vite 7**: In Vite 7, all values in `optimizeDeps.entries` are treated as glob patterns rather than literal file paths. If you have literal paths with special characters, escape them. [src8]

## Diagnostic Commands

```bash
# Check for remaining Webpack references in the project
grep -rn "webpack\|require(\|module\.exports" --include='*.js' --include='*.ts' --include='*.jsx' --include='*.tsx' src/ | grep -v node_modules

# Find remaining process.env references
grep -rn "process\.env\." --include='*.js' --include='*.ts' --include='*.jsx' --include='*.tsx' src/

# Find .js files containing JSX that need renaming
grep -rln "<[A-Z][a-zA-Z]*" --include='*.js' src/

# Detect circular dependencies (install madge: npm install -g madge)
npx madge src/main.tsx --circular --extensions ts,tsx,js,jsx

# Verify Vite dev server starts
npx vite --debug

# Verify production build completes
npx vite build 2>&1 | tail -20

# Compare bundle sizes (install rollup-plugin-visualizer)
npx vite build && open dist/stats.html

# Check that all env vars are prefixed correctly
grep -rn "^[A-Z]" .env* | grep -v "^.*:VITE_\|^.*:#\|^.*:NODE_ENV"

# List all dependencies that might need Vite-specific plugins
npm ls --depth=0 | grep -i "webpack\|loader\|babel"

# Verify Node.js version meets Vite 7 requirements
node -v  # Must be 20.19+ or 22.12+
```

## Version History & Compatibility

| Version | Status | Key Features | Migration Notes |
|---|---|---|---|
| Vite 8.x (2026-03-12) | Current | Rolldown bundler (unified Rust toolchain, 10-30x faster builds, dev/prod parity), Oxc replaces esbuild for JS transforms, integrated Devtools, built-in `tsconfig` paths, WebAssembly SSR, `emitDecoratorMetadata` support | `build.rollupOptions` → `build.rolldownOptions`; `optimizeDeps.esbuildOptions` → `optimizeDeps.rolldownOptions`; `esbuild` option → `oxc`; default target Chrome 111/Firefox 114/Safari 16.4; `transformWithEsbuild` → `transformWithOxc`; +15 MB install size; recommended 2-step path: migrate to `rolldown-vite` on Vite 7 first |
| Vite 7.x (2025-09) | Maintenance | Node 20.19+ required, `baseline-widely-available` target, `buildApp` hook, Sass legacy API removed | Drop Node 18; remove `splitVendorChunkPlugin`; use `order`/`handler` in `transformIndexHtml` hooks |
| Vite 6.x (2024) | LTS | Environment API (experimental), Rolldown preview | Vite 5 configs work with minor updates; `server.fs.allow` tightened |
| Vite 5.x (2023) | Maintenance | Rollup 4, Node 18+ required, improved CSS handling | Drop Node 14/16 support; update Rollup plugins to v4-compatible |
| Vite 4.x (2022) | EOL | SWC support via plugin, improved SSR | First version with stable React SWC plugin |
| Vite 3.x (2022) | EOL | ESM-only config, `import.meta.glob` changes | `glob` returns lazy imports by default (add `{ eager: true }` for sync) |
| Vite 2.x (2021) | EOL | First stable release, Rollup-based | Original migration target from Webpack; most guides reference this |

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Starting a new project or major refactor | Webpack config is simple and build times are acceptable | Keep Webpack |
| Dev server HMR is painfully slow (>2s) | Project relies on Webpack-specific features (Module Federation) | Webpack 5 with Module Federation |
| Want to reduce build configuration complexity | Team has deep Webpack plugin expertise and custom loaders | Maintain existing Webpack setup |
| Using React, Vue, Svelte, or vanilla JS/TS | Building a complex micro-frontend architecture | Webpack 5 + Module Federation or Rspack |
| Need native ESM and modern browser targeting | Must support IE11 or very old browsers | Webpack 5 with Babel |
| Project size is small to medium (<500 modules) | Very large monorepo with 10K+ modules and custom build pipelines | Turbopack or Rspack |
| Want faster builds without changing bundler API | Need Webpack API compatibility with better perf | Rspack (drop-in Webpack replacement) |

## Important Caveats

- On Vite 7 and earlier, Vite uses esbuild for development (fast, but less compatible) and Rollup for production (slower, but more configurable). Code that works in dev may fail in production -- always verify with `vite build && vite preview`. Vite 8 closes this gap by using Rolldown for both. [src9]
- Vite does not polyfill Node.js built-in modules (`path`, `fs`, `crypto`, etc.). If your frontend code imports these (often via transitive dependencies), you need `vite-plugin-node-polyfills` or must refactor.
- Vite's dev server serves native ES modules to the browser. The first page load in development can be slow on large projects (1000+ modules) because the browser must fetch each module individually. Use `optimizeDeps.include` to pre-bundle heavy dependencies.
- The `@vitejs/plugin-react-swc` plugin offers faster builds than `@vitejs/plugin-react` (Babel-based) but may crash on syntax errors rather than displaying error overlays. Test stability before committing to SWC. Note: `@vitejs/plugin-react` v6 (paired with Vite 8) now uses Oxc and drops Babel entirely. [src2, src9]
- Rolldown-based (Vite 8) and Rollup-based (Vite ≤7) production builds produce different chunk structures than Webpack. If your deployment relies on specific output file names or chunk patterns (e.g., long-term caching with specific hash formats), verify the output structure after migration.
- Vite 8 (released 2026-03-12) ships Rolldown as the unified bundler. Real-world reports: Linear cut production builds from 46s to 6s (87% reduction); HMR is ~24× faster than Webpack. Migration from Vite 7: the compat layer auto-converts `build.rollupOptions`, `optimizeDeps.esbuildOptions`, and the `esbuild` config option, but plan to rename them before the layer is removed. Recommended path for large apps: switch to the `rolldown-vite` package on Vite 7 first to isolate Rolldown-specific issues, then upgrade to Vite 8. [src9, src10]
- Vite 7 changed the default browser target from `'modules'` (Chrome 87, Firefox 78, Safari 14) to `'baseline-widely-available'` (Chrome 107, Firefox 104, Safari 16). Vite 8 raises it further to Chrome 111 / Firefox 114 / Safari 16.4. If you need older browser support, set `build.target` explicitly. [src8, src9]
- Oxc does not yet lower native TypeScript/legacy decorators. If your project relies on `experimentalDecorators` or stage-3 decorator semantics, you must add a Babel or SWC plugin until Oxc catches up. [src9]
- For large codebases, plan an incremental migration (2-6 weeks): run Vite for dev while keeping Webpack for production builds temporarily, then flip prod once all blockers (CommonJS, require.context, Module Federation, SVG, custom loaders) are cleared. [src10]

## Related Units

- [jQuery to React Migration](/software/migrations/jquery-to-react/2026)
- [JavaScript to TypeScript Migration](/software/migrations/javascript-to-typescript/2026)
- [Create React App to Next.js Migration](/software/migrations/cra-to-nextjs/2026)
- [Angular to React Migration](/software/migrations/angular-to-react/2026)
