Skip to main content

Overview

This guide covers deploying Q-Sopa to production. The application is built with Vite and can be deployed to any static hosting platform.

Building for Production

Before deploying, you need to create an optimized production build.

Build Command

npm run build
This command:
  1. Bundles your React application
  2. Optimizes assets (minification, tree-shaking)
  3. Creates a dist/ directory with production-ready files

Build Configuration

The build is configured in vite.config.js:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
})
Preview your production build locally before deploying:
npm run build
npm run preview
This serves the dist/ folder at http://localhost:4173

Environment Variables

Setting Up Environment Variables

Create environment files for different stages: .env.development (local development):
VITE_API_BASE_URL=http://localhost:3000
.env.production (production):
VITE_API_BASE_URL=https://apiqsp-production.up.railway.app

Using Environment Variables

Update src/services/api.js to use environment variables:
const BASE_URL = import.meta.env.VITE_API_BASE_URL || "https://apiqsp-production.up.railway.app";

export const getCategorias = async () => {
  const res = await fetch(`${BASE_URL}/categories`);
  if (!res.ok) throw new Error("Error al cargar categorías");
  return res.json();
};

export const getComidas = async () => {
  const res = await fetch(`${BASE_URL}/products`);
  if (!res.ok) throw new Error("Error al cargar comidas");
  return res.json();
};

export const getProductsByCategory = async (categoryId) => {
  const res = await fetch(`${BASE_URL}/products/category/${categoryId}`);
  if (!res.ok) throw new Error("Error al cargar productos de la categoría");
  return res.json();
};
Vite only exposes environment variables prefixed with VITE_ to your client-side code. Never store sensitive keys in client-side environment variables.

Deployment Platforms

Vercel offers seamless deployment with automatic builds and previews.
1

Install Vercel CLI

npm install -g vercel
2

Login to Vercel

vercel login
3

Deploy

vercel
Follow the prompts to configure your project.
4

Set Environment Variables

In the Vercel dashboard:
  1. Go to Project Settings → Environment Variables
  2. Add VITE_API_BASE_URL with your production API URL
  3. Redeploy to apply changes

Vercel Configuration

Create vercel.json in your project root:
{
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "framework": "vite",
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/index.html"
    }
  ]
}

GitHub Integration

For automatic deployments:
  1. Push your code to GitHub
  2. Import your repository in Vercel Dashboard
  3. Configure build settings:
    • Framework Preset: Vite
    • Build Command: npm run build
    • Output Directory: dist
  4. Add environment variables
  5. Deploy
Every push to your main branch will trigger an automatic deployment. Pull requests get preview deployments.

Netlify

Netlify is another excellent option for static sites.
1

Install Netlify CLI

npm install -g netlify-cli
2

Login to Netlify

netlify login
3

Initialize Netlify

netlify init
4

Deploy

netlify deploy --prod

Netlify Configuration

Create netlify.toml in your project root:
[build]
  command = "npm run build"
  publish = "dist"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

[build.environment]
  NODE_VERSION = "18"

Setting Environment Variables

In Netlify Dashboard:
  1. Go to Site Settings → Build & Deploy → Environment
  2. Add VITE_API_BASE_URL
  3. Trigger a new deploy

Railway

Deploy alongside your backend API on Railway.
1

Install Railway CLI

npm install -g @railway/cli
2

Login to Railway

railway login
3

Initialize Project

railway init
4

Add Build Configuration

Create railway.json:
{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS",
    "buildCommand": "npm run build"
  },
  "deploy": {
    "startCommand": "npm run preview",
    "restartPolicyType": "ON_FAILURE"
  }
}
5

Deploy

railway up
Railway is particularly useful if your API is already hosted there, as both frontend and backend can be in the same project.

GitHub Pages

Deploy to GitHub Pages for free static hosting.
1

Update vite.config.js

Add base path for GitHub Pages:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  base: '/your-repo-name/', // Replace with your repository name
})
2

Install gh-pages

npm install --save-dev gh-pages
3

Add Deploy Scripts

Update package.json:
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d dist"
  }
}
4

Deploy

npm run deploy
This builds your app and pushes it to the gh-pages branch.
5

Enable GitHub Pages

  1. Go to your repository settings
  2. Navigate to Pages section
  3. Set source to gh-pages branch
  4. Save

Cloudflare Pages

Deploy with Cloudflare’s global CDN.
1

Connect Repository

  1. Log in to Cloudflare Dashboard
  2. Go to Pages → Create a project
  3. Connect your GitHub repository
2

Configure Build

  • Framework preset: Vite
  • Build command: npm run build
  • Build output directory: dist
3

Set Environment Variables

Add VITE_API_BASE_URL in the environment variables section
4

Deploy

Click “Save and Deploy”

CORS Configuration

If your API and frontend are on different domains, you may encounter CORS issues.

Backend CORS Setup

Your API must allow requests from your frontend domain. Example Express.js configuration:
const express = require('express');
const cors = require('cors');
const app = express();

// Allow your production domain
app.use(cors({
  origin: ['https://your-frontend-domain.com', 'http://localhost:5173'],
  credentials: true
}));

// Your API routes...
Never use cors({origin: '*'}) in production. Always specify allowed origins explicitly.

Performance Optimization

Image Optimization

  1. Use WebP format for better compression
  2. Implement lazy loading:
// In ProductCard.jsx
<img 
  src={image} 
  alt={title}
  loading="lazy"
/>
  1. Use CDN for images: Host product images on a CDN like Cloudinary or Imgix

Code Splitting

Vite automatically handles code splitting, but you can optimize further:
import { lazy, Suspense } from 'react';

const Menu = lazy(() => import('./pages/Menu'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Menu />
    </Suspense>
  );
}

Caching Strategy

Implement API response caching:
// src/services/api.js
const cache = new Map();
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes

export const getCategorias = async () => {
  const cacheKey = 'categories';
  const cached = cache.get(cacheKey);
  
  if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
    return cached.data;
  }
  
  const res = await fetch(`${BASE_URL}/categories`);
  if (!res.ok) throw new Error("Error al cargar categorías");
  const data = await res.json();
  
  cache.set(cacheKey, { data, timestamp: Date.now() });
  return data;
};

Monitoring and Analytics

Adding Google Analytics

  1. Install the package:
npm install react-ga4
  1. Initialize in your app:
// src/main.jsx
import ReactGA from 'react-ga4';

ReactGA.initialize('G-XXXXXXXXXX');

// Track page views
ReactGA.send({ hitType: "pageview", page: window.location.pathname });

Error Tracking with Sentry

  1. Install Sentry:
npm install @sentry/react
  1. Configure:
// src/main.jsx
import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: "your-sentry-dsn",
  environment: import.meta.env.MODE,
  tracesSampleRate: 1.0,
});

Deployment Checklist

1

Pre-deployment

  • Update API URL for production
  • Test build locally (npm run build && npm run preview)
  • Verify all environment variables
  • Check for console errors
  • Test on multiple browsers
  • Verify mobile responsiveness
2

Deployment

  • Choose hosting platform
  • Configure build settings
  • Set environment variables
  • Deploy application
  • Verify deployment URL
3

Post-deployment

  • Test all features in production
  • Verify API connectivity
  • Check loading times
  • Test category filtering
  • Confirm product images load
  • Test mobile drawer menu
  • Set up monitoring/analytics

Continuous Deployment

Set up automatic deployments with GitHub Actions:
# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          
      - name: Install dependencies
        run: npm ci
        
      - name: Build
        run: npm run build
        env:
          VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }}
          
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v20
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.ORG_ID }}
          vercel-project-id: ${{ secrets.PROJECT_ID }}
          vercel-args: '--prod'

Troubleshooting Deployment

Ensure all dependencies are in package.json:
rm -rf node_modules package-lock.json
npm install
npm run build
Check the browser console for errors. Common causes:
  • Incorrect base path in vite.config.js
  • Missing environment variables
  • CORS issues with API
Remember:
  • Variables must be prefixed with VITE_
  • Rebuild after changing environment variables
  • Access with import.meta.env.VITE_VARIABLE_NAME

Next Steps

Troubleshooting

Fix common issues and errors

Customization

Customize the application

Build docs developers (and LLMs) love