Incorporamento di risorse nei framework JavaScript

Migliorare Largest Contentful Paint nell'ecosistema JavaScript.

Nell'ambito del progetto Aurora, Google sta collaborando con i più diffusi framework web per garantirne le buone prestazioni secondo i Core Web Vitals. Angular e Next.js hanno già inserito il carattere incorporato, come spiegato nella prima parte di questo articolo. La seconda ottimizzazione che tratteremo è l'incorporamento di CSS critico, che ora è abilitato per impostazione predefinita nell'interfaccia a riga di comando di Angular e ha un'implementazione in corso in Nuxt.js.

Caratteri incorporati

Dopo aver analizzato centinaia di applicazioni, il team di Aurora ha scoperto che gli sviluppatori spesso includono caratteri nelle applicazioni facendoli riferimento nell'elemento <head> di index.html. Ecco un esempio di come apparirà una volta includendo le icone Material:

<!doctype html>
<html lang="en">
<head>
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  ...
</html>

Anche se questo pattern è completamente valido e funzionale, blocca il rendering dell'applicazione e introduce una richiesta aggiuntiva. Per comprendere meglio il problema, osserva il codice sorgente del foglio di stile indicato nel precedente codice HTML:

/* fallback */
@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/font.woff2) format('woff2');
}

.material-icons {
  /*...*/
}

Osserva come la definizione di font-face fa riferimento a un file esterno ospitato su fonts.gstatic.com. Durante il caricamento dell'applicazione, il browser deve prima scaricare il foglio di stile originale indicato nell'intestazione.

Un&#39;immagine che mostra come il sito web deve effettuare una richiesta al server e scaricare il foglio di stile esterno
Per prima cosa, il sito web carica il foglio di stile del carattere.

Successivamente, il browser scarica il file woff2 e, infine, può procedere con il rendering dell'applicazione.

Un&#39;immagine che mostra le due richieste effettuate, una per il foglio di stile del carattere e la seconda per il file del carattere.
Successivamente, viene richiesto il caricamento del carattere.

Un'opportunità per l'ottimizzazione consiste nel scaricare il foglio di stile iniziale al momento della creazione e incorporarlo in index.html. In questo modo viene saltato un intero round trip alla CDN in fase di runtime, riducendo il tempo di blocco.

Durante la creazione dell'applicazione, viene inviata una richiesta alla rete CDN che recupera il foglio di stile e lo inserisce nel file HTML, aggiungendo un <link rel=preconnect> al dominio. Applicando questa tecnica, otterremmo il seguente risultato:

<!doctype html>
<html lang="en">
<head>
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin >
  <style type="text/css">
  @font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/font.woff2) format('woff2');}.material-icons{/*...*/}</style>
  ...
</html>

I caratteri incorporati sono ora disponibili in Next.js e Angular

Quando gli sviluppatori di framework implementano l'ottimizzazione negli strumenti sottostanti, semplificano l'abilitazione delle applicazioni nuove e esistenti, portando il miglioramento all'intero ecosistema.

Questo miglioramento è attivato per impostazione predefinita da Next.js v10.2 e Angular v11. Entrambi supportano l'incorporamento dei caratteri Google e Adobe. Angular prevede di introdurre quest'ultimo nella versione 12.2.

Puoi trovare l'implementazione del font inlining in Next.js su GitHub e guardare il video che spiega questa ottimizzazione nel contesto di Angular.

Incorporazione di CSS fondamentale

Un altro miglioramento comporta il miglioramento delle metriche First Contentful Paint (FCP) e Largest Contentful Paint (LCP) tramite l'incorporamento di un CSS fondamentale. Il CSS fondamentale di una pagina include tutti gli stili usati nella visualizzazione iniziale. Per scoprire di più sull'argomento, consulta Rimandare i CSS non critici.

Abbiamo notato che molte applicazioni caricano gli stili in modo sincrono, il che blocca il rendering delle applicazioni. Una soluzione rapida consiste nel caricare gli stili in modo asincrono. Anziché caricare gli script con media="all", imposta il valore dell'attributo media su print e, una volta completato il caricamento, sostituisci il valore dell'attributo con all:

<link rel="stylesheet" href="..." media="print" onload="this.media='all'">

Questa pratica, tuttavia, può causare uno sfarfallio dei contenuti senza stile.

La pagina sembra sfarfallare quando vengono caricati gli stili.

Il video riportato sopra mostra il rendering di una pagina, che carica i suoi stili in modo asincrono. Lo sfarfallio si verifica perché il browser inizia a scaricare gli stili, quindi esegue il rendering del codice HTML che segue. Una volta che il browser scarica gli stili, attiva l'evento onload dell'elemento link, aggiornando l'attributo media in all e applica gli stili al DOM.

Nell'intervallo di tempo che intercorre tra il rendering del codice HTML e l'applicazione degli stili, la pagina risulta parzialmente priva di stile. Quando il browser utilizza gli stili, notiamo uno sfarfallio, che rappresenta un'esperienza utente negativa e genera regressioni in Cumulative Layout Shift (CLS).

L'incorporamento fondamentale di CSS, insieme al caricamento in stile asincrono, possono migliorare il comportamento di caricamento. Lo strumento critters individua gli stili utilizzati nella pagina osservando i selettori in un foglio di stile e confrontandoli con il codice HTML. Quando trova una corrispondenza, considera gli stili corrispondenti come parte del CSS fondamentale e li incorpora.

Ad esempio:

Cosa non fare
<head>
   <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
</head>
<body>
  <section>
    <button class="primary"></button>
  </section>
</body>
/* styles.css */
section button.primary {
  /* ... */
}
.list {
  /* ... */
}

Esempio prima di incorporarli.

Nell'esempio precedente, le bestioline leggono e analizzano i contenuti di styles.css. Dopodiché, associa i due selettori al codice HTML e scopre che utilizziamo section button.primary. Infine, le bestioline incorporano gli stili corrispondenti nell'elemento <head> della pagina, ottenendo come risultato:

Cosa fare
<head>
  <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
  <style>
  section button.primary {
    /* ... */
  }
  </style>
</head>
<body>
  <section>
    <button class="primary"></button>
  </section>
</body>

Esempio dopo l'incorporamento.

Dopo aver incorporato il codice CSS fondamentale nell'HTML, noterai che lo sfarfallio della pagina è scomparso:

Il caricamento della pagina dopo l'incorporamento in CSS.

L'incorporamento critico di CSS è ora disponibile in Angular e attivato per impostazione predefinita nella versione 12. Se stai utilizzando la versione 11, attivala impostando la proprietà inlineCritical su true in angular.json. Per attivare questa funzionalità in Next.js, aggiungi experimental: { optimizeCss: true } a next.config.js.

Conclusioni

In questo post abbiamo parlato di alcune delle collaborazioni tra Chrome e framework web. Se sei un autore di framework e riconosci alcuni dei problemi che abbiamo affrontato nella tua tecnologia, speriamo che le nostre scoperte ti ispirano ad applicare ottimizzazioni del rendimento simili.

Scopri di più sui miglioramenti. Puoi trovare un elenco completo del lavoro di ottimizzazione che abbiamo svolto per i Segnali web essenziali nel post Ti presentiamo Aurora.