vite

Vite Config for React

Vite configuration for React projects with path aliases, proxy setup, build optimization, and environment variable handling.

Overview

A Vite configuration for React projects with TypeScript. Includes path alias resolution, API proxy for development, build optimization with code splitting, environment variable handling, and testing setup with Vitest.

Configuration

// vite.config.ts

import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import path from "node:path";

export default defineConfig(({ mode }) => {
  // Load environment variables based on mode (development, production)
  const env = loadEnv(mode, process.cwd(), "");

  return {
    // ── Plugins ──
    plugins: [
      react({
        // Use the automatic JSX runtime (no need to import React)
        jsxRuntime: "automatic",
      }),
    ],

    // ── Path Aliases ──
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "./src"),
        "@components": path.resolve(__dirname, "./src/components"),
        "@lib": path.resolve(__dirname, "./src/lib"),
        "@hooks": path.resolve(__dirname, "./src/hooks"),
        "@assets": path.resolve(__dirname, "./src/assets"),
      },
    },

    // ── Dev Server ──
    server: {
      port: 3000,                      // Dev server port
      open: true,                      // Open browser on start
      strictPort: true,                // Fail if port is in use

      // Proxy API requests to backend during development
      proxy: {
        "/api": {
          target: env.VITE_API_URL || "http://localhost:8000",
          changeOrigin: true,          // Change Origin header to target
          secure: false,               // Allow self-signed certs
          rewrite: (path) => path,     // Keep /api prefix (or remove it)
        },
        "/ws": {
          target: "ws://localhost:8000",
          ws: true,                    // WebSocket proxy
        },
      },

      // CORS settings for development
      cors: true,
    },

    // ── Build Configuration ──
    build: {
      outDir: "dist",                  // Output directory
      sourcemap: mode === "production" ? "hidden" : true,  // Hidden in prod
      target: "es2020",                // Browser target

      // Code splitting configuration
      rollupOptions: {
        output: {
          manualChunks: {
            // Split vendor libraries into separate chunks
            "react-vendor": ["react", "react-dom"],
            "router": ["react-router-dom"],
          },
        },
      },

      // Chunk size warning threshold
      chunkSizeWarningLimit: 500,      // KB

      // Minification
      minify: "esbuild",              // Fast minification (or "terser" for smaller output)

      // CSS code splitting
      cssCodeSplit: true,
    },

    // ── Preview Server (serves production build locally) ──
    preview: {
      port: 4173,
      strictPort: true,
    },

    // ── CSS Configuration ──
    css: {
      devSourcemap: true,              // CSS source maps in dev

      modules: {
        localsConvention: "camelCase", // .my-class becomes styles.myClass
      },
    },

    // ── Environment Variables ──
    // Only variables prefixed with VITE_ are exposed to client code
    envPrefix: "VITE_",

    // ── Dependency Optimization ──
    optimizeDeps: {
      include: [
        "react",
        "react-dom",
        "react-router-dom",
      ],
    },

    // ── Test Configuration (Vitest) ──
    test: {
      globals: true,                   // Use global test/describe/expect
      environment: "jsdom",            // Simulate browser environment
      setupFiles: ["./src/test/setup.ts"],
      include: ["src/**/*.{test,spec}.{ts,tsx}"],
      coverage: {
        provider: "v8",
        reporter: ["text", "lcov", "html"],
        exclude: ["node_modules/", "src/test/"],
      },
    },
  };
});

Key Options Explained

  • defineConfig(({ mode })) — Function form gives access to the current mode (development or production), enabling conditional configuration.
  • loadEnv(mode, ...) — Loads .env, .env.local, .env.[mode] files. Only VITE_-prefixed variables are exposed to client code for security.
  • proxy — Routes API requests from the dev server to your backend, avoiding CORS issues during development. Not used in production.
  • manualChunks — Splits vendor libraries into separate chunks so they are cached independently. React rarely changes, so it can be cached long-term.
  • sourcemap: "hidden" — Generates source maps for error tracking services (Sentry) but does not reference them in the output files, keeping them private.
  • optimizeDeps.include — Pre-bundles listed dependencies during dev server startup. Prevents slow reloads when Vite encounters new dependencies.
  • test block — Vitest configuration lives alongside Vite config. Shares the same aliases, transforms, and plugin setup.

Common Modifications

  • SWC plugin: Replace @vitejs/plugin-react with @vitejs/plugin-react-swc for faster development builds using SWC instead of Babel.
  • PWA support: Add vite-plugin-pwa for service worker generation and offline support.
  • SVG as components: Add vite-plugin-svgr to import SVGs as React components: import { ReactComponent as Logo } from './logo.svg'.
  • Bundle analysis: Add rollup-plugin-visualizer to generate a treemap of your bundle for size optimization.
  • Base path: Set base: "/my-app/" when deploying to a subdirectory like example.com/my-app/.