Vite + React: Modern Frontend Development Setup
Master Vite for React development. Learn project setup, configuration, plugins, environment variables, and production optimization.
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 serve | Serve source files directly |
| Slow cold start | Instant server start |
| Full rebuild on changes | Precise HMR updates |
| Complex configuration | Minimal 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
| Feature | Command/Config |
|---|---|
| Dev server | npm run dev |
| Build | npm run build |
| Preview | npm run preview |
| Env vars | VITE_* prefix |
| Aliases | resolve.alias |
| Proxy | server.proxy |
Vite provides the fastest and most enjoyable development experience for modern React applications.
Advertisement
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
React Hooks Complete Guide: useState to Custom Hooks
Master all React hooks from basics to advanced. Learn useState, useEffect, useContext, useReducer, useMemo, useCallback, and create custom hooks.
JavaScriptZustand: Lightweight React State Management Made Simple
Master Zustand for React state management. Learn store creation, async actions, middleware, persistence, and TypeScript integration patterns.
JavaScriptNext.js 14 Tutorial: Complete Guide with App Router
Master Next.js 14 with App Router. Learn server components, data fetching, routing, server actions, and build full-stack React applications.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.