Vite is the modern build tool for React applications, replacing Create React App in most new projects. Where CRA bundles all your code on startup (slow for large projects), Vite serves files directly as native ES modules during development — the browser loads only what it needs, when it needs it. The result is a development server that starts in under a second regardless of project size, with hot module replacement (HMR) that applies code changes in milliseconds without a full page reload. For production, Vite uses Rollup to bundle everything efficiently.
Creating a React + Vite Project
# Create a new React project with Vite
npm create vite@latest blog-frontend -- --template react
# Or with TypeScript (recommended for larger projects):
npm create vite@latest blog-frontend -- --template react-ts
cd blog-frontend
npm install
npm run dev # starts dev server at http://localhost:5173
# Project structure:
# blog-frontend/
# ├── index.html ← entry point (Vite serves this)
# ├── src/
# │ ├── main.jsx ← mounts React app into index.html
# │ ├── App.jsx ← root component
# │ ├── App.css
# │ └── assets/
# ├── public/ ← static files (copied as-is to dist/)
# ├── vite.config.js ← Vite configuration
# └── package.json
.jsx (or .tsx) for files containing JSX and .js (or .ts) for plain JavaScript. You must use the correct extension — Vite will not process JSX syntax in a .js file by default. If you see “Unexpected token” errors when using JSX, the first thing to check is whether the file has the .jsx extension.vite.config.js to forward API requests to your FastAPI backend during development. With proxy: {"/api": "http://localhost:8000"}, a browser request to /api/posts is forwarded to http://localhost:8000/api/posts. This avoids CORS issues during development and means you do not need to hardcode the backend URL in your frontend code — the proxy is only active in development; production uses a real reverse proxy (Nginx).public/ directory is for static assets that should be served at the root URL without processing (favicons, robots.txt, manifest files). Files in src/assets/ are imported directly in JavaScript and processed by Vite (hashed filenames, optimised). Use public/ for files that need a stable URL; use src/assets/ for images and fonts referenced in components.Vite Configuration for the Blog Application
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";
export default defineConfig({
plugins: [react()],
// Path alias — @/ maps to src/ for cleaner imports
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
// Dev server configuration
server: {
port: 5173,
// Proxy API requests to FastAPI backend
proxy: {
"/api": {
target: "http://localhost:8000",
changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, ""),
// Uncomment if FastAPI routes don't have /api prefix
},
"/uploads": {
target: "http://localhost:8000",
changeOrigin: true,
},
},
},
// Build configuration
build: {
outDir: "dist",
sourcemap: true, // source maps for debugging
rollupOptions: {
output: {
manualChunks: {
// Split vendor code for better caching
vendor: ["react", "react-dom"],
},
},
},
},
});
The Entry Point and Root Component
// index.html — Vite's entry point
// <!DOCTYPE html>
// <html lang="en">
// <body>
// <div id="root"></div> ← React mounts here
// <script type="module" src="/src/main.jsx"></script>
// </body>
// </html>
// src/main.jsx — mounts the React app
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.jsx";
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>
);
// StrictMode: enables extra development warnings and double-invokes
// lifecycle methods to detect side effects — remove for production profiling
// src/App.jsx — root component
export default function App() {
return (
<div className="app">
<h1>Blog Application</h1>
</div>
);
}
Common Mistakes
Mistake 1 — Using .js extension for files containing JSX
❌ Wrong:
src/components/PostCard.js # contains JSX — Vite gives syntax error!
✅ Correct:
src/components/PostCard.jsx # ✓ .jsx extension for files with JSX
Mistake 2 — Importing with wrong path after setting alias
❌ Wrong — relative path from deep in the tree:
import PostCard from "../../../components/PostCard" // fragile path!
✅ Correct — use the @/ alias:
import PostCard from "@/components/PostCard" // ✓ always from src root
Mistake 3 — Running npm run build instead of npm run dev during development
❌ Wrong — build creates a production bundle (slow, no HMR).
✅ Correct — npm run dev for development (fast HMR), npm run build only for production deployment.
Quick Reference
| Task | Command / File |
|---|---|
| Create project | npm create vite@latest name -- --template react |
| Start dev server | npm run dev → http://localhost:5173 |
| Production build | npm run build → dist/ |
| Preview production | npm run preview |
| Config file | vite.config.js |
| Path alias | resolve.alias: {"@": path.resolve(__dirname, "src")} |
| API proxy | server.proxy: {"/api": "http://localhost:8000"} |