Lezione 10 – Deploy: Vercel + Render

🚀 React + Vite + Node.js — Guida completa · Lezione 10 di 10
← L09 — Autenticazione base con JWT

LEZIONE 10  ·  DEPLOY  ·  FINAL

Deploy: Vercel + Render

DevNotes è pronto. È ora di portarlo online. In questa lezione finale ottimizzi la build, gestisci le variabili d’ambiente in produzione, deploi il frontend su Vercel e il backend su Render, e configuri il CI/CD automatico via GitHub.


// cosa costruiremo DevNotes sarà online su due URL permanenti: frontend React compilato e servito da Vercel CDN (devnotes.vercel.app), backend Express su Render con URL HTTPS automatico (devnotes-api.onrender.com). Ogni push su main rideployerà automaticamente entrambi. Le variabili d’ambiente sensibili (JWT_SECRET) non saranno mai nel codice sorgente.

1. Anatomia della build Vite

Durante lo sviluppo, Vite serve i file senza bundling reale grazie agli ES modules nativi del browser. Per la produzione, npm run build usa Rollup internamente per produrre un bundle ottimizzato.

# nella cartella frontend/
npm run build

# Output tipico:
# ✓ 34 modules transformed.
# dist/index.html                  0.5 kB
# dist/assets/index-BxKv4M5A.js  142.3 kB  │ gzip:  45.8 kB
# dist/assets/index-DcFzk9jO.css   3.1 kB  │ gzip:   1.2 kB

La cartella dist/ contiene tutto il necessario per servire l’app. I nomi dei file includono un hash (index-BxKv4M5A.js) per il cache-busting: quando il codice cambia, l’hash cambia e il browser scarica il file aggiornato invece di usare la versione in cache.

Cosa produce npm run build
src/ — codice sorgente (JSX, moduli ES, CSS Modules)
↓ Rollup: tree-shaking, minification, code splitting
dist/index.html
entry point
dist/assets/*.js
bundle minificato + hash
dist/assets/*.css
stili estratti + hash
dist/assets/img/*
risorse ottimizzate

Anteprima locale della build di produzione

# Simula il server di produzione localmente prima di deployare
npm run preview
# → Local: http://localhost:4173/
⚡ Sempre fare preview prima del deploy La build di produzione si comporta diversamente da npm run dev: il proxy Vite non esiste, le variabili d’ambiente devono iniziare con VITE_, i percorsi relativi potrebbero comportarsi diversamente. Testa con npm run preview prima di fare push.

2. Variabili d’ambiente: sviluppo vs produzione

Vite espone al codice frontend solo le variabili con prefisso VITE_. Questo è intenzionale: impedisce di esporre accidentalmente segreti server nel bundle JavaScript.

// frontend/.env.development  (usato da npm run dev)
VITE_API_URL=http://localhost:5173
# con il proxy Vite non serve indicare localhost:3001
// frontend/.env.production  (usato da npm run build)
VITE_API_URL=https://devnotes-api.onrender.com
# URL del backend su Render — lo imposterai al passo 5
// backend/.env
PORT=3001
JWT_SECRET=la_tua_chiave_segreta_lunga
JWT_EXPIRES_IN=7d
NODE_ENV=development
ALLOWED_ORIGIN=http://localhost:5173
# In produzione: ALLOWED_ORIGIN=https://devnotes.vercel.app

Come accedere alle variabili nel codice:

// frontend — accesso a variabile VITE_
const apiUrl = import.meta.env.VITE_API_URL

// backend — accesso a variabile .env (dopo require('dotenv').config())
const secret = process.env.JWT_SECRET
FileCaricato quandoCommittato?
.envSempre (base)❌ Mai
.env.localSempre, override locale❌ Mai
.env.developmentSolo npm run dev⚠️ Se non contiene segreti
.env.productionSolo npm run build⚠️ Se non contiene segreti

3. CORS in produzione

In sviluppo il proxy Vite eliminava il problema CORS. In produzione, frontend e backend sono su domini diversi: devi configurare Express per accettare richieste dall’origine Vercel.

// backend/server.js — CORS configurato per produzione
const cors = require('cors')

const allowedOrigins = [
  'http://localhost:5173',         // sviluppo locale
  process.env.ALLOWED_ORIGIN,     // produzione (da .env / Render dashboard)
].filter(Boolean)

app.use(cors({
  origin: (origin, callback) => {
    // Permetti richieste senza origin (es. curl, Postman) e quelle in lista
    if (!origin || allowedOrigins.includes(origin))
      callback(null, true)
    else
      callback(new Error(`CORS bloccato per: ${origin}`))
  },
  credentials: true,
}))

4. Deploy del frontend su Vercel

Vercel è ottimizzato per i framework frontend moderni. Rileva automaticamente Vite, esegue la build e distribuisce i file statici su una CDN globale.

Metodo A — Vercel CLI (da terminale)

# Installa la CLI una volta (globale)
npm install -g vercel

# Nella cartella frontend/
cd devnotes/frontend
vercel

# La CLI chiede:
# Set up and deploy? → Y
# Which scope? → il tuo account
# Link to existing project? → N
# Project name? → devnotes-frontend
# In which directory is your code located? → ./   (la cartella corrente)
# Want to modify settings? → N
# Per il deploy di produzione (dopo il primo setup)
vercel --prod

Metodo B — Interfaccia web + GitHub (consigliato per CI/CD)

  1. Vai su vercel.com → “Add New Project”
  2. Importa il repository GitHub profgiagnotti/react-vite-guide
  3. In “Root Directory” specifica frontend
  4. Framework Preset: Vercel lo rileva automaticamente come Vite
  5. In “Environment Variables” aggiungi VITE_API_URL con l’URL del backend Render (lo aggiornerai al passo 5)
  6. Clicca “Deploy”
✅ CI/CD automatico Dopo il setup iniziale, ogni push su main trigghera un nuovo deploy automatico. I push su altri branch creano Preview Deployments su URL univoci — ideale per testare feature branch prima del merge.

Gestire il routing SPA su Vercel

Un’app React con React Router usa la History API. Se l’utente visita direttamente devnotes.vercel.app/note/5, Vercel cerca un file /note/5/index.html che non esiste e restituisce 404. Soluzione: crea un file vercel.json nella cartella frontend/:

// frontend/vercel.json
{
  "rewrites": [
    { "source": "/((?!api/).*)", "destination": "/index.html" }
  ]
}

Questa regola dice: “reindirizza qualunque percorso che non inizia con /api/ verso index.html“. React Router gestisce il routing lato client.


5. Deploy del backend su Render

Render è una piattaforma cloud che gestisce il deploy di server Node.js con HTTPS automatico, restart automatico in caso di crash e deploy continuo da GitHub.

Prepara il backend per Render

Render ha bisogno di sapere come avviare il server. Verifica che backend/package.json abbia lo script start corretto e una versione Node specificata:

// backend/package.json
{
  "name": "devnotes-api",
  "version": "1.0.0",
  "engines": {
    "node": ">=18.0.0"    // Render usa la versione specificata qui
  },
  "scripts": {
    "start": "node server.js",    // Render usa questo comando
    "dev":   "nodemon server.js"  // solo in sviluppo locale
  },
  // ... dipendenze ...
}

Il server deve ascoltare sulla porta fornita da Render tramite la variabile d’ambiente PORT:

// backend/server.js — porta dinamica
const PORT = process.env.PORT || 3001
app.listen(PORT, () => console.log(`Server su porta ${PORT}`))

Procedura di deploy su Render

  1. Vai su render.com → “New +” → “Web Service”
  2. Connetti il repository GitHub e seleziona il branch main
  3. Configura i parametri:
    Root Directory: backend
    Runtime: Node
    Build Command: npm install
    Start Command: npm start
  4. In “Environment Variables” aggiungi tutte le variabili del tuo .env backend: JWT_SECRET, JWT_EXPIRES_IN, NODE_ENV=production, ALLOWED_ORIGIN=https://il-tuo-sito.vercel.app
  5. Clicca “Create Web Service”
⚡ Piano gratuito Render — cold start Sul piano gratuito, i Web Service si “addormentano” dopo 15 minuti di inattività. La prima richiesta dopo una pausa può richiedere 30–60 secondi (cold start). Per un’app di produzione reale, considera il piano pagato o una soluzione alternativa come un ping periodico.

6. Il flusso CI/CD completo

Dal git push al deploy in produzione
git push origin main
GitHub webhook
→ Vercel
GitHub webhook
→ Render
Vercel build
npm run build
Render build
npm install
CDN aggiornata
devnotes.vercel.app ✅
Server riavviato
devnotes-api.onrender.com ✅

7. Checklist pre-deploy

Prima di fare il primo push su main, verifica tutto:

Cosa verificareComeOK se…
.env nel .gitignorecat .gitignore | grep .envAlmeno una riga con .env
Build frontend senza errorinpm run build in frontend/Nessun errore, cartella dist/ creata
Preview frontend funzionanpm run preview in frontend/App carica su localhost:4173
Backend avvia con npm startnpm start in backend/Log “Server su porta 3001”
VITE_API_URL impostato in VercelVercel dashboard → Settings → Env VarsValore = URL Render del backend
ALLOWED_ORIGIN impostato in RenderRender dashboard → EnvironmentValore = URL Vercel del frontend
vercel.json presentels frontend/vercel.jsonFile esiste con rewrites SPA

8. Troubleshooting errori comuni

CORS error in produzione

Sintomo Console browser: Access to fetch at 'https://devnotes-api.onrender.com' from origin 'https://devnotes.vercel.app' has been blocked by CORS policy

Causa: ALLOWED_ORIGIN in Render non corrisponde all’URL Vercel esatto (includendo/escludendo il trailing slash, http vs https).
Fix: Controlla e correggi il valore di ALLOWED_ORIGIN nel dashboard Render, poi fai un redeploy manuale.

404 su refresh in produzione

Sintomo Navigare su /note/5 direttamente restituisce 404 da Vercel.
Causa: vercel.json mancante o con regola errata.
Fix: Aggiungi/correggi frontend/vercel.json con la regola rewrite → index.html.

Backend non risponde (cold start)

Sintomo Le prime richieste al backend impiegano 30–60 secondi o vanno in timeout.
Causa: Piano gratuito Render — il server si addormenta dopo 15min di inattività.
Fix (free tier): Aggiungi un health check endpoint e usa un servizio di ping esterno (UptimeRobot) per tenerlo sveglio.
🔬

Laboratorio L10 — Deploy: Vercel + Render

Prepara la build di produzione, configura le variabili d’ambiente, esegui il deploy completo di DevNotes e verifica che frontend e backend comunichino online.

→ Apri il laboratorio

Riepilogo lezione

  • npm run build — Rollup produce bundle minificato con hash per cache-busting nella cartella dist/
  • npm run preview — simula il server di produzione localmente prima del deploy
  • Prefisso VITE_ — solo le variabili con questo prefisso sono esposte al bundle frontend
  • .env.development / .env.production — Vite carica il file corretto in base al comando
  • CORS con whitelistALLOWED_ORIGIN da variabile d’ambiente, non hardcoded nel codice
  • Vercel — CDN globale, deploy da GitHub, Preview Deployments per branch, vercel.json per SPA routing
  • Renderengines.node in package.json, PORT dinamica, variabili d’ambiente dal dashboard
  • CI/CD — ogni push su main trigghera deploy automatici su entrambe le piattaforme
🏆

Serie completata!

Hai costruito e deployato DevNotes: un’app React full-stack con Vite, Express, JWT e deploy su CDN. Hai affrontato JSX, hooks, routing, API REST, autenticazione e CI/CD — gli stessi strumenti usati in produzione da migliaia di team. Il prossimo passo? Sostituisci lo store in-memory con un database reale.


Risorse

DOC
Vite — Building for Production

Opzioni di build, code splitting, chunk strategy, ottimizzazione degli asset

DOC
Vite — Env Variables and Modes

Come funzionano i file .env, il prefisso VITE_ e i mode dev/prod/staging

GUIDE
Vercel — Deploy Vite apps

Configurazione specifica per Vite: preset automatico, variabili d’ambiente, rewrites

GUIDE
Render — Deploy a Node.js/Express App

Guida ufficiale: configurazione Web Service, variabili d’ambiente, health checks

REF
MDN — Cross-Origin Resource Sharing (CORS)

Meccanismo completo: preflight request, header, credenziali, casi d’uso


Lascia un commento