Il mondo della programmazione web è sempre più orientato verso pagine che contengono solo il codice strettamente necessario. Ma come si lavora per creare soluzioni complete, efficienti e indicizzabili automaticamente da motori di ricerca e social network?
Ormai ogni applicazione web moderna, nonché comuni siti come blog o siti d’informazione, viene sviluppata come single page application (SPA). Al posto della tradizionale esperienza utente del susseguirsi di click su link → caricamento nuova pagina, ad ogni interazione dell’utente la pagina reagisce con un aggiornamento del contenuto.
Eventi di caricamento durante la navigazione web classica. Salvo caching delle risorse statiche, questo iter si ripete per ogni passaggio ad un nuova pagina
Usando framework JavaScript come Angular, React, Vue o una delle tante altre soluzioni per lo sviluppo di SPA, il browser non ha più necessità di caricare, scandire ed eseguire tutta la struttura di una nuova pagina ad ogni accesso ad un nuovo contenuto, ma si può limitare a recuperare dal server solo il set minimo di dati necessari per l’aggiornamento della pagina.
In termini di sviluppo, una SPA consiste nello spostare tutta la “logica della view” (cioè gli algoritmi che regolano il contenuto visivo) dal server al client, relegando il primo al solo compito di fornire le informazioni strettamente necessarie per dare l’esperienza web completa. Questo significa anche che lo scheletro HTML iniziale della pagina è completamente svuotato del suo contenuto, ed assomiglia a qualcosa del genere:
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="manifest" href="/manifest.json">
<link rel="shortcut icon" href="/favicon.ico">
<title>La nostra vetrina</title>
</head>
<body>
<div id="root"></div>
<script src="/static/css/styles.js"<>
Indubbiamente molto veloce da scaricare e interpretare. All’atto pratico, però, questo comporta alcune nuove sfide da affrontare.
Problematiche coi motori di ricerca
Questo approccio SPA può essere applicato senza problemi per le web app che non hanno bisogno di indicizzazione, come abbiamo fatto di recente per un’applicazione web per l’organizzazioni di eventi di private bankers. Esistono invece alcuni problemi per i siti web che hanno requisiti di posizionamento.
Pressoché tutti i siti del mondo vengono esplorati e catalogati dai vari motori di ricerca, da Google a Bing, da Yandex a Baidu. Il modo in cui questo avviene è tramite l’utilizzo di crawler bot: si tratta di applicazioni in grado di analizzare le pagine web e costruire un albero dei contenuti del sito in maniera del tutto automatica.
Essendo degli strumenti automatici, non hanno bisogno di ricreare l’interfaccia grafica per poter operare, per cui limitano la quantità di risorse da caricare (come fogli di stile o script) per eseguire il loro compito.
In passato tali bot escludevano del tutto il caricamento e l’esecuzione di fogli di stile e soprattutto script per il funzionamento della pagina, limitandosi unicamente all’analisi statica del contenuto HTML. Di conseguenza, a fronte di una SPA il motore di ricerca non avrebbe rilevato alcun contenuto, considerando il sito come effettivamente vuoto, anche in presenza di una sitemap.
Oggi sappiamo che non è più così, per cui anche i bot dei motori di ricerca scaricano ed eseguono gli script necessari per il funzionamento. Questo vuol dire che possiamo smettere di preoccuparci? Purtroppo la situazione non è così semplice.
Crawler basati su vecchi motori di rendering
I bot utilizzano spesso i motori alla base dei comuni browser per ricreare le pagine da analizzare. Tuttavia, non c’è alcuna garanzia che tali motori siano allineati con le versioni utilizzate comunemente dagli utenti del sito. In particolare, a maggio 2018 il bot di Google è ancora basato sulla versione 41 di Chromium, diventata obsoleta nell’aprile 2015.
Questo significa che la nostra SPA potrebbe non funzionare correttamente su tali motori di rendering, pregiudicando la corretta esposizione dei contenuti. Un problema spesso ignorato, soprattutto perché i test automatici non vengono normalmente eseguiti su piattaforme così vecchie.
Non ci sono solo i motori di ricerca
Mentre i motori di ricerca fanno della catalogazione di siti il loro motivo d’essere ed hanno quindi negli anni sviluppato algoritmi sofisticati per l’estrazione dei contenuti, spesso capita che le nostre pagine vengano analizzate ed esposte da altri strumenti automatici.
Il caso più classico consiste nella condivisione di un link su social network quali Facebook o Twitter, o su applicazioni di messaggistica come Whatsapp o Telegram.
Tali applicazioni hanno implementato l’utile funzione di mostrare un’anteprima del sito puntato dal link, riportando titolo, immagine principale e l’incipit dei contenuti testuali della pagina (reperite tramite euristica o semplicemente con l’uso dei tag Open Graph), aumentando l’interesse dei destinatari a scoprire cosa c’è di più.
Il problema è che tali funzionalità di anteprima non hanno la stessa sofisticatezza dei bot dei motori di ricerca, quindi potrebbe capitare che l’anteprima possa non essere generata o generata in maniera non corretta.
Problematiche di performance
Un altro aspetto da considerare è quello delle performance del nostro sito. Infatti, mentre navighiamo tranquillamente col nostro PC, collegato alla rete di casa o dell’ufficio, raramente soffriamo di problemi di velocità nel caricamento delle risorse o di mancanza di responsività della pagina.
Ma uno scenario completamente diverso si apre quando si naviga nello stesso sito con un dispositivo mobile, dotato spesso di memoria e potenza elaborativa nettamente inferiori, nonché talvolta di banda di rete molto meno ampia a causa di scarsa connettività. E si tratta di un problema quantomai grave, dato che è già da un paio d’anni che gli accessi ai siti tramite piattaforma mobile hanno superato quelli desktop.
Un problema comune delle SPA è che tutti i template dell’interfaccia sono gestiti tramite JavaScript, così come tutta la logica di view. Ne consegue che per il funzionamento dell’applicazione vengono creati dei bundle di JavaScript di dimensioni anche notevoli, contenenti le librerie di gestione della pagina, i template e le logiche. Stiamo parlando di dimensioni di anche qualche megabyte, in dipendenza della complessità dell’applicazione.
Tutto questo ha un costo in termini di elaborazione. E questo costo si traduce in maggiori tempi di attesa per l’apparizione della pagina e la sua possibilità di interazione.
Una questione quanto mai delicata, dal momento che generalmente si suggerisce di rendere il sito interattivo in meno di un secondo per ridurre al minimo la possibilità che l’utente si spazientisca e abbandoni la pagina.
Il server-side rendering
La soluzione ad entrambe le tipologie di problemi è nota come server-side rendering (SSR). Consiste essenzialmente nell’operazione, a dire il vero nota da sempre, di lasciare che il server si occupi di ricreare lo scheletro HTML della pagina, e di inviare il risultato al client al posto dell'”abbozzo” di documento mostrato sopra.
Per dirla a grandi linee questo è esattamente quel che si è fatto normalmente nel siti multi-pagina prima dell’avvento delle SPA, quindi sembra che a prima vista si ritorni ai vecchi sistemi! In realtà la questione è più complessa.
La differenza principale sta nel fatto che la ricreazione della pagina sul server avviene solo per l’accesso iniziale dell’utente al sito o applicazione web, mentre per le successive fasi di navigazione si procede come una normale SPA. Questo produce i seguenti vantaggi:
- i motori di ricerca e i sistemi di condivisione della pagina su social network, che di fatto si comportano come “utenti al primo accesso”, non si troveranno più a dover indicizzare dei semplici abbozzi, ma potranno contare sul contenuto completo della pagina;
- essendo il contenuto della pagina già disponibile per l’utente al momento del primo accesso al sito, si può ritardare il caricamento degli script di creazione della view e di gestione della stessa in un momento immediatamente successivo, riducendo la quantità di dati da scaricare prima che l’utente possa vedere e interagire con la pagina.
Come avviene il SSR
Nelle SPA, la creazione della view della pagina è demandato alla parte di scripting della stessa. Il server, invece, potrebbe essere stato sviluppato usando un altro linguaggio, come Java o PHP, e per ricreare la view da inviare al client dovrebbe in qualche modo emularne il comportamento: un compito decisamente laborioso e soggetto ad errori.
Di conseguenza, l’architettura del server dovrebbe essere ripensata in maniera tale che la creazione della pagina sia compito di un motore in grado di eseguire il JavaScript in essa presente, e questo comporta dover utilizzare un server Node.js per questo scopo.
Immaginando un’architettura molto semplice, un server HTTP smisterà le richieste effettuate dal client verso una CDN per le risorse statiche, oppure verso il server che espone le API per l’applicazione web, e in tutti gli altri casi verso il server Node.js per la creazione della view.
Questo sistema ha anche il vantaggio collaterale di permettere di rispondere con un codice di errore adeguato nel caso di richiesta non corretta (come 404 o 401), invece del comune codice di stato 200 se si lascia l’operazione di creazione della view al client. Questo non ha normalmente impatto su un comune utente che naviga nel sito, ma può fare la differenza per un bot per capire se un indirizzo è realmente valido o inaccessibile.
Sulla strada dell’ottimizzazione
Ci sono tanti altri accorgimenti che si possono prendere per migliorare le performance della propria applicazione o sito web. In particolare, il lazy loading delle risorse, che consiste nel caricamento di immagini, font, media, fogli di stile o script solo nel momento in cui è effettivamente richiesto dal client.
Il passo successivo consiste nel limitarsi a gestire inizialmente solo il contenuto above-the-fold (termine preso dalla carta stampate che indica il contenuto che l’utente vede in cima alla pagina). Si tratta della separazione del critical rendering path dal resto dell’applicazione, in cui si può anche fare in modo che alcune risorse (come fogli di stile e script) vengano inviate inline nella pagina grazie, ancora una volta, al server-side rendering.
Queste tecniche portano a ridurre, anche drasticamente, le dimensioni delle risorse statiche trasferite all’utente. Le normali procedure di comunicazione con i server fanno sì che una prima breve “congestione” nel trasferimento dei dati avvenga dopo i primi 14.6 kB, per cui l’obiettivo ottimale consiste nell’inviare entro tale limite tutto il necessario per una prima visualizzazione della pagina.
Si tratta di tecniche avanzate che necessitano di approfondimenti separati, ma i vantaggi verrebbero meno senza un adeguato sistema di server-side rendering.