React
load server vs universal in SvelteKit: chi gira dove
In SvelteKit +page.server.ts esegue load solo sul server, +page.ts anche nel browser: la scelta dipende da cosa il dato tocca e da quante volte lo paghi.
In sintesi
- Il file con suffisso .server resta fuori dal bundle del browser: lì stanno database e variabili private.
- Il load universale gira sul server durante il render e di nuovo nel browser a ogni navigazione.
- Quello che load restituisce viene serializzato: classi e funzioni non attraversano il confine.
In SvelteKit +page.server.ts esegue load solo sul server, mentre +page.ts esegue lo stesso codice sul server durante il render e nel browser a ogni navigazione: la scelta dipende da cosa il dato tocca.
Due file, due contratti
Il suffisso .server tiene il modulo fuori dal bundle del browser: lì puoi importare il database e leggere variabili d’ambiente private. Il file universale finisce nel browser, quindi niente segreti e niente driver.
npx sv check
// src/routes/orders/+page.server.ts
import { db } from "$lib/server/db";
export const load = async () => {
const orders = await db.order.findMany({ take: 20 });
return { orders };
};
Nel file universale ricevi fetch, params, url e depends: la fetch è quella di SvelteKit, che inoltra i cookie e deduplica le richieste durante il render.
// src/routes/products/+page.ts
export const load = async ({ fetch, depends }) => {
depends("app:products");
const res = await fetch("/api/products");
return { products: await res.json() };
};
Il dato deve attraversare il confine
Quello che load restituisce viene serializzato: numeri, stringhe, array, Date e Map passano, un’istanza di classe o una connessione al database no. L’errore arriva in build o al primo render, non dove lo cerchi.
Come scegliere
| File | Dove gira | Cosa può usare |
|---|---|---|
| +page.server.ts | Solo sul server | Database, segreti, cookie della richiesta |
| +page.ts | Server in SSR, browser in navigazione | fetch, API pubbliche, moduli condivisi |
| +layout.server.ts | Solo sul server | Dati comuni a un gruppo di pagine |
| +page.ts con fetch relativa | Entrambi, lo stesso codice | Endpoint pubblici già esposti |
Il limite da mettere in conto
Il load universale viene eseguito due volte: sul server per l’HTML iniziale e nel browser quando navighi. Una fetch lenta lì costa due volte, e un load server che restituisce molta roba scrive tutto nell’HTML e nella cache del client.
Errori che si vedono
- Importare un modulo server da
+page.ts: la build si ferma, perché quel codice non può finire nel browser. - Restituire una classe o un oggetto con metodi: la serializzazione perde i metodi e il componente riceve dati muti.
- Leggere
document.cookiein+page.ts: durante il render sul server non esiste, e il primo HTML è diverso dal secondo. - Ripetere in
+page.server.tsuna fetch che il componente fa già: due richieste per lo stesso dato.
Nel catalogo i dati arrivano in tabelle già pronte: table raccoglie i componenti, il blocco table porta le righe, e svelte-bits si installa come sorgente per il resto della pagina. Le azioni di form sono in form actions in SvelteKit, i file di rotta in routing e layout in SvelteKit, la sessione in hook per l’autenticazione, il confronto in Svelte vs React.
Domande frequenti
Posso usare entrambi nella stessa rotta?
Sì, ma solo uno dei due restituisce dati alla pagina: se esistono entrambi, il load universale riceve il risultato del load server in data e non può sovrascriverlo. Tieni il server per i dati e l’universale per ciò che dipende dal browser.
Perché la fetch nel load universale è meglio di quella globale?
Perché quella fornita da SvelteKit inoltra i cookie durante il render sul server e deduplica le richieste identiche. La fetch globale non sa nulla della richiesta in corso e non può farlo.
Il load server gira anche nelle navigazioni client?
Sì. Sul client SvelteKit chiama un endpoint interno generato per la rotta, quindi il codice resta sul server ma il risultato arriva comunque. Per questo una query lenta si sente anche dopo il primo caricamento.
Dove metto il codice condiviso?
In $lib. Se tocca il database o i segreti va in $lib/server, che la build rifiuta di importare da un modulo destinato al browser. Il resto può stare in $lib senza suffisso.
Perché ottengo un errore di serializzazione?
Perché il valore restituito contiene qualcosa che non sopravvive al trasporto, come una funzione, una classe o un BigInt non gestito. Restituisci dati semplici e ricostruisci l’oggetto nel componente.