Deployment

This guide covers the three most common deployment targets for Jumbo React Vite. All deployment paths start with the same production build command.

Building for production

bash
pnpm build

This runs tsc && vite build. TypeScript type errors will fail the build. Output is written to the dist/ directory.

To preview the production build locally before deploying:

bash
pnpm preview
# Serves dist/ at http://localhost:4173

Vercel is the recommended deployment target. A vercel.json config ships with the project that handles SPA routing and sets long-cache headers for built assets:

json
{
  "rewrites": [
    { "source": "/(.*)", "destination": "/index.html" }
  ],
  "headers": [
    {
      "source": "/assets/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
      ]
    }
  ]
}
  1. Install the Vercel CLI and deploy

    bash
    npm install -g vercel
    vercel

    Vercel auto-detects Vite and sets the build command to pnpm build and output to dist/.

  2. Set environment variables

    Go to Project → Settings → Environment Variables in the Vercel dashboard and add any VITE_-prefixed variables your app requires (e.g. VITE_GOOGLE_MAPS_API_KEY).

  3. Deploy to production

    bash
    vercel --prod

Option 2 — Docker + nginx

Use a multi-stage Dockerfile to build and serve the app with nginx:

dockerfile
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
 
# Install pnpm
RUN corepack enable && corepack prepare pnpm@9.15.0 --activate
 
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
 
COPY . .
RUN pnpm build
 
# Stage 2: Serve
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

The nginx config must send index.html for all routes to support client-side routing:

# nginx.conf
server {
  listen 80;
  root /usr/share/nginx/html;
  index index.html;

  location / {
    try_files $uri $uri/ /index.html;
  }

  gzip on;
  gzip_types text/plain text/css application/javascript application/json image/svg+xml;
  gzip_min_length 1024;

  location /assets/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
  }
}

Build and run:

bash
docker build -t jumbo-react-vite:latest .
docker run -p 8080:80 jumbo-react-vite:latest

Option 3 — Static hosting (S3 + CloudFront)

bash
# Build
pnpm build
 
# Upload to S3
aws s3 sync dist/ s3://your-bucket-name --delete
 
# Invalidate CloudFront cache
aws cloudfront create-invalidation \
  --distribution-id YOUR_DISTRIBUTION_ID \
  --paths "/*"

Configure the S3 bucket or CloudFront distribution to serve index.html for all 404 responses. In CloudFront, add a custom error response: 404 → /index.html, HTTP 200.

Environment variables in CI/CD

For GitHub Actions, set secrets in Settings → Secrets and inject them at build time:

yaml
# .github/workflows/deploy.yml
- name: Build
  env:
    VITE_GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
  run: pnpm build

Post-deployment checklist

  • All VITE_ environment variables are set in the deployment environment
  • SPA fallback (try_files or /* rewrite) is configured for client-side routing
  • HTTPS is enforced
  • The Google Maps API key is replaced with an env variable and domain-restricted
  • pnpm build completes without TypeScript errors locally before pushing
  • Login with demo@example.com is disabled or replaced with real auth
  • Browser console shows no errors on first load
  • Dark mode, RTL, and language switching work correctly