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 del framework PWA di eCommerce open source, React Storefront. All’inizio di quest’anno, abbiamo contribuito con molte nuove funzioni e ottimizzazioni 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 funzionalità 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 pacchetto del browser.

Si è trattato di un buon guadagno all’epoca e ha contribuito a migliorare i punteggi delle prestazioni di Lighthouse (v5.7) per le tipiche app React Storefront dagli anni ’80 agli anni ’90, misurati da PageSpeed Insights (PSI). Per 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 sarebbe stata essenziale la riduzione del pacchetto nei prossimi mesi, quando Lighthouse v6.0 sarebbe caduto come una bomba e avrebbe cancellato i punteggi delle prestazioni di tutti.

Scopri come la distribuzione dei punteggi Lighthouse misurata su PSI per i principali siti Web di e-commerce è cambiata quando la versione 6.0 è scesa:

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 nel 2021. Il punteggio delle prestazioni di Lighthouse non verrà utilizzato, anche se alcuni elementi utilizzati per determinare tale punteggio saranno, e anche allora, non saranno misurati utilizzando un test sintetico come Lighthouse, ma piuttosto i dati del campo reale del Chrome User Experience Report (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 di prestazioni Lighthouse di una pagina.

Faro 5,7 Peso Faro 6,0 Peso
First Contentful Paint (FCP) 20% First Contentful Paint (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 totale di blocco (TBT) 15%
Tempo di interazione (TTI) 33% Tempo di interazione (TTI) 15%
- - Spostamento layout cumulativo (CLS) 5%

Tempo totale di blocco (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 difficile le moderne spa/PWA pesanti da JavaScript. Anche con React Storefront 7, che ha ridotto del 50% le dimensioni del bundle, abbiamo visto un calo di 20 a 30 punti nel punteggio delle prestazioni di Lighthouse v6.0 per le pagine dei prodotti, in gran parte dovuto all’inclusione del TBT come parametro che influenza il 25% del punteggio complessivo delle prestazioni.

Se si utilizza un framework isomorfo, come Next.js, che supporta il rendering lato server, il TBT è principalmente determinato 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 ha lo scopo di quantificare il modo in cui l’utente percepisce le prestazioni di caricamento della pagina iniziale osservando quanto tempo impiega l’elemento contentful più grande per completare la verniciatura. Per la maggior parte dei siti, specialmente nei siti di eCommerce, l’elemento più contento è l’immagine eroica. Nel caso di pagine di prodotti nelle app React Storefront, l’elemento contentful più grande è 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 è causato più comunemente dalle immagini, che tendono a spingere gli elementi intorno a loro mentre si ridimensionano per ospitare l’immagine una volta scaricati i dati dalla rete. Lo spostamento del layout spesso può essere completamente eliminato riservando spazio per ogni immagine prima di caricarla. Fortunatamente, il componente Image di React Storefront lo fa già, quindi l’app Starter di React Storefront vanta un punteggio CLS perfetto pari a 0.

Va notato che altri colpevoli comuni di CLS scadenti sono i banner e i popup che appaiono dopo la prima colorazione della pagina. 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 iniziale React Storefront su Lighthouse v6.0, utilizzando PageSpeed Insights, ha ottenuto un punteggio di 60 secondi:

Per migliorare il punteggio, abbiamo innanzitutto puntato su LCP. A 2,5 secondi, FCP era preoccupante (arriveremo a questo punto più tardi), ma il divario di quasi 3 secondi tra FCP e LCP si è distinto come qualcosa che doveva essere migliorato.

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 divario, abbiamo inserito l’immagine utilizzando un URL dati base64 come questo:

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

				
			

Per farlo, abbiamo scaricato l’immagine principale, convertita in base64 e inserito 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 passare 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 esecuzioni, ma il punteggio complessivo è stato costantemente nei 80 secondi più bassi Per Context, il sito di e-commerce leader con le prestazioni più elevate sulla v6.0 è 87, come misurato sulla PSI, e sembra che sia subito fuori dagli anni ’90 – dai un’occhiata a www.rockauto.com

Il divario tra FCP e LCP mostrato sopra è stato di circa lo stesso che abbiamo visto in diverse corse. La maggior parte delle volte l’intervallo era compreso tra 100 ms e 300 ms. Occasionalmente FCP e LCP erano uguali.

Ottimizzazione del TBT

Successivamente, abbiamo cercato di migliorare il TBT. E’ stato piuttosto impegnativo. Come accennato in precedenza, per migliorare LCP, è necessario ridurre le dimensioni del pacchetto JavaScript o migliorare il tempo 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 tempo di compilazione che riducono al minimo le dimensioni del bundle fornite dalla configurazione del webpack di Next.js, nonché ottimizzazioni babel specifiche per Material UI. Allora, dove possiamo migliorare? Tempo di idratazione.

Lazy Hydration per la vittoria!

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

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

L’idratazione pigra comporta il ritardo dell’idratazione di alcuni componenti fino a quando non è assolutamente necessario e, soprattutto, dopo il caricamento iniziale della pagina (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.

Implementare l’idratazione pigra su React Storefront si è rivelato piuttosto difficile a causa della dipendenza di Material UI 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 dell’albero dei componenti per ritardare l’idratazione fino a quando non si verifica un evento specifico, come l’elemento che viene scorrezzato nella vista o l’utente che tocca lo schermo.

Ecco un esempio in cui pigro idratare 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 in diverse aree dell’applicazione, in particolare:

  • Menu a scorrimento: Idratiamo questo fenomeno quando l’utente preme il pulsante hamburger.
  • Tutti i controlli sotto la piega includono i selettori di dimensioni, colore e quantità, nonché le schede delle informazioni sul prodotto.
  • Carosello immagini principale: Questo e il menu principale sono probabilmente i componenti con più funzionalità e, quindi, i più costosi da idratare.

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

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

Noterai che l’FCP è salito un po’, ma l’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 le seriografie.

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>
				
			

L’uso di ANC 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 invece di 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" />
				
			

Siamo lieti che ciò abbia migliorato il LCP e i punteggi complessivi:

Ha anche leggermente urtato l’FCP su 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 il rinvio 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 Starter React Storefront erano alterate nei bassi anni ’60 Con queste ottimizzazioni, l’abbiamo messa nell’aria ora rarificata dei bassi 90 A questo punto, riteniamo che l’unico modo per migliorare ulteriormente il punteggio sarebbe rimuovere le dipendenze, il che potrebbe significare mettere in discussione 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:

Preact

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

Frazionamento

Next.js ha recentemente introdotto un frazionamento più dettagliato delle risorse del browser. Quando è stato introdotto per la prima volta in Next.js 9,1, abbiamo notato che i frammenti aggiuntivi più piccoli in realtà peggioravano TTI. Probabilmente rende l’app più veloce per il ritorno degli utenti dopo il rilascio di una nuova versione perché può sfruttare meglio la cache del browser, ma Lighthouse non si preoccupa di nulla di tutto ciò. Quindi React Storefront ha limitato il numero di frammenti 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 font Web personalizzato. Per impostazione predefinita, React Storefront utilizza Roboto (anche se può essere modificato o rimosso). I font Web personalizzati riducono le prestazioni, semplici e semplici. Rimuovi il font Web e otterrai circa 1 secondo di FCP.

Come nel caso dell’analisi, gli stakeholder sembrano disposti a mettere in discussione le prestazioni per avere un font specifico. React Storefront serve il font Web dalla stessa origine del sito per eliminare il tempo di negoziazione TLS che si dovrebbe attendere se si carica il font da una CDN di terze parti, ad esempio Google Fonts. Nello specifico, 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 ed analizzare. Pensavamo che l’inlining di quel CSS nel documento potesse aiutare con le prestazioni, ma non lo è stato

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

Aumenta il tuo punteggio Lighthouse

I nostri clienti si posizionano al 95° percentile dei primi 500 siti Web di e-commerce su Lighthouse v6.0.

Pianifica una conversazione consultiva!