mrkeyoor.com_
Wed 05 Aug 05:04 UTC
npmCLI & Toolingupdated 05 Aug 2026

vite

Vite is a frontend build tool with two halves: a dev server that serves your source over native ES modules, so it starts near-instantly and hot-swaps single modules instead of rebundling, and a production build command that bundles with Rolldown into optimized static assets. You configure it once in vite.config.ts, framework templates (React, Vue, Svelte, Solid, and more) come from create-vite, and a plugin API extends both halves. It is the default build layer for most frontend work that is not tied to a full-stack framework.

Verdict

The default choice for new frontend builds, and a safe one: fast, well documented, and actively developed with a huge ecosystem. Just treat majors as migrations, not version bumps, since v8 changed the production bundler.

API stability4/5The config surface has been stable since v2 and migration guides ship per major, but majors land yearly and v8 swapped the production bundler to Rolldown, which can break Rollup-specific plugins.
Docs5/5vite.dev covers config reference, plugin and JavaScript APIs, and a migration guide per major; among the best documentation in JS tooling.
Maintenance5/5Backed by the VoidZero team with daily pushes, a yearly major cadence, and a maintained previous-major line (7.3.x alongside 8.x).
Ecosystem5/5The build tool under Vue, Svelte, Solid, Astro, and most React SPA templates; large plugin ecosystem plus compatibility with many Rollup plugins.

Use it if

  • You are starting a SPA or client-rendered app in React, Vue, Svelte, or Solid and want dev-server startup and HMR measured in milliseconds
  • You are migrating off webpack and want a config measured in tens of lines instead of hundreds
  • You ship a JS/TS library and want library mode to emit ESM and CJS builds without hand-rolling a bundler setup
  • You test with Vitest and want one shared config and transform pipeline for app and tests
Skip it if

Setup reality

npm create vite@latest scaffolds a working app in under a minute and the dev server just works. The friction shows up later: Node 20.19+ or 22.12+ is required, CSS preprocessors (sass, less, stylus) are peer deps you install yourself, env vars silently come back undefined unless prefixed VITE_, and dev (unbundled ESM) and build (Rolldown bundle) are different pipelines, so some bugs only reproduce in vite build. Treat the yearly major as a real upgrade: v8 swapped Rollup for Rolldown under the hood.

Patterns

Scaffold a new appscaffold-project

npm create vite@latest my-app -- --template react-ts
cd my-app && npm install && npm run dev

The extra -- is required with npm so the template flag actually reaches create-vite.

Minimal vite.config.tsbase-config

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

export default defineConfig({
  plugins: [react()],
  server: { port: 3000, open: true },
})

defineConfig exists only for IntelliSense; the plain object is the entire config.

Use environment variablesenv-variables

# .env.local
VITE_API_URL=https://api.example.com

// in client code
const url = import.meta.env.VITE_API_URL

Vars without the VITE_ prefix are never exposed to the client, and import.meta.env is replaced statically at build time.

Proxy API calls in devdev-proxy

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
})

The proxy only runs in the dev server; production needs a real reverse proxy or CORS setup.

Add an @ import aliaspath-alias

import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'

export default defineConfig({
  resolve: {
    alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },
  },
})

TypeScript does not read Vite aliases; mirror them in tsconfig paths or editor imports break.

Import many files at onceglob-import

const modules = import.meta.glob('./pages/*.tsx')
for (const path in modules) {
  modules[path]().then((mod) => console.log(path, mod))
}

Lazy by default; pass { eager: true } to inline the imports at build time instead of returning loader functions.

Reference static assetsstatic-assets

import logoUrl from './assets/logo.svg'
// force a URL for any file type
import workletUrl from './worklet.js?url'

Imported assets get content-hashed filenames; files in public/ are served as-is at / and skip hashing.

Build a library instead of an applibrary-mode

import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: 'src/index.ts',
      name: 'MyLib',
      fileName: 'my-lib',
    },
    rollupOptions: { external: ['react', 'react-dom'] },
  },
})

Externalize peer deps yourself or React ends up bundled inside your library.

Build a multi-page appmulti-page-build

import { resolve } from 'node:path'
import { defineConfig } from 'vite'

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

Each page needs its own .html entry; dev-server URLs follow the same directory layout.

Vary config by command or modeconditional-config

import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ command, mode }) => {
  const env = loadEnv(mode, process.cwd(), '')
  return {
    base: command === 'build' ? '/app/' : '/',
    define: { __API__: JSON.stringify(env.API_URL) },
  }
})

process.env is not populated from .env files inside the config file; use loadEnv.

Handle HMR updates manuallyhmr-accept

if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    if (newModule) render(newModule.default)
  })
}

Always guard with import.meta.hot so the block is dead-code-eliminated from production builds.

Check the production build locallypreview-build

npm run build
npm run preview

vite preview serves dist/ locally for smoke testing; it is not a production server.

Alternatives

PackageRegistryPick it when
webpacknpmYou depend on module federation or a mature loader ecosystem with no Vite equivalent
esbuildnpmYou want a raw, scriptable bundler for a library or server code and no dev server
@rspack/corenpmYou want webpack API compatibility with Rust-level build speed