JavaScript 6 min read

Vite + React: Modern Frontend Development Setup

Master Vite for React development. Learn project setup, configuration, plugins, environment variables, and production optimization.

MR

Moshiour Rahman

Advertisement

What is Vite?

Vite is a modern frontend build tool that provides an extremely fast development experience. It leverages native ES modules and provides lightning-fast Hot Module Replacement (HMR).

Vite vs Traditional Bundlers

Traditional (Webpack)Vite
Bundle first, then serveServe source files directly
Slow cold startInstant server start
Full rebuild on changesPrecise HMR updates
Complex configurationMinimal config needed

Getting Started

Create New Project

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

# yarn
yarn create vite my-app --template react-ts

# pnpm
pnpm create vite my-app --template react-ts

cd my-app
npm install
npm run dev

Available Templates

# Vanilla
npm create vite@latest my-app -- --template vanilla
npm create vite@latest my-app -- --template vanilla-ts

# React
npm create vite@latest my-app -- --template react
npm create vite@latest my-app -- --template react-ts
npm create vite@latest my-app -- --template react-swc
npm create vite@latest my-app -- --template react-swc-ts

# Vue
npm create vite@latest my-app -- --template vue
npm create vite@latest my-app -- --template vue-ts

# Svelte
npm create vite@latest my-app -- --template svelte
npm create vite@latest my-app -- --template svelte-ts

Project Structure

my-app/
├── public/
│   └── favicon.ico
├── src/
│   ├── assets/
│   │   └── logo.svg
│   ├── components/
│   │   └── Button.tsx
│   ├── App.tsx
│   ├── App.css
│   ├── main.tsx
│   └── vite-env.d.ts
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

Configuration

Basic Configuration

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

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
    open: true,
    cors: true
  },
  build: {
    outDir: 'dist',
    sourcemap: true
  }
});

Path Aliases

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

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
      '@hooks': path.resolve(__dirname, './src/hooks'),
      '@utils': path.resolve(__dirname, './src/utils'),
      '@assets': path.resolve(__dirname, './src/assets')
    }
  }
});
// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@hooks/*": ["src/hooks/*"],
      "@utils/*": ["src/utils/*"],
      "@assets/*": ["src/assets/*"]
    }
  }
}
// Usage
import { Button } from '@components/Button';
import { useAuth } from '@hooks/useAuth';
import { formatDate } from '@utils/date';

Proxy Configuration

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

Environment Variables

Define Variables

# .env
VITE_APP_TITLE=My App
VITE_API_URL=https://api.example.com

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

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

# .env.local (not committed to git)
VITE_SECRET_KEY=my-secret

Use Variables

// Access in code
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
const mode = import.meta.env.MODE;

// TypeScript definitions
// src/vite-env.d.ts
/// <reference types="vite/client" />

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

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

Plugins

Essential Plugins

npm install -D @vitejs/plugin-react-swc
npm install -D vite-plugin-svgr
npm install -D vite-plugin-compression
npm install -D vite-tsconfig-paths
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import svgr from 'vite-plugin-svgr';
import compression from 'vite-plugin-compression';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  plugins: [
    react(),
    tsconfigPaths(),
    svgr({
      svgrOptions: {
        icon: true
      }
    }),
    compression({
      algorithm: 'gzip',
      ext: '.gz'
    })
  ]
});

SVG as React Components

// With vite-plugin-svgr
import { ReactComponent as Logo } from './logo.svg';
// or
import Logo from './logo.svg?react';

function App() {
  return <Logo className="logo" />;
}

PWA Plugin

npm install -D vite-plugin-pwa
// vite.config.ts
import { VitePWA } from 'vite-plugin-pwa';

export default defineConfig({
  plugins: [
    react(),
    VitePWA({
      registerType: 'autoUpdate',
      manifest: {
        name: 'My App',
        short_name: 'App',
        theme_color: '#ffffff',
        icons: [
          {
            src: '/icon-192.png',
            sizes: '192x192',
            type: 'image/png'
          },
          {
            src: '/icon-512.png',
            sizes: '512x512',
            type: 'image/png'
          }
        ]
      }
    })
  ]
});

CSS Handling

CSS Modules

// Button.module.css
.button {
  padding: 10px 20px;
  border-radius: 4px;
}

.primary {
  background: blue;
  color: white;
}

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

function Button({ variant = 'primary', children }) {
  return (
    <button className={`${styles.button} ${styles[variant]}`}>
      {children}
    </button>
  );
}

Tailwind CSS

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
// tailwind.config.js
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

Sass/SCSS

npm install -D sass
// styles.scss
$primary-color: #007bff;

.button {
  background: $primary-color;

  &:hover {
    background: darken($primary-color, 10%);
  }
}

Build Optimization

Code Splitting

// vite.config.ts
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          router: ['react-router-dom'],
          ui: ['@mui/material', '@emotion/react']
        }
      }
    }
  }
});

Lazy Loading

import { lazy, Suspense } from 'react';

// Lazy load components
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));

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

Asset Optimization

// vite.config.ts
export default defineConfig({
  build: {
    assetsInlineLimit: 4096, // Inline assets < 4kb
    cssCodeSplit: true,
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    }
  }
});

Bundle Analysis

npm install -D rollup-plugin-visualizer
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';

export default defineConfig({
  plugins: [
    react(),
    visualizer({
      filename: 'dist/stats.html',
      open: true,
      gzipSize: true
    })
  ]
});

Testing Setup

Vitest

npm install -D vitest @testing-library/react @testing-library/jest-dom jsdom
// 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',
    css: true
  }
});
// src/test/setup.ts
import '@testing-library/jest-dom';
// Button.test.tsx
import { render, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import Button from './Button';

describe('Button', () => {
  it('renders correctly', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByRole('button')).toHaveTextContent('Click me');
  });
});

Deployment

Static Hosting

// vite.config.ts for GitHub Pages
export default defineConfig({
  base: '/repo-name/', // Set base path
});

// Build
npm run build

// Deploy dist folder

Docker

# Dockerfile
FROM node:20-alpine as build

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# nginx.conf
server {
    listen 80;
    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /assets {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Summary

FeatureCommand/Config
Dev servernpm run dev
Buildnpm run build
Previewnpm run preview
Env varsVITE_* prefix
Aliasesresolve.alias
Proxyserver.proxy

Vite provides the fastest and most enjoyable development experience for modern React applications.

Advertisement

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.