Skip to main content
Technology & EngineeringMigration Patterns195 lines

Webpack to Vite

Migrate a Webpack-based project to Vite for faster development builds and HMR

Quick Summary33 lines
You are an expert in migrating JavaScript/TypeScript projects from Webpack to Vite for dramatically faster dev server startup and hot module replacement.

## Key Points

1. **Audit Webpack Config** — catalog all loaders, plugins, aliases, and environment variable patterns.
2. **Install Vite** — add Vite and corresponding framework plugin alongside Webpack.
3. **Create vite.config.ts** — translate Webpack settings to Vite equivalents.
4. **Update Entry Points** — move to `index.html` as the entry point (Vite requires this).
5. **Fix Imports** — resolve any non-ESM import patterns, require() calls, and asset handling differences.
6. **Remove Webpack** — delete Webpack config, loaders, and dev dependencies once Vite is verified.
- Run Webpack and Vite in parallel during migration so you can compare behavior before fully switching.
- Replace `process.env.REACT_APP_*` references project-wide using a codemod or find-and-replace.
- Use `vite-plugin-checker` for TypeScript type checking in dev (Vite skips type checking by default for speed).
- For libraries that rely on Node.js built-ins (`path`, `fs`, `crypto`), install the browser polyfill packages and configure `resolve.alias`.
- Test the production build (`vite build && vite preview`) early — dev and production use different pipelines in Vite.
- **Missing `index.html` at root** — Vite requires `index.html` as the entry point at the project root, not generated by a plugin.

## Quick Example

```bash
npm install --save-dev vite @vitejs/plugin-react
npm uninstall webpack webpack-cli webpack-dev-server babel-loader css-loader style-loader html-webpack-plugin
```

```typescript
// Before (Webpack / CRA)
const apiUrl = process.env.REACT_APP_API_URL;

// After (Vite)
const apiUrl = import.meta.env.VITE_API_URL;
```
skilldb get migration-patterns-skills/Webpack to ViteFull skill: 195 lines
Paste into your CLAUDE.md or agent config

Webpack to Vite — Migration Patterns

You are an expert in migrating JavaScript/TypeScript projects from Webpack to Vite for dramatically faster dev server startup and hot module replacement.

Core Philosophy

Overview

Vite leverages native ES modules in development, eliminating the bundling step that makes Webpack dev servers slow on large projects. The migration involves replacing Webpack configuration with Vite equivalents, updating import patterns, and swapping plugins. Production builds use Rollup under the hood and produce optimized output comparable to Webpack.

Migration Strategy

  1. Audit Webpack Config — catalog all loaders, plugins, aliases, and environment variable patterns.
  2. Install Vite — add Vite and corresponding framework plugin alongside Webpack.
  3. Create vite.config.ts — translate Webpack settings to Vite equivalents.
  4. Update Entry Points — move to index.html as the entry point (Vite requires this).
  5. Fix Imports — resolve any non-ESM import patterns, require() calls, and asset handling differences.
  6. Remove Webpack — delete Webpack config, loaders, and dev dependencies once Vite is verified.

Step-by-Step Guide

1. Audit existing Webpack configuration

Common Webpack features that need Vite equivalents:

WebpackVite Equivalent
webpack-dev-servervite (built-in)
babel-loaderesbuild (built-in)
ts-loaderesbuild (built-in)
css-loader / style-loaderBuilt-in CSS support
file-loader / url-loaderBuilt-in asset handling
html-webpack-pluginindex.html at project root
DefinePlugindefine in config or .env files
resolve.aliasresolve.alias in config
MiniCssExtractPluginBuilt-in CSS code splitting

2. Install Vite and plugins

npm install --save-dev vite @vitejs/plugin-react
npm uninstall webpack webpack-cli webpack-dev-server babel-loader css-loader style-loader html-webpack-plugin

3. Move index.html to project root

Vite uses index.html as the entry point (not a Webpack-generated file):

<!-- index.html (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>
  <script type="module" src="/src/main.tsx"></script>
</body>
</html>

4. Create vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

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

  resolve: {
    alias: {
      // Translate Webpack aliases
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils'),
    },
  },

  // Environment variables: Vite uses VITE_ prefix instead of REACT_APP_
  // Access via import.meta.env.VITE_API_URL instead of process.env.REACT_APP_API_URL
  define: {
    // Bridge for libraries that check process.env.NODE_ENV
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
  },

  server: {
    port: 3000,
    proxy: {
      // Translate devServer.proxy from Webpack
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
      },
    },
  },

  build: {
    outDir: 'dist',
    sourcemap: true,
  },
});

5. Update environment variable references

// Before (Webpack / CRA)
const apiUrl = process.env.REACT_APP_API_URL;

// After (Vite)
const apiUrl = import.meta.env.VITE_API_URL;

Rename .env variable prefixes:

# Before
REACT_APP_API_URL=https://api.example.com

# After
VITE_API_URL=https://api.example.com

6. Fix CommonJS require() calls

Vite dev mode uses native ESM, so require() is not available:

// Before
const logo = require('./assets/logo.png');

// After
import logo from './assets/logo.png';

For dynamic requires:

// Before
const icon = require(`./icons/${name}.svg`);

// After
const modules = import.meta.glob('./icons/*.svg', { eager: true });
const icon = modules[`./icons/${name}.svg`];

7. Update package.json scripts

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

Best Practices

  • Run Webpack and Vite in parallel during migration so you can compare behavior before fully switching.
  • Replace process.env.REACT_APP_* references project-wide using a codemod or find-and-replace.
  • Use vite-plugin-checker for TypeScript type checking in dev (Vite skips type checking by default for speed).
  • For libraries that rely on Node.js built-ins (path, fs, crypto), install the browser polyfill packages and configure resolve.alias.
  • Test the production build (vite build && vite preview) early — dev and production use different pipelines in Vite.

Common Pitfalls

  • Missing index.html at root — Vite requires index.html as the entry point at the project root, not generated by a plugin.
  • process.env references — Vite does not inject process.env globally. Every reference must be migrated to import.meta.env or explicitly defined.
  • CommonJS dependencies — some npm packages ship only CommonJS. Vite pre-bundles these automatically via esbuild, but edge cases may require adding them to optimizeDeps.include.
  • CSS Modules naming — Vite expects .module.css file naming for CSS Modules. Files without .module. in the name are treated as global CSS.
  • Glob import differences — Webpack's require.context is replaced by import.meta.glob, which has a different API. This requires manual code changes.

Anti-Patterns

Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.

Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.

Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.

Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.

Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.

Install this skill directly: skilldb add migration-patterns-skills

Get CLI access →