Da CSR a SSR con Laravel, Inertia e React: cosa cambia davvero

Da CSR a SSR con Laravel, Inertia e React: cosa cambia davvero

Non un tutorial di configurazione, ma i problemi reali che emergono quando il rendering lato server entra in produzione.

Passare dal rendering client-side all'SSR non significa semplicemente sostituire createRoot() con hydrateRoot() e aggiungere un processo Node.

Quando si porta davvero SSR dentro un'app Laravel, Inertia e React, iniziano a emergere problemi che nel rendering solo browser non esistono o restano invisibili.

Perché introdurre SSR

L'obiettivo era semplice: far arrivare ai crawler e ai client un documento HTML già significativo, senza dipendere interamente dall'esecuzione di JavaScript.

Con SSR, React costruisce il markup sul server. Il browser riceve quella struttura e successivamente la “idrata”, collegando eventi e stato all'HTML già presente.

La nuova pipeline

L'architettura diventa a due fasi:

  1. Laravel prepara pagina e props Inertia;
  2. un renderer Node produce l'HTML React;
  3. il browser riceve HTML già popolato;
  4. React esegue l'hydration sul client.

Questo crea però una regola fondamentale: il primo render del server e quello del browser devono produrre lo stesso risultato.

Il primo problema: hydration mismatch

Nel rendering client-side è normale leggere subito localStorage, window o preferenze del browser. Sul server, però, questi oggetti non esistono.

Un esempio classico è il tema. Se il server parte da “system” ma il browser legge immediatamente “dark” da localStorage, i due render producono markup diverso.

La soluzione è rendere deterministico il primo render: server e client partono dallo stesso stato, mentre la preferenza locale viene applicata dopo l'hydration.

Le date sono più pericolose di quanto sembrino

Un altro mismatch può nascere senza usare direttamente API browser. Basta formattare una data senza fissare esplicitamente il fuso orario.

Il processo Node può girare in UTC, mentre il visitatore usa un fuso differente. Una pubblicazione vicina alla mezzanotte può quindi mostrare un giorno sul server e un altro nel browser.

Per le pagine SSR è meglio definire esplicitamente il fuso corretto oppure delegare la formattazione al backend.

Ziggy e route() lato server

Nel browser, helper e configurazioni globali possono essere dati per scontati. Con SSR non più.

Le route devono essere disponibili anche al renderer server-side e devono riferirsi alla richiesta corrente. Questo richiede una configurazione esplicita, evitando dipendenze implicite dal template HTML o da variabili globali presenti soltanto nel browser.

Il fallback conta quanto l'SSR

Un server SSR non dovrebbe diventare un nuovo single point of failure per l'intero sito.

Se il renderer Node non risponde, l'applicazione deve poter tornare al comportamento client-side. Per questo è importante usare timeout brevi e trattare SSR come un miglioramento del rendering, non come un requisito assoluto per servire la pagina.

Il deploy cambia

La build ora deve produrre due output: bundle client e bundle SSR. L'immagine di produzione deve contenere il renderer server-side e il processo SSR deve essere avviato e supervisionato correttamente.

Questo significa testare non soltanto PHP e TypeScript, ma anche la build Docker finale. Una configurazione che funziona in sviluppo può fallire semplicemente perché nell'immagine di produzione mancano dipendenze che localmente sono disponibili.

Come ho validato l'implementazione

La verifica ha coinvolto più livelli:

  • test PHP per integrazione e fallback;
  • test JavaScript per renderer e helper;
  • type checking e lint;
  • build SSR reale;
  • build Docker;
  • browser automation per verificare hydration ed errori console.

Conclusione

SSR è una modifica architetturale, non una feature grafica. Sposta parte del frontend sul server e obbliga a rendere esplicite assunzioni che prima il browser nascondeva.

Il vantaggio non è soltanto SEO. Il vero beneficio è che l'applicazione diventa più rigorosa sul modo in cui costruisce il primo render.

Condividi: