home / skills / bobmatnyc / claude-mpm-skills / vite

This skill helps you accelerate modern web development with Vite by delivering instant HMR, zero-config setup, and fast production builds.

npx playbooks add skill bobmatnyc/claude-mpm-skills --skill vite

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
20.9 KB
---
name: vite-build-tool
description: "Vite lightning-fast build tool with instant HMR, ESM-first architecture, and zero-config setup for modern web development"
progressive_disclosure:
  entry_point:
    summary: "Vite lightning-fast build tool with instant HMR, ESM-first architecture, and zero-config setup for modern web development"
    when_to_use: "When working with vite-build-tool or related functionality."
    quick_start: "1. Review the core concepts below. 2. Apply patterns to your use case. 3. Follow best practices for implementation."
---
# Vite Build Tool Skill

---
progressive_disclosure:
  entry_point:
    summary: "Lightning-fast build tool with instant HMR and ESM-first architecture for modern web development"
    when_to_use:
      - "When building React/Vue/Svelte/Preact applications"
      - "When needing instant HMR (Hot Module Replacement)"
      - "When migrating from webpack/CRA/Parcel"
      - "When setting up TypeScript projects with zero config"
      - "When building component libraries or UI frameworks"
    quick_start:
      - "npm create vite@latest my-app"
      - "Select framework: React/Vue/Svelte/Vanilla"
      - "cd my-app && npm install && npm run dev"
    essential_commands:
      - "vite: Start dev server with instant HMR"
      - "vite build: Production build with Rollup"
      - "vite preview: Preview production build locally"
  token_estimate:
    entry: 75
    full: 4000
---

## Core Concepts

### Why Vite?

**ESM-First Architecture**
- No bundling in development - serves native ESM
- Instant cold server start (no matter project size)
- Lightning-fast HMR that stays fast as app grows
- Rollup-based production builds with optimal code splitting

**Key Advantages**
- **Dev Speed**: 10-100x faster than webpack (no bundling)
- **Zero Config**: TypeScript, JSX, CSS modules out-of-box
- **Framework Agnostic**: React, Vue, Svelte, Preact, Lit
- **Plugin Ecosystem**: Rollup plugins + Vite-specific plugins
- **Modern by Default**: ESM, dynamic imports, top-level await

## Quick Start

### Create New Project

```bash
# Interactive creation
npm create vite@latest

# With template
npm create vite@latest my-app -- --template react-ts
npm create vite@latest my-app -- --template vue
npm create vite@latest my-app -- --template svelte-ts

# Available templates:
# vanilla, vanilla-ts
# react, react-ts, react-swc, react-swc-ts
# vue, vue-ts
# svelte, svelte-ts
# preact, preact-ts
# lit, lit-ts
```

### Essential Commands

```bash
# Development server (instant start)
npm run dev
vite --port 3000 --host 0.0.0.0

# Production build
npm run build
vite build --mode production

# Preview production build
npm run preview
vite preview --port 8080

# Clear cache (dependency pre-bundling)
rm -rf node_modules/.vite
```

## Configuration

### Basic vite.config.ts

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

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

  // Dev server
  server: {
    port: 3000,
    open: true,
    cors: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  },

  // Build options
  build: {
    outDir: 'dist',
    sourcemap: true,
    minify: 'terser',
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          utils: ['lodash-es', 'date-fns']
        }
      }
    }
  },

  // Path aliases
  resolve: {
    alias: {
      '@': '/src',
      '@components': '/src/components',
      '@utils': '/src/utils'
    }
  }
});
```

### Framework-Specific Configs

**React + TypeScript + SWC**
```typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import path from 'path';

export default defineConfig({
  plugins: [
    react({
      // Enable Fast Refresh
      fastRefresh: true,
      // SWC optimizations
      tsDecorators: true
    })
  ],

  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  },

  build: {
    target: 'es2020',
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('node_modules')) {
            if (id.includes('react') || id.includes('react-dom')) {
              return 'react-vendor';
            }
            return 'vendor';
          }
        }
      }
    }
  }
});
```

**Vue 3 + TypeScript**
```typescript
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';

export default defineConfig({
  plugins: [
    vue(),
    vueJsx() // For JSX/TSX in Vue
  ],

  resolve: {
    alias: {
      '@': '/src',
      'vue': 'vue/dist/vue.esm-bundler.js'
    }
  },

  // Vue-specific optimizations
  optimizeDeps: {
    include: ['vue', 'vue-router', 'pinia']
  }
});
```

**Svelte + TypeScript**
```typescript
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  plugins: [
    svelte({
      compilerOptions: {
        dev: process.env.NODE_ENV !== 'production'
      },
      hot: {
        preserveLocalState: true
      }
    })
  ],

  build: {
    target: 'es2020',
    minify: 'esbuild'
  }
});
```

## Environment Variables

### .env Files

```bash
# .env (loaded in all cases)
VITE_APP_TITLE=My App

# .env.local (local overrides, gitignored)
VITE_API_KEY=secret-key

# .env.development
VITE_API_URL=http://localhost:8000

# .env.production
VITE_API_URL=https://api.production.com
```

### Usage in Code

```typescript
// TypeScript: Define env types
interface ImportMetaEnv {
  readonly VITE_APP_TITLE: string;
  readonly VITE_API_URL: string;
  readonly VITE_API_KEY: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

// Access variables (MUST start with VITE_)
console.log(import.meta.env.VITE_API_URL);
console.log(import.meta.env.MODE); // 'development' or 'production'
console.log(import.meta.env.DEV); // boolean
console.log(import.meta.env.PROD); // boolean
```

### vite-env.d.ts

```typescript
/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_APP_TITLE: string;
  readonly VITE_API_URL: string;
  readonly VITE_API_KEY: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}
```

## Plugin Ecosystem

### Official Plugins

```bash
# React
npm install -D @vitejs/plugin-react          # Babel-based
npm install -D @vitejs/plugin-react-swc      # SWC-based (faster)

# Vue
npm install -D @vitejs/plugin-vue
npm install -D @vitejs/plugin-vue-jsx

# Svelte
npm install -D @sveltejs/vite-plugin-svelte

# Legacy browser support
npm install -D @vitejs/plugin-legacy
```

### Essential Community Plugins

```typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import tsconfigPaths from 'vite-tsconfig-paths';
import { VitePWA } from 'vite-plugin-pwa';
import compression from 'vite-plugin-compression';
import { visualizer } from 'rollup-plugin-visualizer';

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

    // TypeScript paths from tsconfig.json
    tsconfigPaths(),

    // PWA support
    VitePWA({
      registerType: 'autoUpdate',
      manifest: {
        name: 'My App',
        short_name: 'App',
        theme_color: '#ffffff'
      }
    }),

    // Gzip/Brotli compression
    compression({
      algorithm: 'brotliCompress',
      ext: '.br'
    }),

    // Bundle size visualization
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true
    })
  ]
});
```

## TypeScript Configuration

### tsconfig.json for Vite

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,

    /* Path aliases */
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"]
    }
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}
```

### tsconfig.node.json (for config files)

```json
{
  "compilerOptions": {
    "composite": true,
    "skipLibCheck": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true
  },
  "include": ["vite.config.ts"]
}
```

## CSS & Asset Handling

### CSS Modules

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

// Component.tsx
import styles from './Component.module.css';

export function Button() {
  return <button className={styles.button}>Click</button>;
}
```

### PostCSS Configuration

```javascript
// postcss.config.js
export default {
  plugins: {
    'postcss-nesting': {},
    'autoprefixer': {},
    'cssnano': {
      preset: 'default'
    }
  }
};
```

### Sass/SCSS

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

```typescript
// Just import - Vite handles it
import './styles.scss';

// Vite config for global variables
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@/styles/variables.scss";`
      }
    }
  }
});
```

### Static Assets

```typescript
// Import as URL
import imgUrl from './assets/logo.png';
console.log(imgUrl); // '/assets/logo.abc123.png'

// Import as string (raw)
import svgRaw from './icon.svg?raw';
console.log(svgRaw); // '<svg>...</svg>'

// Import as Web Worker
import Worker from './worker?worker';
const worker = new Worker();

// Public directory (not processed)
// public/favicon.ico → /favicon.ico
<img src="/favicon.ico" />
```

## Build Optimization

### Code Splitting

```typescript
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        // Manual chunks for better caching
        manualChunks(id) {
          if (id.includes('node_modules')) {
            // Split by package
            if (id.includes('react') || id.includes('react-dom')) {
              return 'react-vendor';
            }
            if (id.includes('@mui')) {
              return 'mui-vendor';
            }
            if (id.includes('lodash')) {
              return 'lodash-vendor';
            }
            return 'vendor';
          }
        },

        // Naming patterns
        chunkFileNames: 'assets/js/[name]-[hash].js',
        entryFileNames: 'assets/js/[name]-[hash].js',
        assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
      }
    },

    // Chunk size warnings
    chunkSizeWarningLimit: 1000,

    // Minification
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    }
  }
});
```

### Dependency Pre-bundling

```typescript
export default defineConfig({
  optimizeDeps: {
    // Force include (for dynamic imports)
    include: [
      'react',
      'react-dom',
      'lodash-es'
    ],

    // Force exclude (keep unbundled)
    exclude: [
      'your-local-package'
    ],

    // esbuild options
    esbuildOptions: {
      target: 'es2020',
      define: {
        global: 'globalThis'
      }
    }
  }
});
```

### Library Mode

```typescript
// Build as library/package
import { defineConfig } from 'vite';
import { resolve } from 'path';

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'MyLibrary',
      fileName: (format) => `my-library.${format}.js`,
      formats: ['es', 'cjs', 'umd']
    },

    rollupOptions: {
      // Externalize deps that shouldn't be bundled
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM'
        }
      }
    }
  }
});
```

## Migration Guides

### From Create React App (CRA)

```bash
# 1. Remove CRA
npm uninstall react-scripts

# 2. Install Vite
npm install -D vite @vitejs/plugin-react

# 3. Update package.json scripts
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}
```

```typescript
// 4. Create vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000
  },
  build: {
    outDir: 'build' // CRA uses 'build'
  }
});
```

```html
<!-- 5. Update index.html (move to root, remove %PUBLIC_URL%) -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
```

```typescript
// 6. Update environment variables
// CRA: REACT_APP_API_URL
// Vite: VITE_API_URL

// Before (CRA)
process.env.REACT_APP_API_URL

// After (Vite)
import.meta.env.VITE_API_URL
```

### From Webpack

```typescript
// webpack.config.js → vite.config.ts

// Webpack concepts → Vite equivalents:
// - entry → index.html + <script src="main.tsx">
// - output.path → build.outDir
// - resolve.alias → resolve.alias (same!)
// - module.rules → plugins (for file types)
// - optimization.splitChunks → build.rollupOptions.output.manualChunks
// - DefinePlugin → define config option
// - devServer → server config
```

## SSR (Server-Side Rendering)

### Basic SSR Setup

```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    // SSR build
    ssr: true,
    outDir: 'dist/server'
  }
});
```

```typescript
// server.ts (Express + Vite SSR)
import express from 'express';
import { createServer as createViteServer } from 'vite';

async function createServer() {
  const app = express();

  const vite = await createViteServer({
    server: { middlewareMode: true },
    appType: 'custom'
  });

  app.use(vite.middlewares);

  app.use('*', async (req, res) => {
    const url = req.originalUrl;

    try {
      // Load template
      let template = await vite.transformIndexHtml(
        url,
        fs.readFileSync('index.html', 'utf-8')
      );

      // Load SSR entry
      const { render } = await vite.ssrLoadModule('/src/entry-server.tsx');

      // Render app
      const appHtml = await render(url);

      // Inject into template
      const html = template.replace(`<!--ssr-outlet-->`, appHtml);

      res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
    } catch (e) {
      vite.ssrFixStacktrace(e);
      res.status(500).end(e.stack);
    }
  });

  app.listen(3000);
}

createServer();
```

## Performance Best Practices

### Dev Server Optimization

```typescript
export default defineConfig({
  server: {
    // Faster dependency resolution
    fs: {
      strict: false,
      allow: ['..']
    },

    // WebSocket connection
    hmr: {
      overlay: true,
      clientPort: 3000
    }
  },

  // Faster pre-bundling
  optimizeDeps: {
    force: false, // Only rebuild on deps change
    include: ['large-dependencies']
  },

  // Faster transforms
  esbuild: {
    logOverride: { 'this-is-undefined-in-esm': 'silent' }
  }
});
```

### Build Performance

```typescript
export default defineConfig({
  build: {
    // Faster builds (esbuild vs terser)
    minify: 'esbuild',

    // Disable source maps in production
    sourcemap: false,

    // Target modern browsers only
    target: 'es2020',

    // Reduce rollup overhead
    rollupOptions: {
      cache: true
    },

    // Report compressed size (slower but informative)
    reportCompressedSize: false
  }
});
```

### Smart Code Splitting

```typescript
// Dynamic imports for route-based splitting
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));

// Component-level splitting
const HeavyChart = lazy(() => import('./components/HeavyChart'));

// Conditional loading
const AdminPanel = lazy(() =>
  import(/* @vite-ignore */ './admin/Panel')
);
```

## Debugging

### Common Issues

**Issue: Module not found**
```bash
# Clear dependency cache
rm -rf node_modules/.vite
npm install
```

**Issue: HMR not working**
```typescript
// Check vite.config.ts
export default defineConfig({
  server: {
    hmr: {
      overlay: true
    },
    watch: {
      usePolling: true // For Docker/WSL
    }
  }
});
```

**Issue: Build errors but dev works**
```bash
# Check for:
# - TypeScript errors (tsc --noEmit)
# - Import paths (case sensitivity)
# - Missing dependencies in package.json
```

### Debug Mode

```bash
# Verbose logging
DEBUG=vite:* vite

# Specific debug scopes
DEBUG=vite:deps vite
DEBUG=vite:hmr vite
DEBUG=vite:config vite
```

## Advanced Patterns

### Multi-page App

```typescript
import { defineConfig } from 'vite';
import { resolve } from 'path';

export default defineConfig({
  build: {
    rollupOptions: {
      input: {
        main: resolve(__dirname, 'index.html'),
        admin: resolve(__dirname, 'admin/index.html'),
        docs: resolve(__dirname, 'docs/index.html')
      }
    }
  }
});
```

### Custom Plugin

```typescript
import { Plugin } from 'vite';

export function myPlugin(): Plugin {
  return {
    name: 'my-plugin',

    // Transform code
    transform(code, id) {
      if (id.endsWith('.custom')) {
        return {
          code: transformCode(code),
          map: null
        };
      }
    },

    // Handle HMR
    handleHotUpdate({ file, server }) {
      if (file.endsWith('.custom')) {
        server.ws.send({
          type: 'custom',
          event: 'update'
        });
      }
    },

    // Modify config
    config(config, env) {
      return {
        define: {
          __BUILD_TIME__: JSON.stringify(new Date().toISOString())
        }
      };
    }
  };
}
```

### Monorepo Support

```typescript
// packages/app/vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  resolve: {
    alias: {
      '@shared': '../../packages/shared/src'
    }
  },

  optimizeDeps: {
    include: [
      '@workspace/shared' // Pre-bundle workspace deps
    ]
  },

  server: {
    fs: {
      allow: ['../..'] // Allow serving from monorepo root
    }
  }
});
```

## Integration Examples

### Vite + React + TypeScript + Tailwind

```bash
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

```typescript
// tailwind.config.js
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

### Vite + Testing (Vitest)

```bash
npm install -D vitest @testing-library/react jsdom
```

```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html']
    }
  }
});
```

## Quick Reference

### Essential Configuration Options

```typescript
export default defineConfig({
  // Base public path
  base: '/my-app/',

  // Modes: 'development' | 'production'
  mode: 'production',

  // Define global constants
  define: {
    __APP_VERSION__: JSON.stringify('1.0.0')
  },

  // Public directory
  publicDir: 'public',

  // Cache directory
  cacheDir: 'node_modules/.vite',

  // Log level
  logLevel: 'info' // 'info' | 'warn' | 'error' | 'silent'
});
```

### Common Plugin Combinations

```typescript
// React + TypeScript + PWA + Analytics
import react from '@vitejs/plugin-react-swc';
import { VitePWA } from 'vite-plugin-pwa';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  plugins: [
    react(),
    tsconfigPaths(),
    VitePWA({
      registerType: 'autoUpdate'
    })
  ]
});
```

## Related Skills

When using Vite, consider these complementary skills (available in the skill library):

- **React**: React framework integration - use Vite's optimized React plugin for fast development
- **Vue**: Vue framework integration - leverage Vite's native Vue support and SFC compilation
- **Svelte**: Svelte framework integration - combine Svelte's compile-time optimizations with Vite's speed
- **TypeScript**: TypeScript configuration - configure TypeScript with Vite for type-safe development
- **Vitest**: Testing with Vite - use Vitest for lightning-fast unit testing with Vite's transform pipeline

## Resources

**Official Documentation**
- Vite Guide: https://vitejs.dev/guide/
- Config Reference: https://vitejs.dev/config/
- Plugin API: https://vitejs.dev/guide/api-plugin.html

**Community**
- Awesome Vite: https://github.com/vitejs/awesome-vite
- Vite Rollup Plugins: https://vite-rollup-plugins.patak.dev/

**Migration Tools**
- CRA to Vite: https://github.com/vitejs/vite/discussions/3802
- Webpack to Vite: https://github.com/originjs/webpack-to-vite

Overview

This skill packages Vite, a lightning-fast ESM-first build tool with instant HMR and zero-config defaults for modern web apps. It helps set up dev servers, production builds, framework integrations, and common optimizations for React, Vue, Svelte, Preact and library projects. The goal is fast iteration in development and efficient Rollup-based production output.

How this skill works

The skill inspects project context and recommends Vite scaffolding, plugins and config patterns. It generates or updates vite.config.ts, provides essential npm scripts, suggests OptimizeDeps and Rollup manualChunks, and outlines env handling and TypeScript settings. It also guides framework-specific plugin choices and build modes like library or SSR.

When to use it

  • Creating new React/Vue/Svelte/Preact projects with instant HMR
  • Migrating from webpack, CRA, or Parcel to a modern dev toolchain
  • Setting up TypeScript projects with minimal configuration
  • Building component libraries or publishing JS packages
  • Optimizing production builds with code splitting and dependency pre-bundling

Best practices

  • Use native ESM for development to keep cold starts and HMR instant
  • Keep env variables prefixed with VITE_ and type them in vite-env.d.ts
  • Configure manualChunks to split vendors for better caching
  • Use framework-specific Vite plugins (react-swc, @vitejs/plugin-vue, svelte plugin)
  • Add optimizeDeps.include for heavy dynamic imports and exclude local packages

Example use cases

  • Scaffold a new TypeScript React app: npm create vite@latest my-app -- --template react-ts
  • Migrate a CRA repo: remove react-scripts, install vite + plugin, update scripts to vite/dev/build/preview
  • Build a library: configure build.lib with entry, formats and externalized deps
  • SSR setup: enable middlewareMode and use createViteServer for server-side rendering
  • Add PWA and compression: integrate vite-plugin-pwa and vite-plugin-compression in plugins

FAQ

Do environment variables require special names?

Yes. Variables exposed to client code must start with VITE_. Define types via ImportMetaEnv and access with import.meta.env.

How do I speed up cold starts for large projects?

Rely on Vite's native ESM dev server; tune optimizeDeps.include to pre-bundle heavy deps and clear node_modules/.vite when cache issues appear.