| |

React 3 ⚛️ Creating a Project with Vite

Vite is the build tool that the React ecosystem now recommends for new projects. It was created by Evan You, the creator of Vue, and it replaces the older Create React App (CRA) tooling that was the standard for years. The difference is dramatic: CRA’s dev server takes roughly 15 seconds to start, while Vite’s starts in under 3 seconds. Hot Module Replacement in CRA takes 1–3 seconds; in Vite it is under 100 milliseconds . The React documentation itself now suggests using a framework like Next.js or a tool like Vite instead of CRA .

The reason Vite is fast is architectural. CRA uses Webpack, which bundles the entire application before serving it. Vite uses native ES modules during development: the browser requests modules on demand, and Vite transforms them one at a time. The dev server starts immediately because there is no bundle to build. Production builds use Rollup for optimized output .

Key point: Vite is not a React-specific tool. It supports Vue, Svelte, Solid, Lit, Preact, and plain JavaScript. The React template is one of many. When you scaffold a project with Vite, you are choosing a build tool that happens to have excellent React support, not a React-specific framework. This distinction matters because the configuration you learn in a Vite project — the index.html entry point, the vite.config.ts file, the src/ folder structure — is Vite’s, not React’s.


Why Vite Exists

The React ecosystem has gone through several build tool generations. Each one solved a problem the previous one had, and each one introduced its own trade-offs.

The Webpack problem. Create React App wrapped Webpack in a zero-configuration package. It worked, but Webpack’s cold-start time grows with the project. A large application could take 15 seconds or more before the dev server was ready. HMR was slow because Webpack had to rebuild the changed chunk and propagate the update through the bundle graph .

The ESM problem. Modern browsers support ES modules natively. A <script type="module"> tag can import other modules, and the browser fetches them over the network. Vite exploits this: instead of bundling everything into one file, it serves the source files as ES modules. The browser requests App.jsx, Vite transforms it, and the browser executes it. The first request is slow, but subsequent requests are cached by the browser .

The maintenance problem. Create React App is effectively unmaintained. Facebook stopped investing in it, and the React documentation now points users to Vite, Next.js, and other alternatives . New projects that use CRA start with deprecated tooling.

The trade-off. Vite’s development model requires the browser to support ES modules. All modern browsers do. It also requires the network to fetch many small files instead of one large bundle. On localhost, this is fast. On a remote dev server, the network latency could matter. Vite’s production build uses Rollup to create optimized bundles, so the deployed application does not have this problem .


a. Scaffolding the Project

The npm create vite@latest command is the entry point. It downloads the create-vite package, prompts for a project name and a template, and scaffolds the project .

The interactive form asks for the project name and the framework. The --template flag skips the prompts and specifies the template directly.

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

The command scaffolds a React project with JavaScript. The react-ts template scaffolds a React project with TypeScript . The react-swc and react-swc-ts templates use SWC instead of Babel for faster compilation .

After the scaffold, the project has this structure :

my-react-app/
├── node_modules/
├── public/
├── src/
│   ├── assets/
│   ├── App.css
│   ├── App.jsx
│   ├── index.css
│   └── main.jsx
├── .gitignore
├── index.html
├── package.json
├── vite.config.js
└── README.md

The index.html file is at the root of the project, not inside public/. This is a Vite convention. In CRA, index.html lives in public/ and uses %PUBLIC_URL% placeholders. In Vite, index.html is the entry point, and URLs are automatically rebased relative to the project root .

The src/ directory contains the application code. The main.jsx file is the entry point that mounts the React application. The App.jsx file is the root component. The assets/ folder holds static assets that Vite processes .

The public/ directory holds static assets that Vite does not process. A file in public/ is served as-is and can be referenced with an absolute path like /image.png .

The vite.config.js file is the build configuration. A minimal React project has one plugin:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
})

The @vitejs/plugin-react plugin enables React’s Fast Refresh, Vite’s HMR implementation for React .


b. Installing Dependencies and Running the Dev Server

After scaffolding, the dependencies are not installed. The node_modules/ folder does not exist until npm install runs.

cd my-react-app
npm install

The npm install command reads package.json, resolves the dependency tree, downloads the packages, and writes package-lock.json. The React and React DOM packages are installed as runtime dependencies. The Vite plugin and Vite itself are installed as development dependencies .

The npm run dev command starts the dev server:

npm run dev

The output shows the local URL:

VITE v5.4.0  ready in 300 ms
➜  Local:   http://localhost:5173/

The server starts in milliseconds, not seconds. The browser can open the URL immediately. The first page load is slightly slower because Vite transforms the modules on demand, but subsequent loads are cached .

When a source file changes, Vite sends only the changed module to the browser. The browser replaces the module without reloading the page. The component state is preserved. This is HMR, and it is what makes the development loop feel instant .

The npm run build command produces the production bundle:

npm run build

The output goes to the dist/ folder. The build uses Rollup, which tree-shakes the code, minifies it, and splits it into chunks. The production bundle is optimized for size and loading speed .

The npm run preview command serves the production build locally, so you can verify it before deploying:

npm run preview

The command starts a local server that serves the dist/ folder. It is not a production server — it is a preview tool. The deployed application should be served by a static file server or a CDN .


c. The Project Structure and Configuration

The Vite project structure is intentionally minimal. Vite adds no files you do not need. The structure is the application’s structure, not the tool’s.

The index.html file is the entry point. It contains a <div id="root"></div> and a <script type="module" src="/src/main.jsx"></script> tag. The script tag points to the React entry point .

The src/main.jsx file is the React entry point. It imports React, React DOM, and the root component, and it calls createRoot() to mount the application:

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import './index.css'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

The App.jsx file is the root component. The index.css file is the global stylesheet. The App.css file is the component-specific stylesheet .

The vite.config.js file is the configuration. A minimal React project needs only the React plugin. For larger projects, the configuration grows: path aliases, proxy settings, environment variables, and additional plugins .

The environment variables in a Vite project use the VITE_ prefix. Only variables with this prefix are exposed to the client code. They are accessed with import.meta.env.VITE_API_URL instead of process.env.REACT_APP_API_URL . The change is not just a rename: process.env is a Node.js API, and import.meta.env is a Vite API. The two are different mechanisms with different behaviors.


Complete Example Session

This session scaffolds a React project with Vite, installs dependencies, runs the dev server, and builds for production.

# ============================================
# PART 1: SCAFFOLD THE PROJECT
# ============================================

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

# Output:
# Scaffolding project in /path/to/my-react-app...
# Done. Now run:
#   cd my-react-app
#   npm install
#   npm run dev

# ============================================
# PART 2: EXPLORE THE STRUCTURE
# ============================================

cd my-react-app
ls -la

# Output:
# drwxr-xr-x  node_modules (missing until npm install)
# drwxr-xr-x  public
# drwxr-xr-x  src
# -rw-r--r--  .gitignore
# -rw-r--r--  index.html
# -rw-r--r--  package.json
# -rw-r--r--  vite.config.js

ls src/

# Output:
# App.css
# App.jsx
# assets
# index.css
# main.jsx

# ============================================
# PART 3: VIEW THE PACKAGE.JSON
# ============================================

cat package.json

# Output:
# {
#   "name": "my-react-app",
#   "private": true,
#   "version": "0.0.0",
#   "type": "module",
#   "scripts": {
#     "dev": "vite",
#     "build": "vite build",
#     "lint": "eslint .",
#     "preview": "vite preview"
#   },
#   "dependencies": {
#     "react": "^18.3.1",
#     "react-dom": "^18.3.1"
#   },
#   "devDependencies": {
#     "@vitejs/plugin-react": "^4.3.1",
#     "vite": "^5.4.0"
#   }
# }

# The scripts are the core commands:
# dev → start the dev server
# build → build for production
# preview → serve the production build

# ============================================
# PART 4: INSTALL DEPENDENCIES
# ============================================

npm install

# Output:
# added 45 packages, and audited 46 packages in 2s
# found 0 vulnerabilities

# The node_modules folder is created.
# The package-lock.json file is written.

# ============================================
# PART 5: START THE DEV SERVER
# ============================================

npm run dev

# Output:
# VITE v5.4.0  ready in 300 ms
# ➜  Local:   http://localhost:5173/
# ➜  Network: use --host to expose

# The server starts in 300 ms.
# Open http://localhost:5173/ in a browser.

# ============================================
# PART 6: HOT MODULE REPLACEMENT
# ============================================

# Edit src/App.jsx
# Change the text inside the <h1> tag.

# Before:
# <h1>Vite + React</h1>

# After:
# <h1>My first Vite app</h1>

# Save the file.
# The browser updates the text without a full reload.
# The component state is preserved.

# ============================================
# PART 7: BUILD FOR PRODUCTION
# ============================================

npm run build

# Output:
# vite v5.4.0 building for production...
# ✓ 34 modules transformed.
# dist/index.html                   0.46 kB
# dist/assets/index-abc123.js     143.21 kB
# ✓ built in 1.2s

# The production bundle is in dist/.
# The bundle is minified, tree-shaken, and split.

# ============================================
# PART 8: PREVIEW THE PRODUCTION BUILD
# ============================================

npm run preview

# Output:
# ➜  Local:   http://localhost:4173/

# The preview server serves the dist/ folder.
# Verify the production build before deploying.

# ============================================
# PART 9: ADD A PATH ALIAS
# ============================================

# vite.config.js
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'),
    },
  },
})

# The @ alias maps to ./src.
# Import with: import Button from '@/components/Button'

# ============================================
# PART 10: THE DEVELOPMENT WORKFLOW
# ============================================

# 1. Scaffold with npm create vite@latest
# 2. Install with npm install
# 3. Run with npm run dev
# 4. Edit with HMR
# 5. Build with npm run build
# 6. Preview with npm run preview
# 7. Deploy the dist/ folder

The ten parts cover scaffolding the project, exploring the structure, viewing the package.json, installing dependencies, starting the dev server, Hot Module Replacement, building for production, previewing the production build, adding a path alias, and the development workflow.


Quick Reference

The Vite Commands

CommandPurpose
npm create vite@latestScaffold a new project
npm installInstall dependencies
npm run devStart the dev server
npm run buildBuild for production
npm run previewPreview the production build

The React Templates

TemplateLanguageCompiler
reactJavaScriptBabel
react-tsTypeScriptBabel
react-swcJavaScriptSWC
react-swc-tsTypeScriptSWC

The Project Structure

PathPurpose
index.htmlEntry point (root, not public/)
src/main.jsxReact entry point
src/App.jsxRoot component
src/assets/Processed static assets
public/Unprocessed static assets
vite.config.jsBuild configuration

The Environment Variables

CRAVite
process.env.REACT_APP_*import.meta.env.VITE_*
Only REACT_APP_ exposedOnly VITE_ exposed
Node.js APIVite API

Best Practices

✅ Do This:

# Use the React template
npm create vite@latest my-app -- --template react                # ✅
# Use SWC for faster builds
npm create vite@latest my-app -- --template react-swc            # ✅
# Use the preview command before deploying
npm run preview                                                  # ✅
// Use import.meta.env for environment variables
const apiUrl = import.meta.env.VITE_API_URL                      // ✅
// Use path aliases for clean imports
alias: { '@': path.resolve(__dirname, './src') }                 // ✅

❌ Don’t Do This:

# Don't use Create React App for new projects
npx create-react-app my-app  # deprecated                       # ❌
// Don't use process.env in Vite
const apiUrl = process.env.REACT_APP_API_URL  // does not work    // ❌
# Don't put index.html in public/
# It belongs in the project root                                  // ❌
# Don't serve the preview server in production
npm run preview  # not for production                            // ❌

Common Pitfalls

PitfallWhy It HappensFix
process.env undefinedVite uses import.meta.envUse the Vite syntax
index.html not foundWrong locationMove to project root
Slow first loadVite transforms on demandSubsequent loads are fast
Build output missingNo npm run buildRun the build command
Env vars not exposedMissing VITE_ prefixPrefix with VITE_

Real-World Examples

1. Scaffold a Project

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

2. Scaffold with TypeScript

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

3. Install Dependencies

npm install

4. Run the Dev Server

npm run dev

5. Build for Production

npm run build

6. Preview the Build

npm run preview

7. Add a Plugin

plugins: [react()]                                               // in vite.config.js

8. Add a Path Alias

alias: { '@': path.resolve(__dirname, './src') }                 // in vite.config.js

9. Use an Environment Variable

const apiUrl = import.meta.env.VITE_API_URL                      // in source code

10. Serve the Build

# Deploy the dist/ folder to any static host

Visual

Vite vs CRA

┌──────────────────────────────────────────────┐
│  VITE vs CRA                                 │
│                                              │
│  Dev server startup:                         │
│    CRA  ████████████████████ (15s)           │
│    Vite ████ (3s)                            │
│                                              │
│  HMR speed:                                  │
│    CRA  ████████████ (1-3s)                  │
│    Vite █ (100ms)                            │
│                                              │
│  Maintenance:                                │
│    CRA  🔴 Deprecated                        │
│    Vite 🟢 Active                            │
│                                              │
└──────────────────────────────────────────────┘

The Project Structure

┌──────────────────────────────────────────────┐
│  my-react-app/                               │
│  ├── node_modules/                           │
│  ├── public/          ← unprocessed assets   │
│  ├── src/             ← application code     │
│  │   ├── assets/      ← processed assets     │
│  │   ├── App.css      ← component styles     │
│  │   ├── App.jsx      ← root component       │
│  │   ├── index.css    ← global styles        │
│  │   └── main.jsx     ← entry point          │
│  ├── index.html       ← entry HTML           │
│  ├── package.json     ← dependencies         │
│  └── vite.config.js   ← build config         │
│                                              │
└──────────────────────────────────────────────┘

The Development Workflow

┌──────────────────────────────────────────────┐
│  1. npm create vite@latest                   │
│  2. cd my-react-app                          │
│  3. npm install                              │
│  4. npm run dev                              │
│  5. Edit code (HMR updates instantly)        │
│  6. npm run build                            │
│  7. npm run preview                          │
│  8. Deploy dist/                             │
│                                              │
└──────────────────────────────────────────────┘

The Environment Variables

┌──────────────────────────────────────────────┐
│  CRA                    VITE                 │
│  ───                    ────                 │
│  process.env            import.meta.env      │
│  REACT_APP_API_URL      VITE_API_URL         │
│                                              │
│  Only REACT_APP_        Only VITE_           │
│  prefixed vars          prefixed vars        │
│  are exposed            are exposed          │
│                                              │
│  The two mechanisms are different.           │
│                                              │
└──────────────────────────────────────────────┘

Summary

ItemValue
Scaffold commandnpm create vite@latest my-app -- --template react
Dev servernpm run dev
Production buildnpm run build
Previewnpm run preview
Entry pointindex.html at project root
React entrysrc/main.jsx
Root componentsrc/App.jsx
Config filevite.config.js
Env variablesimport.meta.env.VITE_*
CRA statusDeprecated

Key takeaways:

  • Vite is the modern replacement for Create React App. CRA is deprecated and unmaintained. Vite’s dev server starts in under 3 seconds, and its HMR is nearly instantaneous. The React documentation recommends Vite for new projects .
  • The npm create vite@latest command scaffolds a project. The --template react flag skips the interactive prompts. The react-ts template scaffolds a TypeScript project. The react-swc template uses SWC for faster compilation .
  • The index.html file is at the project root, not in public/. Vite treats index.html as the entry point and part of the module graph. URLs inside it are automatically rebased relative to the project root .
  • The src/ directory contains the application code. main.jsx is the entry point that mounts React. App.jsx is the root component. assets/ holds processed static files. public/ holds unprocessed static files .
  • The vite.config.js file configures the build. The @vitejs/plugin-react plugin enables React Fast Refresh. Path aliases, proxy settings, and additional plugins are added here .
  • Environment variables use the VITE_ prefix. They are accessed with import.meta.env.VITE_* instead of process.env.REACT_APP_*. The two mechanisms are different: import.meta.env is a Vite API, not a Node.js API .
  • The development workflow is: scaffold, install, run, edit, build, preview, deploy. Vite handles the tooling. React handles the UI. The dist/ folder is the production artifact.

Remember: Vite is the build tool. React is the library. The npm create vite@latest command scaffolds the project. The npm run dev command starts the server. The HMR updates the browser without a reload. The npm run build command produces the production bundle. The index.html is at the root. The src/ folder holds the code. The vite.config.js file holds the configuration. The VITE_ prefix exposes environment variables. Vite replaces CRA. The dev server is fast. The build is optimized. The workflow is modern.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!