Creating a React App with Vite

Every React application starts with a scaffold โ€” a generated project with the correct build tooling, folder structure, and configuration already in place. In the MERN stack, Vite is the standard scaffolding tool for React. It creates a project with a development server that starts in milliseconds, hot module replacement that updates the browser instantly on every save, and a production build pipeline optimised for modern browsers. In this lesson you will scaffold the MERN Blog client, start the development server, and make your first code changes.

Why Vite, Not Create React App?

Vite Create React App (CRA)
Dev server start < 1 second 10โ€“60 seconds on large projects
HMR speed Instant โ€” only updates changed module Full bundle re-compile on changes
Build tool Rollup (production) Webpack
Maintenance Actively maintained Deprecated and unmaintained since 2023
Config vite.config.js โ€” minimal, flexible Ejected or react-scripts โ€” complex
Note: Vite uses native ES modules in development โ€” it serves your source files directly to the browser without bundling them first. The browser resolves imports itself using the type="module" script tag. This is why Vite starts so fast: there is no bundling step at startup. In production, Vite uses Rollup to bundle everything into optimised, minified files.
Tip: Run npm create vite@latest without a project name to be prompted interactively. For the MERN Blog, run it from inside your monorepo root: npm create vite@latest client -- --template react. The --template react flag selects the React JavaScript template. Use --template react-ts for TypeScript if you prefer typed React development.
Warning: Vite’s development server runs on port 5173 by default โ€” different from the Express API server on port 5000. When React makes API calls during development, the browser will trigger CORS checks. Configure the Vite proxy in vite.config.js to forward /api requests to your Express server โ€” this avoids CORS entirely in development and is already set up in the project structure from Chapter 2.

Scaffolding the MERN Blog Client

# Navigate to your monorepo root (mern-blog/)
cd mern-blog

# Scaffold the React client with Vite
npm create vite@latest client -- --template react

# Expected output:
# โœ” Project name: client
# โœ” Package name: client
# Scaffolding project in /mern-blog/client...
# Done.

# Install dependencies
cd client
npm install

# Install core packages for the MERN Blog client
npm install axios react-router-dom

# Start the development server
npm run dev

# Expected output:
# VITE v5.x.x  ready in 312 ms
# โžœ  Local:   http://localhost:5173/
# โžœ  Network: use --host to expose

What Gets Scaffolded

client/
โ”œโ”€โ”€ public/
โ”‚   โ””โ”€โ”€ vite.svg                 โ† static assets served at /
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ assets/
โ”‚   โ”‚   โ””โ”€โ”€ react.svg            โ† imported assets (processed by Vite)
โ”‚   โ”œโ”€โ”€ App.css                  โ† styles for App component
โ”‚   โ”œโ”€โ”€ App.jsx                  โ† root application component
โ”‚   โ”œโ”€โ”€ index.css                โ† global styles
โ”‚   โ””โ”€โ”€ main.jsx                 โ† entry point โ€” mounts React into the DOM
โ”œโ”€โ”€ index.html                   โ† HTML shell โ€” Vite injects the JS bundle here
โ”œโ”€โ”€ vite.config.js               โ† Vite configuration
โ””โ”€โ”€ package.json

Your First Code Change

// src/App.jsx โ€” replace the scaffolded content
function App() {
  return (
    <div className="app">
      <header>
        <h1>MERN Blog</h1>
        <nav>
          <a href="/">Home</a>
          <a href="/about">About</a>
        </nav>
      </header>
      <main>
        <p>Welcome to the MERN Blog. Posts will appear here.</p>
      </main>
    </div>
  );
}

export default App;
Save the file โ†’ Vite detects the change โ†’ HMR updates the browser instantly
No page reload required โ€” the component updates in place within milliseconds

Configuring the Vite Proxy for the Express API

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

export default defineConfig({
  plugins: [react()],
  server: {
    port: 5173,
    proxy: {
      // Forward all /api requests to the Express server during development
      '/api': {
        target:      'http://localhost:5000',
        changeOrigin: true,
      },
    },
  },
});

// With this config:
// fetch('/api/posts') in React โ†’ forwarded to http://localhost:5000/api/posts
// No CORS issues in development โ€” the proxy makes it same-origin
// In production: deploy React to a CDN and configure CORS on Express

npm Scripts in the React Project

{
  "scripts": {
    "dev":     "vite",           // Start dev server at http://localhost:5173
    "build":   "vite build",     // Build for production โ†’ dist/ folder
    "preview": "vite preview",   // Preview the production build locally
    "lint":    "eslint . --ext js,jsx"
  }
}

Common Mistakes

Mistake 1 โ€” Running npm install in the wrong directory

โŒ Wrong โ€” installing React packages in the server directory:

cd mern-blog/server
npm install axios react-router-dom  # wrong directory โ€” installs in server/node_modules

โœ… Correct โ€” always cd into client/ before installing client packages:

cd mern-blog/client
npm install axios react-router-dom  # correct โœ“

Mistake 2 โ€” Using CRA instead of Vite for new projects

โŒ Wrong โ€” starting with the deprecated Create React App:

npx create-react-app client  # deprecated โ€” slow dev server, unmaintained

โœ… Correct โ€” always use Vite for new React projects:

npm create vite@latest client -- --template react  # โœ“ fast, modern

Mistake 3 โ€” Forgetting to configure the Vite proxy

โŒ Wrong โ€” making API calls with the full URL in development:

fetch('http://localhost:5000/api/posts') // hardcoded dev URL โ€” breaks in production

โœ… Correct โ€” use the Vite proxy and relative URLs:

fetch('/api/posts') // relative URL โ†’ proxied to Express in dev, direct in production โœ“

Quick Reference

Task Command
Scaffold React + Vite npm create vite@latest client -- --template react
Install dependencies cd client && npm install
Start dev server npm run dev
Build for production npm run build
Preview production build npm run preview
Dev server port http://localhost:5173

🧠 Test Yourself

You scaffold a Vite React app and configure a proxy for /api pointing to http://localhost:5000. In your React component you call fetch('/api/posts'). Your Express server is running on port 5000. What happens in development?