Build and Deployment
|
This section documents React 19.x for the web, using function components and Hooks throughout (class components appear only where React still requires them, such as error boundaries). React Native is out of scope and gets only a pointer. The React 19 additions follow the current official React documentation. This content was generated with the assistance of AI and should be verified against react.dev before being relied on in production, since React APIs continue to evolve between releases. This section’s bibliography lists the reference material consulted while preparing these pages. |
A React app ships as static assets, a running server, or both. This page covers bundling with Vite and the three deployment shapes, with a worked static-SPA deploy.
Bundling
A bundler walks the module graph from your entry point, applies transforms (JSX → JS, TypeScript
stripping), removes unused exports (tree-shaking), minifies, splits code into chunks, and writes
content-hashed filenames (app.9f3a1c.js) so browsers can cache aggressively and still get updates.
Vite is the default toolchain: an esbuild-based dev server with hot module replacement, and Rollup for the production build.
npm run build # -> dist/ (index.html + hashed assets)
npm run preview # serve dist/ locally to sanity-check
-
Dynamic
import()becomes a separate chunk loaded on demand — the mechanism behind code splitting. -
import.meta.envexposes build-time config; only variables prefixedVITE_are sent to the client. -
Source maps (
build.sourcemap: true) map minified stack traces back to your source; upload them to your error tracker rather than serving them publicly.
References: Vite: Building for Production, Build a React App from Scratch.
Three deployment models
-
(a) SPA / static build — upload
dist/to any static host or CDN (Netlify, Vercel, GitHub Pages, S3
CloudFront). Configure a SPA fallback: rewrite unknown paths to/index.htmlso client-side routes work on refresh. No server. Best for dashboards, internal tools, auth-gated apps where SEO does not matter. -
(b) SSR — a long-running Node or edge server calls
renderToPipeableStreamper request (or use a platform like Vercel/Netlify that runs your framework’s server for you). Best when pages are dynamic, per-user, and need fast first paint or SEO. See Server Rendering. -
(c) SSG / prerender — render HTML per route at build time and serve the files statically, optionally revalidating (ISR). Best for content that changes rarely.
Worked example B — a Vite React SPA on AWS S3 + CloudFront
A client-rendered SPA that calls a REST API with fetch/axios, built to static files and served from S3
behind CloudFront. No server-side rendering, so no server to run.
# 1. build
npm run build
# dist/index.html
# dist/assets/index-4e9b12.js
# dist/assets/index-9a1f77.css
# 2. deploy: hashed assets get a long cache; index.html must not be cached
aws s3 sync dist/ s3://my-app-bucket --delete \
--cache-control "public,max-age=31536000,immutable" \
--exclude index.html
aws s3 cp dist/index.html s3://my-app-bucket/index.html \
--cache-control "no-cache"
# 3. invalidate the CDN so index.html is refetched
aws cloudfront create-invalidation --distribution-id E123ABC --paths "/index.html"
CloudFront config: set the default root object to index.html, and add a custom error response
mapping 403/404 to /index.html with a 200 status so deep links like /reports/42 load the SPA and let
the client router take over. The API lives on its own origin, so it must send
CORS headers for the SPA’s domain.
// the SPA just calls the API over the network
const res = await fetch(`${import.meta.env.VITE_API_URL}/products/42`);
const product = await res.json();
CI/CD and environment variables
-
CI/CD — on push, install, run tests and type-check,
npm run build, then publish: uploaddist/(SPA/ SSG) or deploy the server image (SSR). Keep the build reproducible (lockfile, pinned Node). -
Build-time vs. run-time env — anything in
import.meta.env.VITE_*is baked into the bundle at build and visible to users; never put secrets there. Runtime secrets belong on the server (SSR) or in the API, not the client bundle. Rebuild to change a build-time value.