Home Blogs Ottimizzazione del sito Web per Lighthouse v6.0
Applications

Ottimizzazione del sito Web per Lighthouse v6.0

About The Author

Outline

Layer0 è uno dei principali contributori al framework open source PWA di eCommerce, React Storefront. All’inizio di quest’anno, abbiamo contribuito con molte nuove funzioni e ottimizzazioni AS React Storefront v7, Due dei più significativi sono stati il passaggio a Next.js e la rimozione di diverse dipendenze chiave (ad esempio MobX) a favore delle nuove capacità integrate di React per la gestione dello stato, come l’hook useState e l’API Context. Ciò ha comportato un taglio approssimativo della metà delle dimensioni del bundle del browser.

Questo è stato un buon guadagno all’epoca e ha contribuito a migliorare i punteggi delle prestazioni di Bump Lighthouse (v5.7) per le tipiche app React Storefront dagli anni ’80 agli anni ’90, misurate con PageSpeed Insights (PSI). Per quanto riguarda il contesto, un punteggio di oltre 83% ha superato il 99% dei primi 500 siti Web di e-commerce su Lighthouse v5.7. Non ci rendevamo conto di quanto fosse essenziale la riduzione del pacchetto nei prossimi mesi, quando Lighthouse v6.0 sarebbe caduto come una bomba e cancellerebbe i punteggi delle prestazioni di tutti.

Scopri come la distribuzione dei punteggi di Lighthouse misurati su PSI per i principali siti Web di e-commerce è cambiata quando la versione v6.0 è caduta:

In questo post, condividiamo come abbiamo migliorato i punteggi Lighthouse v6.0 per React Storefront, ma le tecniche possono essere applicate ad altri framework.
Inoltre, è importante notare che Google ha annunciato il 28 maggio 2020, le metriche specifiche che useranno per classificare i siti in 2021. Il punteggio delle prestazioni di Lighthouse non verrà utilizzato, anche se alcuni elementi utilizzati per determinare tale punteggio, e anche in questo caso, non verranno misurati utilizzando un test sintetico come Lighthouse, ma dati di campo reali ricavati dal report dell’esperienza utente Chrome (Crux).

Le nuove metriche di Lighthouse 6,0: TBT, LCP e CLS

Lighthouse v6.0 introduce diverse nuove metriche di velocità percettiva e riformula il modo in cui le metriche complessive influiscono sul punteggio delle prestazioni di Lighthouse di una pagina.
Faro 5,7 Peso Faro 6,0 Peso
Primo contenuto di vernice (FCP) 20% Primo contenuto di vernice (FCP) 15%
Indice di velocità (si) 27% Indice di velocità (si) 15%
Prima vernice significativa (FMP) 7% LCP (Large Contenful Paint) 25%
Prima CPU inattiva (FCI) 13% Tempo di blocco totale (TBT) 15%
Tempo di interattività (TTI) 33% Tempo di interattività (TTI) 15%
- - Spostamento layout cumulativo (CLS) 5%

Tempo di blocco totale (TBT)

Il tempo di blocco totale è una nuova metrica inclusa in Lighthouse v6.0 che misura il tempo in cui l’analisi e l’esecuzione di JavaScript blocca il thread principale durante il caricamento della pagina. Questa metrica tratta in modo molto duro le moderne SPA/PWA con uso pesante di JavaScript. Anche con il taglio del 50% di React Storefront 7 nelle dimensioni del pacchetto, abbiamo visto un calo di 20 – 30 punti nel punteggio delle prestazioni di Lighthouse v6.0 per le pagine dei prodotti, in gran parte dovuto all’inclusione del TBT come metrica che influenza il 25% del punteggio complessivo delle prestazioni.

Se si utilizza un framework isomorfico, come Next.js, che supporta il rendering lato server, il TBT è determinato principalmente dalla dimensione del bundle e dal tempo di idratazione. In poche parole, l’unico modo per migliorare il TBT è rimuovere le dipendenze, ottimizzare i componenti o semplificare il sito utilizzando un numero inferiore di componenti.

LCP (Large Contentful Paint)

LCP è una nuova metrica che ha un peso del 25% rispetto al punteggio complessivo di Lighthouse v6.0. LCP mira a quantificare il modo in cui l’utente percepisce le prestazioni di caricamento della pagina iniziale osservando quanto tempo impiega l’elemento contento più grande per finire la pittura. Per la maggior parte dei siti, specialmente nei siti Web di e-commerce, l’elemento più grande contento è l’immagine dell’eroe. Nel caso di pagine di prodotti nelle app React Storefront, l’elemento più importante è l’immagine principale del prodotto. Se non sei sicuro di quale elemento questo sia sul tuo sito, PSI ti dirà:

Per ottimizzare per LCP, è necessario assicurarsi che l’immagine venga caricata il più rapidamente possibile.

Spostamento layout cumulativo (CLS)

Lo spostamento cumulativo del layout misura lo spostamento del layout di pagina durante il caricamento iniziale della pagina. Lo spostamento del layout è più comunemente causato dalle immagini, che tendono a spingere gli elementi intorno a loro mentre si ridimensionano per adattarsi all’immagine una volta scaricati i dati dalla rete. Lo spostamento del layout può spesso essere completamente eliminato riservando spazio per ogni immagine prima del caricamento. Fortunatamente, il componente Image di React Storefront lo fa già, quindi l’app iniziale React Storefront vanta un punteggio CLS perfetto di 0 pronto all’uso. Va notato che altri colpevoli comuni di CLS scadenti sono striscioni e popup che compaiono dopo che la pagina è stata inizialmente dipinta. Gli utenti li odiano e ora anche Lighthouse lo fa.

Come abbiamo ottimizzato React Storefront per Lighthouse v6.0

Quando abbiamo testato per la prima volta la pagina del prodotto dell’app di base React Storefront su Lighthouse v6.0, utilizzando PageSpeed Insights, ha ottenuto un punteggio minimo di 60:

Per migliorare il punteggio, ci concentriamo innanzitutto su LCP. A 2,5 secondi, FCP era preoccupante (ci arriveremo più tardi), ma il divario di quasi 3 secondi tra FCP e LCP si è distinto come qualcosa che aveva bisogno di miglioramenti.

Ottimizzazione LCP

L’immagine principale del prodotto di React Storefront (semplicemente un segnaposto – la casella verde con il “prodotto 1” al centro) è stata resa come tag HTML img con un URL src che punta a https://via.placeholder.com. Quel sito ha un TTFB decente (circa 150 ms), che potrebbe essere migliorato passando a una CDN più veloce come Layer0 CDN-as-JavaScript. Tuttavia, abbiamo dubitato che 150 ms rappresentassero il divario di quasi 3 secondi tra FCP e LCP. Per eliminare il gap, abbiamo inlineato l’immagine utilizzando un URL dati base64 come questo:

				
					<img decoding="async" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAA…"/>

				
			

Lo abbiamo fatto scaricando l’immagine principale, convertendola in base64 e inserendola nell’attributo src durante il rendering lato server sul cloud JavaScript senza server di Layer0. Ecco la linea nell’endpoint API del prodotto:

				
					const mainProductImage = result.product.media.full[0]
mainProductImage.src = await getBase64ForImage(mainProductImage.src)
				
			

Ed ecco il codice che recupera e converte l’immagine in base 64:

				
					import fetch from 'node-fetch'

export default async function getBase64ForImage(src) {
  const res = await fetch(src)
  const contentType = res.headers.get('content-type')
  const buffer = await res.buffer()
  return `data:${contentType};base64,${buffer.toString('base64')}`
return `data:${contentType};base64,${buffer.toString('base64')}` return `data:${contentType};base64,${buffer.toString('base64')}` return `data:${contentType};base64,${buffer.toString('base64')}`
}

				
			

Piuttosto semplice e vecchia scuola. E l’impatto sul punteggio?

Facendo scendere l’LCP da 5,3 a 2,8 s, abbiamo guadagnato 21 punti nel punteggio Lighthouse v6.0 della pagina! È un po’ inquietante come un cambiamento così piccolo possa influenzare drammaticamente il punteggio di Lighthouse v6.0, ma lo prenderemo. Va notato che tutte le metriche variano in qualche modo tra le corse, ma il punteggio complessivo è stato costante nei 80 anni più bassi Per quanto riguarda il contesto, il sito Web di e-commerce più performante della v6.0 ha ottenuto 87 risultati misurati sulla PSI e sembra che sia proprio degli anni ’90: Dai un’occhiata al www.rockauto.com

Il divario tra FCP e LCP mostrato in precedenza era circa pari a quello che abbiamo visto in diverse piste. La maggior parte delle volte il divario era compreso tra 100 ms e 300 ms. Occasionalmente FCP e LCP erano gli stessi.

Ottimizzazione TBT

Successivamente, abbiamo cercato di migliorare il TBT. E’ stato piuttosto impegnativo. Come accennato in precedenza, per migliorare LCP, è necessario ridurre le dimensioni del bundle JavaScript o migliorare i tempi di idratazione. Con la maggior parte delle app, semplicemente non è possibile iniziare a strappare le dipendenze per ridurre il pacchetto. Le app create con React Storefront 7 beneficiano già di molte ottimizzazioni in fase di compilazione che riducono al minimo le dimensioni del pacchetto fornite dalla configurazione del webpack di Next.js, nonché di specifiche ottimizzazioni babel per l’interfaccia utente dei materiali . Dove possiamo migliorare? Tempo di idratazione.

Pigro idratazione per la vittoria!

Fortunatamente, la comunità React Storefront aveva già iniziato a lavorare per sostenere l’idratazione pigra prima che Lighthouse v6.0 scendesse. Questo ci ha certamente fatto accelerare i nostri sforzi.

Nel caso in cui tu non sia consapevole, idratazione si riferisce a React che prende il controllo degli elementi HTML resi sul server in modo che possano diventare interattivi. I pulsanti diventano cliccabili; le sequenze diventano scorrevoli, ecc. Maggiore è il numero di componenti di una pagina, maggiore sarà il tempo necessario per l’idratazione. I componenti complessi, come il menu principale e la sequenza di immagini del prodotto, richiedono ancora più tempo.

L’idratazione pigra comporta ritardare l’idratazione di alcuni componenti fino a quando non è assolutamente necessaria e, soprattutto, dopo il caricamento della pagina iniziale (e dopo il calcolo del TBT). L’idratazione pigra può essere rischiosa. È necessario assicurarsi che gli elementi della pagina siano pronti a rispondere all’input dell’utente prima che l’utente tenti di interagire con essi.

L’implementazione dell’idratazione pigra su React Storefront si è rivelata piuttosto difficile a causa della dipendenza dell’interfaccia utente Material da CSS-in-JS, che aggiunge dinamicamente stili al documento solo dopo che i componenti sono stati idratati. Salverò i dettagli per un’altra volta. Alla fine, abbiamo creato un componente LazyHydrate che gli sviluppatori possono inserire in qualsiasi punto della struttura dei componenti per ritardare l’idratazione fino a quando non si verifica un evento specifico, ad esempio l’elemento che viene scorrato nella vista o l’utente che tocca lo schermo.

Ecco un esempio in cui si idrata pigramente il MediaCarousel che visualizza le immagini principali del prodotto:

				
					 import LazyHydrate from 'react-storefront/LazyHydrate'
<LazyHydrate id="carousel" on="touch">
  <MediaCarousel
    ...
  />
</LazyHydrate> 

				
			

Abbiamo applicato l’idratazione pigra a diverse aree dell’applicazione, in particolare:

  • Menu di scorrimento: Idratiamo questo aspetto quando l’utente tocca il pulsante hamburger.
  • Tutti i controlli sotto la piega: Includono i selettori di dimensione, colore e quantità, nonché le schede delle informazioni sul prodotto.
  • Il carosello immagini principale: Questo e il menu principale sono probabilmente i componenti con la maggior funzionalità e, quindi, i più costosi da idratare.

Ecco il punteggio di Lighthouse v6.0 con idratazione pigra applicata:

L’idratazione pigra ha tagliato il TBT di quasi il 40% e il TTI rifinito (che ha un peso del 15% sopra i punteggi nella v6.0) di 700 ms. Questo ha segnato un guadagno di 6 punti nel punteggio complessivo di Lighthouse v6.0.

Noterai che FCP è salito un po’, ma LCP è sceso. Queste piccole modifiche sono essenzialmente “all’interno del rumore” che si ottiene quando si esegue PageSpeed Insights. Tutti i punteggi fluttuano leggermente tra una corsa e l’altra.

Ottimizzazione FCP

In base al punteggio sopra riportato, abbiamo ritenuto che FCP e/o LCP potessero essere ulteriormente migliorati. Sappiamo che gli script possono bloccare il rendering, quindi abbiamo esaminato come Next.js importa gli script nel documento:

				
					<scriptsrc="/_next/static/runtime/main-cb5fd281935517c43f30.js"async=""></script>
				
			

Usare ASYNC qui potrebbe non essere la scelta migliore. Se lo script viene scaricato durante il rendering, può mettere in pausa il rendering durante la valutazione dello script, aumentando i tempi di FCP e LCP. L’uso di differimento anziché asincrono garantirebbe che gli script vengano valutati solo dopo che il documento è stato dipinto.

Sfortunatamente, Next.js non consente di modificare il modo in cui gli script vengono importati, quindi abbiamo dovuto estendere il componente NextScript come segue:

				
					import React from 'react'
import { NextScript as OriginalNextScript } from 'next/document'
/**
 * A replacement for NextScript from `next/document` that gives you greater control over how script elements are rendered.
 * This should be used in the body of `pages/_document.js` in place of `NextScript`.
 */
export default class NextScript extends OriginalNextScript {
  static propTypes = {
    /**
     * Set to `defer` to use `defer` instead of `async` when rendering script elements.
     */
    mode: PropTypes.oneOf(['async', 'defer']),
  }
  static defaultProps = {
    mode: 'async',
  }
  getScripts() {
    return super.getScripts().map(script => {
      return React.cloneElement(script, {
        key: script.props.src,
        defer: this.props.mode === 'defer' ? true : undefined,
        async: this.props.mode === 'async' ? true : undefined,
      })
    })
  }
}

				
			

Quindi abbiamo aggiunto quanto segue a Pages/_document.js:

				
					 <NextScript mode="defer" />
				
			

Con nostra grande soddisfazione, questo ha migliorato il punteggio complessivo e l’LCP:

Ha anche leggermente urtato l’FCP in molte corse, ma questo potrebbe essere all’interno del “rumore”. Tuttavia, il punteggio complessivo è stato costantemente di 2-3 punti più alto quando si utilizza differimento vs asincrono.

Riepilogo

Quando Lighthouse v6.0 è stato rilasciato alla fine di maggio 2020, i punteggi delle prestazioni per molti siti, tra cui le app React Storefront, sono crollati. Prima delle ottimizzazioni, le prestazioni PDP dell’app iniziale React Storefront erano impantanate nei bassi anni ’60 Con queste ottimizzazioni, l’abbiamo fatta entrare nell’aria ormai rarizzata dei bassi 90 A questo punto, riteniamo che l’unico modo per migliorare ulteriormente il punteggio sia rimuovere le dipendenze, il che potrebbe significare compromettere la produttività degli sviluppatori per le prestazioni delle applicazioni.

Questa è una discussione per un’altra volta. Lascia che ti lasci con alcune cose che abbiamo provato che non hanno funzionato:

Preimpostazione

Preact riduce le dimensioni del pacchetto del 20-30%, ma i punteggi di Lighthouse v6.0 sono risultati costantemente peggiori in tutte le metriche, anche TTI. Non abbiamo idea del perché, ma sappiamo che questo non è nuovo o esclusivo di Lighthouse v6.0. Era più lento anche con Lighthouse v5.7. Continuiamo a fare il check-in periodicamente e speriamo che un giorno questo sia risolto.

Frazionamento

Next.js ha introdotto di recente il chunking più fine delle risorse del browser. Quando è stato introdotto per la prima volta in Next.js 9,1, abbiamo notato che i pezzi aggiuntivi, più piccoli, in realtà hanno peggiorato il TTI. Probabilmente rende l’app più veloce per gli utenti che ritornano dopo il rilascio di una nuova versione perché può sfruttare meglio la cache del browser, ma Lighthouse non si preoccupa di nulla di tutto questo. Quindi React Storefront ha limitato il numero di parti del browser a uno per un po’:

				
					const webpack = require('webpack')
const withReactStorefront = require('react-storefront/plugins/withReactStorefront')
module.exports = withReactStorefront({
  target: 'serverless',
  webpack: config => {
    config.plugins.push(
      new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 1,
      })
    )
    return config
  },
})

				
			

Font Web

La maggior parte dei siti utilizza un carattere Web personalizzato. Per impostazione predefinita, React Storefront utilizza Roboto (anche se può essere modificato o rimosso). I font Web personalizzati eliminano le prestazioni, in modo semplice e semplice. Rimuovi il font Web e otterrai circa 1 secondo di FCP.

Come per l’analisi, le parti interessate sembrano disposte a contrattare le prestazioni per avere un carattere specifico. React Storefront fornisce il font Web dalla stessa origine del sito per eliminare il tempo di negoziazione TLS che si dovrebbe sostenere se si carica il font da un CDN di terze parti, come Google Fonts. In particolare, utilizziamo il pacchetto typeface-roboto di NPM. Se combinato con il css-loader di Webpack , l’utilizzo di typeface-roboto comporta l’importazione del font tramite un file CSS separato che il browser deve scaricare e analizzare. Pensavamo che l’inserimento del CSS nel documento potesse aiutare con le prestazioni, ma non è stato così

Quando si tratta di prestazioni, è sempre necessario misurare. Le ottimizzazioni che dovrebbero funzionare in teoria potrebbero non essere in pratica.

Aumenta il tuo punteggio di Lighthouse

I nostri clienti si classificano al 95° percentile dei 500 siti di e-commerce più importanti su Lighthouse v6.0.

Pianificate una conversazione consultiva!