# Vite Patterns

> When to activate: Vite, vite.config.ts, plugins, HMR, build optimization, code splitting, environment variables, vitest

- Skill: `mattakushi432/vite-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/vite-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/vite-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/vite-patterns

---


# Vite Patterns

## vite.config.ts Baseline
```ts
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'

export default defineConfig(({ command, mode }) => {
  const env = loadEnv(mode, process.cwd(), '')

  return {
    plugins: [react()],

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

    build: {
      target: 'es2022',
      sourcemap: mode !== 'production',
      rollupOptions: {
        output: {
          manualChunks: {
            vendor: ['react', 'react-dom'],
            router: ['react-router-dom'],
            query:  ['@tanstack/react-query'],
          },
        },
      },
    },

    server: {
      port: 3000,
      proxy: {
        '/api': {
          target: env.VITE_API_URL ?? 'http://localhost:8080',
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
        },
      },
    },

    preview: { port: 4173 },
  }
})
```

## Environment Variables
```
# .env
VITE_API_URL=http://localhost:8080
VITE_FEATURE_X=true

# .env.production
VITE_API_URL=https://api.example.com
```
```ts
// Access in code (VITE_ prefix exposes to client)
const apiUrl = import.meta.env.VITE_API_URL
const isProd  = import.meta.env.PROD   // boolean
const isDev   = import.meta.env.DEV    // boolean
const mode    = import.meta.env.MODE   // 'development' | 'production' | custom

// Type-safe env
interface ImportMetaEnv {
  readonly VITE_API_URL: string
  readonly VITE_FEATURE_X: string
}
interface ImportMeta { readonly env: ImportMetaEnv }
```

## Code Splitting
```ts
// Lazy route components
import { lazy, Suspense } from 'react'

const Dashboard = lazy(() => import('./pages/Dashboard'))
const Settings  = lazy(() => import('./pages/Settings'))

function App() {
  return (
    <Suspense fallback={<PageSpinner />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/settings"  element={<Settings />} />
      </Routes>
    </Suspense>
  )
}
```

## Glob Imports
```ts
// Import all locale files
const locales = import.meta.glob('./locales/*.json', { eager: true })

// Lazy-load route components automatically
const pages = import.meta.glob('./pages/**/*.tsx')
// { './pages/Home.tsx': () => import('./pages/Home.tsx'), ... }
```

## Custom Plugin
```ts
import type { Plugin } from 'vite'

function svgLoader(): Plugin {
  return {
    name: 'svg-loader',
    transform(src, id) {
      if (!id.endsWith('.svg?component')) return
      return {
        code: `import React from 'react'; export default (props) => <svg {...props}>${src}</svg>`,
        map: null,
      }
    },
  }
}
```

## Vitest Config
```ts
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'

export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
    globals: true,
    setupFiles: ['./src/test/setup.ts'],
    coverage: {
      provider: 'v8',
      reporter: ['text', 'html', 'lcov'],
      thresholds: { lines: 80, functions: 80, branches: 80 },
    },
  },
  resolve: {
    alias: { '@': resolve(__dirname, './src') },
  },
})
```

## Vitest Tests
```ts
// src/test/setup.ts
import '@testing-library/jest-dom'

// Component test
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { vi, describe, it, expect } from 'vitest'

describe('Button', () => {
  it('calls onClick when clicked', async () => {
    const user    = userEvent.setup()
    const onClick = vi.fn()
    render(<Button onClick={onClick}>Click me</Button>)
    await user.click(screen.getByRole('button'))
    expect(onClick).toHaveBeenCalledOnce()
  })
})
```

## Build Analysis
```ts
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    react(),
    visualizer({ open: true, gzipSize: true }),  // generates stats.html
  ],
})
```

## Multi-Page App
```ts
export default defineConfig({
  build: {
    rollupOptions: {
      input: {
        main:    resolve(__dirname, 'index.html'),
        admin:   resolve(__dirname, 'admin/index.html'),
        widget:  resolve(__dirname, 'widget/index.html'),
      },
    },
  },
})
```

## Library Mode
```ts
export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'),
      name: 'MyLib',
      formats: ['es', 'cjs'],
      fileName: (format) => `my-lib.${format}.js`,
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: { react: 'React', 'react-dom': 'ReactDOM' },
      },
    },
  },
})
```

