React

Routing e layout in SvelteKit: file, segmenti e reset

In SvelteKit la struttura delle cartelle è il router: +page, +layout e +page@ decidono URL, dati e quali layout restano montati.

In sintesi

  • L’URL nasce dalla cartella: [slug] è un parametro, (app) è un gruppo che non compare nell’URL.
  • Il load che tocca segreti va in +page.server.js; +page.js gira anche nel browser.
  • [email protected] riporta una pagina al layout radice e salta quelli intermedi.

In SvelteKit l’URL nasce dalla cartella: src/routes/blog/[slug]/+page.svelte risponde a /blog/qualsiasi-cosa senza un file di rotte da mantenere. Il nome del file dice anche quando quel codice gira, sul server o nel browser.

I file che contano

FileDove giraA cosa serve
+page.svelteServer e clientMarkup della route
+page.server.jsSolo serverload con database e segreti
+page.jsServer e clientload isomorfo su dati pubblici
+layout.svelteServer e clientCornice condivisa dai figli
+error.svelteServer e clientErrore del segmento
src/routes/
  +layout.svelte
  +layout.server.js
  (app)/
    dashboard/
      +layout.svelte
      +page.svelte
    settings/
      +page@(app).svelte
  blog/
    [slug]/
      +page.server.js
      +page.svelte

(app) è un route group: non aggiunge un segmento all’URL e serve a dare un layout comune a più rami. [slug] è un parametro, [[lang]] è opzionale, [...rest] prende il resto del percorso.

// src/routes/blog/[slug]/+page.server.js
import { error } from "@sveltejs/kit";

export async function load({ params }) {
  const post = await db.post.findUnique({ where: { slug: params.slug } });
  if (!post) error(404, "Not found");
  return { post };
}

Layout annidati e reset

Un layout vale per sé e per tutti i figli. [email protected] riporta la pagina al layout radice; +page@(app).svelte la riporta al layout del gruppo: i layout intermedi non vengono montati, e la pagina non eredita il loro markup.

Dove mettere il load

  • +page.server.js quando leggi il database o un segreto: quel codice non arriva al browser.
  • +page.js quando la fetch è pubblica e vuoi la stessa logica sui due lati.
  • ./$types per tipizzare params e data: i tipi sono generati, non scritti a mano.
  • +layout.server.js per dati comuni, sapendo che gira a ogni navigazione dentro il suo ramo.

Il limite da mettere in conto

Un load universale gira due volte, prima sul server e poi nel browser: non è il posto per un segreto. Un load di layout gira a ogni navigazione dentro il suo ramo, salvo invalidazione mirata: se il dato è lento, mettilo nella pagina che lo usa.

Errori frequenti

  • Restituire una funzione da un load: viene serializzata e il client riceve un valore vuoto.
  • Chiamare fetch in onMount quando un load fa già il lavoro: la pagina mostra due stati di caricamento.
  • Mettere la guardia di autenticazione solo nel layout: le azioni dei form passano da un endpoint e non dal layout.
  • Leggere params come numero: è una stringa, la conversione va fatta a mano.

I layout si montano da blocchi già pronti: sidebar e dashboard coprono i due casi ricorrenti di cornice, mentre flowbite-svelte fornisce le primitive Svelte per riempirli. Lo stato dentro le route è in runes di Svelte 5, il vecchio modello di store in store che non si aggiorna, il confronto in Svelte vs React.

Domande frequenti

Dove metto il codice condiviso fra pagine?

In un layout se è interfaccia, in un load di layout se sono dati comuni. La logica che non è né una cosa né l’altra va in un modulo dentro lib, importabile da entrambi.

Come faccio un URL senza prefisso?

Con un route group fra parentesi: la cartella (app) non compare nell’URL. Serve anche a dare un layout diverso a un ramo.

Perché il layout si monta di nuovo durante la navigazione?

Perché stai entrando in un ramo con un layout diverso, o perché una chiave cambia. Se il layout dipende da un parametro, SvelteKit lo ricrea: quella parte va spostata nella pagina.

Posso usare +page.js e +page.server.js insieme?

Sì, ma il load del server gira prima e passa i dati a quello universale. Scegli un file per route quando puoi: due load nella stessa rotta sono difficili da seguire.

Come tipizzo params?

Importando i tipi generati da ./$types: PageServerLoad e PageData seguono il nome della route. Non scriverli a mano, cambiano con la struttura.