Build, Preview, and Deploy

Introduction

Vite builds your React app into static files in dist/—HTML, JavaScript, CSS, and assets ready for Netlify, Vercel, OSS, or Nginx. This chapter covers npm run build, environment modes, assets, history-mode SPA deployment, and API/CORS in production.

Prerequisites

Production Build

bash
npm run build

Output:

text
dist/
├── index.html
├── assets/
│   ├── index-a1b2c3.js
│   └── index-d4e5f6.css
└── vite.svg

Preview locally:

bash
npm run preview

Verify routes like /posts/demo work before upload—preview serves dist/ with SPA fallback behavior similar to production hosts.

Code explanation:

  • Hashed filenames enable long-term caching
  • index.html references hashed assets automatically

Parallel guide: Vue Build and Deploy.

Environment Modes

FileLoaded when
.envAll modes
.env.developmentnpm run dev
.env.productionnpm run build

.env.production:

env
VITE_API_URL=https://api.example.com

Or use relative /api with Nginx proxy—no CORS in browser.

typescript
const apiUrl = import.meta.env.VITE_API_URL ?? "";
const isProd = import.meta.env.PROD;

Only VITE_* variables are exposed—never put secrets in client env vars.

Public vs Assets

DirectoryBehavior
public/Copied to dist/ root (/favicon.ico)
src/assets/Imported in components; hashed in build
tsx
import logo from "./assets/logo.svg";
 
<img src={logo} alt="Logo" />
html
<link rel="icon" href="/favicon.ico" />

Code Splitting

Lazy routes create separate chunks:

tsx
const Dashboard = lazy(() => import("./pages/DashboardPage"));

Inspect dist/assets/ after build—each lazy page adds a chunk.

Deploy Static SPA

Netlify / Vercel

Connect Git repo; build command npm run build; publish directory dist.

Add redirect for client-side routing:

text
/*    /index.html   200

(Netlify _redirects or Vercel vercel.json)

Nginx

try_files fixes 404 on refresh for /dashboard paths.

Full Nginx track: What Is Nginx.

API in Production

SetupConfig
Same domain Nginx proxyVITE_API_URL= empty; fetch /api/...
Separate API subdomainBackend CORS + VITE_API_URL=https://api.example.com
Static CDN + APICORS on API; restrict origins

Base Path (Subfolder Deploy)

App at https://example.com/app/:

vite.config.ts:

typescript
export default defineConfig({
  base: "/app/",
  plugins: [react()],
});

Router:

tsx
createBrowserRouter(routes, { basename: "/app" });

Build Checklist

  • npm run build succeeds
  • npm run preview — home and deep links work
  • Production VITE_API_URL or proxy configured
  • No secrets in VITE_* vars
  • Favicon and public/ assets present

Docker multi-stage build: React Docker and CI.

FAQ

Blank page after deploy?

Wrong base path or assets 404—check browser Network tab.

Old bundle cached?

Hashed assets cache safely; index.html should not be cached aggressively during deploys.

Source maps?

Default in build—disable for public repos if concerned: build.sourcemap: false.

Environment per staging?

.env.staging + vite build --mode staging.

Next chapter?

SSR and Next.js Intro.