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.
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.
entry point
bundle minificato + hash
stili estratti + hash
risorse ottimizzate
Anteprima locale della build di produzione
# Simula il server di produzione localmente prima di deployare npm run preview # → Local: http://localhost:4173/
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
| File | Caricato quando | Committato? |
|---|---|---|
.env | Sempre (base) | ❌ Mai |
.env.local | Sempre, override locale | ❌ Mai |
.env.development | Solo npm run dev | ⚠️ Se non contiene segreti |
.env.production | Solo 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)
- Vai su vercel.com → “Add New Project”
- Importa il repository GitHub
profgiagnotti/react-vite-guide - In “Root Directory” specifica
frontend - Framework Preset: Vercel lo rileva automaticamente come Vite
- In “Environment Variables” aggiungi
VITE_API_URLcon l’URL del backend Render (lo aggiornerai al passo 5) - Clicca “Deploy”
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
- Vai su render.com → “New +” → “Web Service”
- Connetti il repository GitHub e seleziona il branch
main - Configura i parametri:
Root Directory:backend
Runtime: Node
Build Command:npm install
Start Command:npm start - In “Environment Variables” aggiungi tutte le variabili del tuo
.envbackend:JWT_SECRET,JWT_EXPIRES_IN,NODE_ENV=production,ALLOWED_ORIGIN=https://il-tuo-sito.vercel.app - Clicca “Create Web Service”
6. Il flusso CI/CD completo
→ Vercel
→ Render
npm run build
npm install
devnotes.vercel.app ✅
devnotes-api.onrender.com ✅
7. Checklist pre-deploy
Prima di fare il primo push su main, verifica tutto:
| Cosa verificare | Come | OK se… |
|---|---|---|
.env nel .gitignore | cat .gitignore | grep .env | Almeno una riga con .env |
| Build frontend senza errori | npm run build in frontend/ | Nessun errore, cartella dist/ creata |
| Preview frontend funziona | npm run preview in frontend/ | App carica su localhost:4173 |
Backend avvia con npm start | npm start in backend/ | Log “Server su porta 3001” |
VITE_API_URL impostato in Vercel | Vercel dashboard → Settings → Env Vars | Valore = URL Render del backend |
ALLOWED_ORIGIN impostato in Render | Render dashboard → Environment | Valore = URL Vercel del frontend |
vercel.json presente | ls frontend/vercel.json | File esiste con rewrites SPA |
8. Troubleshooting errori comuni
CORS error in produzione
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
/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)
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 laboratorioRiepilogo lezione
npm run build— Rollup produce bundle minificato con hash per cache-busting nella cartelladist/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 whitelist —
ALLOWED_ORIGINda variabile d’ambiente, non hardcoded nel codice - Vercel — CDN globale, deploy da GitHub, Preview Deployments per branch,
vercel.jsonper SPA routing - Render —
engines.nodeinpackage.json,PORTdinamica, variabili d’ambiente dal dashboard - CI/CD — ogni push su
maintrigghera deploy automatici su entrambe le piattaforme
Risorse
Opzioni di build, code splitting, chunk strategy, ottimizzazione degli asset
Come funzionano i file .env, il prefisso VITE_ e i mode dev/prod/staging
Configurazione specifica per Vite: preset automatico, variabili d’ambiente, rewrites
Guida ufficiale: configurazione Web Service, variabili d’ambiente, health checks
Meccanismo completo: preflight request, header, credenziali, casi d’uso