Quando il frontend smette di stare nel browser
C'era una volta un frontend semplice: HTML, CSS, un po' di JavaScript, e tutto viveva nel browser dell'utente. Poi sono arrivate le Single Page Application, e abbiamo spostato sempre più logica lato client. Sembrava il futuro. Il modello tradizionale delle Single Page Application prevedeva che tutta la logica di rendering girasse nel browser: il server mandava un "index.html" quasi vuoto, il client scaricava un bundle JavaScript, lo eseguiva, e solo allora costruiva il DOM. Questo approccio ha dei costi reali in termini di performance: bundle pesanti, tempo di parsing elevato e una dipendenza forte dalla potenza del dispositivo dell'utente.
Oggi l'architettura frontend si è spostata in una direzione diversa: rendering sul server, esecuzione sull'edge, e meno JavaScript nel browser. Non si tratta di un ritorno al server-side rendering classico degli anni 2000, ma di un modello ibrido più preciso, dove ogni pezzo della UI viene eseguito nel contesto più adatto — server, edge o client — in base alle sue esigenze.
Ma esemplifichiamo meglio:
SPA classica (es. Create React App)
Browser riceve un
"index.html"quasi vuotoScarica un bundle JS enorme (500kb+)
Esegue tutto il JavaScript
Solo allora costruisce il DOM e mostra qualcosa
L'utente fissa una pagina bianca mentre il browser esegue.
Next.js con Server Components
Il server esegue il componente React, genera HTML già popolato
Il browser riceve HTML già completo, quindi visibile subito
Scarica solo il JavaScript dei Client Components (bundle molto più piccoli)
Nessuna esecuzione pesante lato client per il contenuto statico
L'utente vede la pagina quasi istantaneamente.
Ogni richiesta HTTP ha un costo in latenza che dipende, tra le altre cose, dalla distanza fisica tra il client e il server. Un server centralizzato a New York risponde a un utente a Milano con una latenza di rete di circa 80-120ms solo per il round-trip — prima ancora che il server abbia fatto qualsiasi elaborazione. Moltiplicato per le richieste di una sessione, il costo si accumula.
L'edge computing risolve questo distribuendo l'esecuzione del codice su una rete di nodi geograficamente vicini agli utenti. Invece di instradare ogni richiesta verso un unico data center, la logica viene eseguita nel nodo più vicino — spesso a pochi millisecondi dall'utente.
Come funziona in pratica
Le principali piattaforme — Vercel Edge Functions, Cloudflare Workers, Netlify Edge Functions — gestiscono tutta l'infrastruttura. Per un progetto Next.js su Vercel, spostare una route sull'edge richiede una sola riga:
// app/api/hello/route.ts
export const runtime = 'edge'
export async function GET(request: Request) {
return new Response('OK')
}
Vercel distribuisce quella funzione in automatico su circa 30 regioni. Non serve configurazione aggiuntiva.
Il Middleware: il caso d'uso più comune
In Next.js, il middleware gira sull'edge di default. È il posto giusto per logica che deve intercettare ogni richiesta prima che arrivi al server: autenticazione, redirect, personalizzazione geografica.
Questo redirect avviene dal nodo edge più vicino all'utente, senza coinvolgere il server principale. Per un utente in Italia, la risposta arriva tipicamente da Francoforte invece che da un data center negli USA.
// middleware.ts
import { NextResponse } from 'next/server'
export function middleware(request: Request) {
const paese = request.geo?.country // popolato da Vercel automaticamente
if (paese === 'IT') {
return NextResponse.redirect(new URL('/it', request.url))
}
}
Limitazioni delle funzioni edge
Le funzioni edge non sono server Node.js completi. Girano in un ambiente V8 isolato (simile a un Service Worker), il che impone dei vincoli precisi:
✅ Supportato
Fetch verso API esterne
Verifica token JWT
Redirect e rewrite URLOperazioni
Lettura header e cookie
❌ Non supportato
Query a database tradizionali (Postgres, MySQL)
Moduli Node.js nativi (fs, path, crypto…)
Operazioni CPU-intensive
Per accedere a un database dall'edge è necessario usare soluzioni compatibili con questo ambiente: Turso (SQLite distribuito), Neon (Postgres serverless con HTTP API), o Upstash (Redis con API HTTP).
React Server Components e Next.js
Con le SPA classiche, il bundle JavaScript include tutto: componenti, logica di fetching, librerie di rendering. Anche le parti della UI che non richiedono interattività vengono spedite al client come codice da eseguire. Questo aumenta il tempo di parsing e di esecuzione, con impatto diretto sul Time to Interactive (TTI).
I React Server Components (RSC), introdotti stabilmente con Next.js App Router, affrontano questo problema alla radice: i componenti che non richiedono interattività vengono renderizzati esclusivamente sul server e inviati al client come HTML — senza il corrispettivo JavaScript nel bundle.
Server Components vs Client Components
La distinzione è netta:
Server Components (default nell'App Router):
Girano solo lato server, non nel browser
Possono fare
"async/await"direttamente, facendo così richieste lato server/database.Non generano JavaScript nel bundle del client
Non possono usare
"useState","useEffect", o"event handler"
Client Components (marcati con "use client"):
Girano nel browser, come i componenti React tradizionali
Supportano tutto lo stato locale, gli hook e gli event handler
Generano JavaScript che viene scaricato ed eseguito dal client
// ProductPage.tsx — Server Component (nessun 'use client')
// Accede direttamente al DB, non genera JS nel bundle
async function ProductPage({ id }: { id: string }) {
const product = await db.products.findUnique({ where: { id } })
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<AddToCartButton productId={id} /> {/* Client Component */}
</div>
)
}
// AddToCartButton.tsx — Client Component
'use client'
export function AddToCartButton({ productId }: { productId: string }) {
const [added, setAdded] = useState(false)
return (
<button onClick={() => setAdded(true)}>
{added ? 'Aggiunto ✓' : 'Aggiungi al carrello'}
</button>
)
}
Core Web Vitals
Cosa sono e perché contano
I Core Web Vitals sono le metriche con cui Google misura la qualità dell'esperienza utente di una pagina web. Dal 2021 fanno parte dei fattori di ranking. Nel 2026 sono diventati un riferimento progettuale standard, non una checklist di fine progetto.
Le tre metriche principali:
LCP – Largest Contentful Paint: Tempo al caricamento del contenuto principale visibile. Una soglia buona è inferiore a 2.5s.
FID – First Input Delay: Latenza tra il primo click/tap dell'utente e la risposta del browser. Una soglia buona è inferiore a 100ms.
CLS – Cumulative Layout Shift: Spostamento cumulativo degli elementi durante il caricamento. Una soglia buona è inferiore a 0.1 (https://web.dev/articles/cls?hl=it#layout-shift-score)
Puoi misurarle con Google Search Console (dati reali degli utenti), PageSpeed Insights (analisi sintetica), o Lighthouse integrato in Chrome DevTools.
Come Edge e Server Components impattano i Web Vitals
I tre argomenti di questo articolo sono direttamente collegati alle metriche:
LCP dipende in larga parte dal TTFB (Time to First Byte): il tempo che passa tra la richiesta e il primo byte di risposta. L'edge computing abbassa il TTFB riducendo la latenza di rete. I Server Components abbassano ulteriormente il TTFB perché il server invia HTML già renderizzato, senza aspettare l'esecuzione JavaScript lato client.
FID misura quanto il browser è occupato quando l'utente interagisce per la prima volta. Un bundle JavaScript pesante blocca il main thread durante il parsing e l'esecuzione, peggiorando FID. Riducendo il JavaScript inviato al client tramite i Server Components, il main thread è più libero e FID migliora.
CLS è spesso causato dall'idratazione asincrona delle SPA: il browser mostra prima l'HTML vuoto, poi aggiunge i contenuti via JavaScript, causando spostamenti di layout visibili. Con i Server Components, l'HTML arriva già completo, eliminando questa fonte di CLS.
Accessibilità e performance: stessa soluzione
Molte ottimizzazioni per i Core Web Vitals coincidono con requisiti di accessibilità WCAG. Alcuni esempi concreti:
HTML semantico corretto (heading gerarchici, landmark ARIA) migliora sia la navigazione da screen reader che i punteggi Lighthouse
Immagini con
"width"e"height"espliciti prevengono il layout shift (CLS) e forniscono informazioni agli assistenti vocaliFont caricati con
"font-display: swap"evitano il blocco del rendering (impatto su LCP) e garantiscono leggibilità anche prima che il font personalizzato sia disponibileContenuto non dipendente da JavaScript riduce CLS e rende la pagina accessibile anche senza JS abilitato
Trattare performance e accessibilità come un'unica area di lavoro riduce la duplicazione degli sforzi e porta a risultati migliori su entrambi i fronti.