Un pacchetto Next.js per la gestione delle librerie di terze parti

Nel 2021, il team di Chrome Aurora ha introdotto il componente Script per migliorare le prestazioni di caricamento degli script di terze parti in Next.js. Dal suo lancio, abbiamo sviluppato le sue funzionalità per semplificare e velocizzare il caricamento delle risorse di terze parti per gli sviluppatori.

Questo post del blog fornisce una panoramica delle funzionalità più recenti che abbiamo rilasciato, in particolare la libreria @next/third-parties, nonché un'idea delle iniziative future previste nella nostra roadmap.

Implicazioni sul rendimento degli script di terze parti

Il 41% di tutte le richieste di terze parti nei siti Next.js sono script. A differenza di altri tipi di contenuti, il download e l'esecuzione degli script possono richiedere molto tempo, il che può bloccare il rendering e ritardare l'interattività dell'utente. I dati del Report sull'esperienza utente di Chrome (CrUX) mostrano che i siti Next.js che caricano più script di terze parti hanno tassi di superamento Interaction to Next Paint (INP) e Largest Contentful Paint (LCP).

Grafico a barre che mostra un calo della percentuale di Next.js che ottiene buoni punteggi INP e LCP in proporzione al numero di elementi di terze parti caricati
Report CrUX di dicembre 2023 (110.823 siti)

La correlazione osservata in questo grafico non implica una relazione di causa ed effetto. Tuttavia, gli esperimenti locali forniscono ulteriori prove del fatto che gli script di terze parti influiscono in modo significativo sul rendimento delle pagine. Ad esempio, il grafico riportato di seguito confronta varie metriche dei lab quando un contenitore di Google Tag Manager, composto da 18 tag selezionati casualmente, viene aggiunto a Taxonomy, una popolare app di esempio di Next.js.

Grafico a barre che mostra la differenza tra varie metriche di laboratorio quando un sito viene caricato con e senza Google Tag Manager
WebPageTest (rete mobile 4G - Virginia, Stati Uniti)

La documentazione di WebPageTest fornisce dettagli su come vengono misurati questi tempi. A prima vista, è chiaro che tutte queste metriche di laboratorio sono interessate dal contenitore GTM. Ad esempio, il tempo di blocco totale (TBT), un utile proxy di laboratorio che approssima l'INP, ha registrato un aumento di quasi 20 volte.

Componente Script

Quando abbiamo rilasciato il componente <Script> in Next.js, ci siamo assicurati di introdurlo tramite un'API facile da usare che somiglia molto all'elemento <script> tradizionale. Utilizzandolo, gli sviluppatori possono collocare uno script di terze parti in qualsiasi componente della loro applicazione e Next.js si occuperà di sequenziare lo script dopo il caricamento delle risorse critiche.

<!-- By default, script will load after page becomes interactive -->
<Script src="https://example.com/sample.js" />

<!-- Script is injected server-side and fetched before any page hydration occurs -->
<Script strategy=”beforeInteractive” src="https://example.com/sample.js" />

<!-- Script is fetched later during browser idle time -->
<Script strategy=”lazyOnload” src="https://example.com/sample.js" />

Decine di migliaia di applicazioni Next.js, inclusi siti popolari come Patreon, Target e Notion, utilizzano il componente <Script>. Nonostante la sua efficacia, alcuni sviluppatori hanno sollevato dubbi in merito ai seguenti aspetti:

  • Dove posizionare il componente <Script> in un'app Next.js rispettando le varie istruzioni di installazione dei diversi provider di terze parti (esperienza per gli sviluppatori).
  • Qual è la strategia di caricamento più ottimale da utilizzare per diversi script di terze parti (esperienza utente).

Per risolvere entrambi i problemi, abbiamo lanciato @next/third-parties, una biblioteca specializzata che offre un insieme di componenti e utilità ottimizzati personalizzati per terze parti di uso comune.

Esperienza degli sviluppatori: gestione semplificata delle librerie di terze parti

Molti script di terze parti vengono utilizzati in una percentuale significativa dei siti Next.js; Google Tag Manager è il più popolare ed è usato rispettivamente dal 66% dei siti. @next/third-parties si basa sul componente <Script> introducendo wrapper di livello superiore progettati per semplificare l'utilizzo in questi casi d'uso comuni.

import { GoogleAnalytics } from "@next/third-parties/google";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleTagManager gtmId="GTM-XYZ" />
    </html>
  );
}

Anche Google Analytics, un altro script di terze parti ampiamente utilizzato (52% dei siti Next.js), ha un proprio componente dedicato.

import { GoogleAnalytics } from "@next/third-parties/google";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleAnalytics gaId="G-XYZ" />
    </html>
  );
}

@next/third-parties semplifica il processo di caricamento degli script di uso comune, ma estende anche la nostra capacità di sviluppare utilità per altre categorie di terze parti, come gli elementi incorporati. Ad esempio, gli incorporamenti di Google Maps e YouTube vengono utilizzati rispettivamente nell'8% e nel 4% dei siti web Next.js. Inoltre, abbiamo fornito dei componenti per renderli più semplici da caricare.

import { GoogleMapsEmbed } from "@next/third-parties/google";
import { YouTubeEmbed } from "@next/third-parties/google";

export default function Page() {
  return (
    <>
      <GoogleMapsEmbed
        apiKey="XYZ"
        height={200}
        width="100%"
        mode="place"
        q="Brooklyn+Bridge,New+York,NY"
      />
      <YouTubeEmbed videoid="ogfYd705cRs" height={400} params="controls=0" />
    </>
  );
}

Esperienza utente: caricamento più rapido delle librerie di terze parti

In un mondo perfetto, ogni libreria di terze parti ampiamente utilizzata sarebbe completamente ottimizzata, rendendo superflue eventuali astrazioni che ne migliorano il rendimento. Tuttavia, finché non sarà realtà, potremo cercare di migliorare l'esperienza utente quando viene integrata tramite framework popolari come Next.js. Possiamo sperimentare diverse tecniche di caricamento, assicurarci che gli script vengano sequenziati nel modo corretto e infine condividere il nostro feedback con provider di terze parti per incoraggiare le modifiche upstream.

Prendiamo ad esempio gli embed di YouTube. Alcune implementazioni alternative hanno un rendimento molto migliore rispetto all'embed nativo. Attualmente, il componente <YouTubeEmbed> esportato da @next/third-parties utilizza lite-youtube-embed che, se dimostrato in un confronto di Next.js intitolato "Hello World", si carica più rapidamente.

GIF che mostra un confronto del caricamento pagina tra il componente Incorporamento di YouTube e un normale iframe di YouTube
WebPageTest (rete mobile 4G - Virginia, Stati Uniti)

Analogamente, per Google Maps includiamo loading="lazy" come attributo predefinito per l'embed per assicurarci che la mappa venga caricata solo quando si trova a una certa distanza dall'area visibile. Potrebbe sembrare un attributo ovvio da includere, soprattutto poiché la documentazione di Google Maps lo include nello snippet di codice di esempio, ma solo il 45% dei siti Next.js che incorporano Google Maps utilizza loading="lazy".

Esecuzione di script di terze parti in un worker web

Una tecnica avanzata che stiamo esplorando in @next/third-parties è semplificare il trasferimento degli script di terze parti a un web worker. Reso popolare da librerie come Partytown, questo approccio può ridurre notevolmente l'impatto degli script di terze parti sul rendimento della pagina riallocandoli completamente dal thread principale.

La seguente GIF animata mostra le variazioni nel tempo di blocco delle attività lunghe e del thread principale quando vengono applicate strategie <Script> diverse a un contenitore GTM all'interno di un sito Next.js. Tieni presente che, sebbene il passaggio da un'opzione di strategia all'altra solo ritardi i tempi di esecuzione di questi script, il loro trasferimento a un web worker elimina completamente il tempo che trascorrono nel thread principale.

GIF che mostra le differenze nel tempo di blocco del thread principale per le diverse strategie di script
WebPageTest (rete mobile 4G - Virginia, Stati Uniti)

In questo esempio specifico, lo spostamento dell'esecuzione del contenitore GTM e degli script dei tag associati in un web worker ha ridotto il TBT del 92%.

Vale la pena notare che, se non gestita con attenzione, questa tecnica può interrompere silenziosamente molti script di terze parti, rendendo difficile il debug. Nei prossimi mesi, convalideremo se eventuali componenti di terze parti offerti da @next/third-parties funzionano correttamente quando vengono eseguiti in un web worker. In questo caso, ci adopereremo per fornire agli sviluppatori un modo semplice e facoltativo per utilizzare questa tecnica.

Passaggi successivi

Durante il processo di sviluppo del pacchetto, è emerso che era necessario centralizzare i suggerimenti di caricamento di terze parti in modo che anche altri framework potessero trarre vantaggio dalle stesse tecniche sottostanti utilizzate. Questo ci ha portato a sviluppare Third Party Capital, una libreria che utilizza JSON per descrivere le tecniche di caricamento di terze parti, che attualmente costituisce la base di @next/third-parties.

Come passaggio successivo, continueremo a concentrarci sul miglioramento dei componenti forniti per Next.js e a impegnarci per includere utilità simili in altri framework e piattaforme CMS popolari. Al momento collaboriamo con i manutentori di Nuxt e prevediamo di rilasciare nel prossimo futuro utilità di terze parti simili personalizzate per il loro ecosistema.

Se una delle terze parti che utilizzi nella tua app Next.js è supportata da @next/third-parties, installa il pacchetto e provalo. Ci farebbe piacere ricevere il tuo feedback su GitHub.