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 rendimento inferiori per 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 seguente confronta varie metriche di Labs quando un contenitore Google Tag Manager, composto da 18 tag selezionati in modo casuale, viene aggiunto a Taxonomy, un'app di esempio Next.js molto utilizzata.

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. Utilizzando questa funzionalità, 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 di diversi fornitori di terze parti (esperienza dello sviluppatore).
  • 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 molto utilizzate.

Esperienza degli sviluppatori: gestione semplificata delle librerie di terze parti

Molti script di terze parti vengono utilizzati in una percentuale significativa di siti Next.js, con Google Tag Manager che è il più popolare, utilizzato dal 66% dei siti. @next/third-parties si basa sul componente <Script>introducendo wrapper di livello superiore progettati per semplificarne l'utilizzo per 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 elementi incorporati di Google Maps e YouTube vengono utilizzati rispettivamente nel 8% e nel 4% dei siti web Next.js e abbiamo anche rilasciato componenti per semplificarne il caricamento.

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 ideale, ogni libreria di terze parti ampiamente adottata sarebbe completamente ottimizzata, rendendo superflue eventuali astratti che ne migliorano le prestazioni. Tuttavia, finché non diventerà realtà, possiamo provare a migliorare la loro esperienza utente quando vengono integrate tramite framework popolari come Next.js. Possiamo sperimentare diverse tecniche di caricamento, assicurarci che gli script siano sequenziati in modo corretto e infine condividere il nostro feedback con fornitori di terze parti per incoraggiare le modifiche a monte.

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 "Hello, World" di Next.js, si carica considerevolmente più velocemente.

GIF che mostra il confronto del caricamento della pagina tra il componente di 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 spostandoli 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 lo sviluppo di questo pacchetto, è emerso chiaramente che era necessario centralizzare i consigli per il caricamento di terze parti in modo che anche altri framework potessero trarre vantaggio dalle stesse tecniche di base 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.