Het optimaliseren van het laden van scripts van derden in Next.js

Begrijp de visie achter de Script-component van Next.js, die een ingebouwde oplossing biedt om het laden van scripts van derden te optimaliseren.

Ongeveer 45% van de verzoeken van websites die op mobiel en desktop worden aangeboden, zijn verzoeken van derden, waarvan 33% scripts zijn . De grootte, latentie en het laden van scripts van derden kunnen de prestaties van een site aanzienlijk beïnvloeden. De Next.js Script-component wordt geleverd met ingebouwde best practices en standaardinstellingen om ontwikkelaars te helpen scripts van derden in hun applicaties te introduceren en tegelijkertijd potentiële prestatieproblemen kant-en-klaar aan te pakken.

Scripts van derden en hun impact op de prestaties

Met scripts van derden kunnen webontwikkelaars bestaande oplossingen gebruiken om gemeenschappelijke functies te implementeren en de ontwikkeltijd te verkorten. Maar de makers van deze scripts hebben doorgaans geen enkele prikkel om rekening te houden met de prestatie-impact op de consumerende website. Deze scripts zijn ook een blackbox voor ontwikkelaars die ze gebruiken.

Scripts zijn verantwoordelijk voor een aanzienlijk aantal bytes van derden die door websites worden gedownload in verschillende categorieën verzoeken van derden. Standaard geeft de browser prioriteit aan scripts op basis van waar ze zich in het document bevinden, wat de ontdekking of uitvoering van scripts die cruciaal zijn voor de gebruikerservaring kan vertragen.

Bibliotheken van derden die nodig zijn voor de lay-out moeten vroegtijdig worden geladen om de pagina weer te geven. Derden die niet nodig zijn voor de initiële weergave moeten worden uitgesteld, zodat ze andere verwerkingen op de hoofdthread niet blokkeren. Lighthouse heeft twee audits om scripts voor het blokkeren van renders of hoofdthreads te markeren.

Lighthouse-audits voor het elimineren van bronnen die het renderen blokkeren en het minimaliseren van het gebruik van derden

Het is belangrijk om rekening te houden met de laadvolgorde van de bronnen op uw pagina, zodat kritieke bronnen geen vertraging oplopen en niet-kritieke bronnen geen kritieke bronnen blokkeren.

Hoewel er best practices zijn om de impact van derden te verminderen, weet niet iedereen hoe deze te implementeren voor elke derde partij waarvan zij gebruik maken. Dit kan ingewikkeld zijn omdat:

  • Gemiddeld gebruiken websites 21 tot 23 verschillende derde partijen (inclusief scripts) op mobiel en desktop. Gebruik en aanbevelingen kunnen per apparaat verschillen.
  • De implementatie van veel externe partijen kan verschillen, afhankelijk van het feit of een bepaald raamwerk of een bepaalde UI-bibliotheek wordt gebruikt.
  • Er worden regelmatig nieuwere bibliotheken van derden geïntroduceerd.
  • Variërende bedrijfsvereisten met betrekking tot dezelfde derde partij maken het voor ontwikkelaars moeilijk om het gebruik ervan te standaardiseren.

Aurora's focus op scripts van derden

Een deel van Aurora's samenwerking met open source webframeworks en -tools is het bieden van sterke standaarden en eigenzinnige tools om ontwikkelaars te helpen aspecten van de gebruikerservaring te verbeteren, zoals prestaties, toegankelijkheid, beveiliging en mobiele gereedheid. In 2021 waren we gefocust op het helpen van framework-stacks bij het verbeteren van de gebruikerservaring en hun Core Web Vitals -statistieken.

Een van de belangrijkste stappen op weg naar het bereiken van ons doel om de prestaties van het raamwerk te verbeteren, was het onderzoeken van de ideale laadvolgorde van scripts van derden in Next.js. Frameworks zoals Next.js zijn uniek gepositioneerd om nuttige standaardinstellingen en functies te bieden waarmee ontwikkelaars efficiënt bronnen kunnen laden, inclusief die van derden. We hebben uitgebreide HTTP Archive- en Lighthouse- gegevens bestudeerd om erachter te komen welke externe partijen de rendering het meest blokkeren in verschillende frameworks.

Om het probleem aan te pakken van het blokkeren van scripts van derden die in een applicatie worden gebruikt door de hoofdthread, hebben we de Script-component gebouwd. De component omvat sequencing-functies om ontwikkelaars betere controles te bieden voor het laden van scripts van derden.

Sequencing van scripts van derden zonder een raamwerkcomponent

De beschikbare richtlijnen om de impact van scripts die weergave blokkeren te verminderen, bieden de volgende methoden voor het efficiënt laden en rangschikken van scripts van derden:

  1. Gebruik het attribuut async of defer met <script> -tags die de browser vertellen niet-kritieke scripts van derden te laden zonder de documentparser te blokkeren. Scripts die niet vereist zijn voor het aanvankelijk laden van de pagina of de eerste gebruikersinteractie, kunnen als niet-kritisch worden beschouwd.

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. Breng vroege verbindingen tot stand met de vereiste oorsprong met behulp van preconnect en dns-prefetch. Hierdoor kunnen kritische scripts eerder beginnen met downloaden.

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. Lazy-load bronnen en insluitingen van derden nadat de inhoud van de hoofdpagina is geladen of wanneer de gebruiker naar het deel van de pagina scrolt waar deze zijn opgenomen.

De Next.js-scriptcomponent

De Next.js Script-component implementeert de bovenstaande methoden voor het sequencen van scripts en biedt een sjabloon voor ontwikkelaars om hun laadstrategie te definiëren. Zodra de geschikte strategie is gespecificeerd, wordt deze optimaal geladen zonder andere kritieke bronnen te blokkeren.

De Script-component bouwt voort op de HTML <script>-tag en biedt een optie om de laadprioriteit voor scripts van derden in te stellen met behulp van het strategie-attribuut.

// Example for beforeInteractive:
<Script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver" strategy="beforeInteractive" />

// Example for afterInteractive (default):
<Script src="https://example.com/samplescript.js" />

// Example for lazyonload:
<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

Het strategieattribuut kan drie waarden aannemen.

  1. beforeInteractive : Deze optie kan worden gebruikt voor kritieke scripts die moeten worden uitgevoerd voordat de pagina interactief wordt. Next.js zorgt ervoor dat dergelijke scripts in de initiële HTML op de server worden geïnjecteerd en vóór ander zelfgebundeld JavaScript worden uitgevoerd. Toestemmingsbeheer, botdetectiescripts of hulpbibliotheken die nodig zijn om kritieke inhoud weer te geven, zijn goede kandidaten voor deze strategie.

  2. afterInteractive : Dit is de standaard toegepaste strategie en komt overeen met het laden van een script met het defer-attribuut. Het moet worden gebruikt voor scripts die de browser kan uitvoeren nadat de pagina interactief is, bijvoorbeeld analysescripts. Next.js injecteert deze scripts aan de clientzijde en wordt uitgevoerd nadat de pagina is gehydrateerd. Tenzij anders aangegeven, worden dus alle scripts van derden die zijn gedefinieerd met behulp van de Script-component uitgesteld door Next.js, waardoor een sterke standaard wordt geboden.

  3. lazyOnload : Deze optie kan worden gebruikt om scripts met lage prioriteit lui te laden wanneer de browser inactief is. De functionaliteit van dergelijke scripts is niet vereist onmiddellijk nadat de pagina interactief wordt, bijvoorbeeld chat- of sociale media-plug-ins.

Ontwikkelaars kunnen Next.js vertellen hoe hun applicatie een script gebruikt door de strategie op te geven. Hierdoor kan het raamwerk optimalisaties en best practices toepassen om het script te laden en tegelijkertijd de beste laadvolgorde te garanderen.

Met behulp van de Script-component kunnen ontwikkelaars overal in de applicatie een script van derden plaatsen voor te laat ladende derden en op documentniveau voor kritieke scripts. Dit houdt in dat de Script-component zich op dezelfde locatie kan bevinden als de component die het script gebruikt. Na hydratatie wordt het script in de kop van het oorspronkelijk weergegeven document of onderaan de body geïnjecteerd, afhankelijk van de gebruikte strategie.

Het meten van de impact

We hebben de sjablonen voor de Next.js -commerce-app en het startersblog gebruikt om twee demo-apps te maken waarmee we de impact van het opnemen van scripts van derden konden meten. Veelgebruikte derde partijen voor Google Tag Manager en sociale media-insluitingen werden eerst rechtstreeks en vervolgens via de Script-component op de pagina's van deze apps opgenomen. Vervolgens hebben we de prestaties van deze pagina's vergeleken op WebPageTest .

Scripts van derden in een Next.js-commerce-app

Scripts van derden zijn toegevoegd aan de commerce-app-sjabloon voor de demo, zoals hieronder weergegeven.

Voor Na
Google Tag Manager met async Scriptcomponent met strategie = afterInteractive voor beide scripts
Twitter Volg-knop zonder async of uitstel
Script- en scriptcomponentconfiguratie voor demo 1 met 2 scripts.

De volgende vergelijking toont de visuele voortgang voor beide versies van de Next.js commerce starterkit . Zoals u kunt zien, vindt LCP bijna 1 seconde eerder plaats als de Script-component is ingeschakeld met de juiste laadstrategie.

Vergelijking van filmstrips die verbetering in LCP laat zien

Scripts van derden in een Next.js-blog

Scripts van derden zijn toegevoegd aan de demoblog-app, zoals hieronder weergegeven.

Voor Na
Google Tag Manager met async Scriptcomponent met strategie = lazyonload voor elk van de vier scripts
Twitter Volg-knop met async
YouTube-abonneerknop zonder async of uitstel
LinkedIn Volg-knop zonder async of uitstel
Script- en scriptcomponentconfiguratie voor demo 2 met 4 scripts.
Video die de voortgang van het laden van de indexpagina toont, met en zonder de Script-component. Er is een verbetering van 0,5 seconde in FCP met de Script-component.

Zoals u in de video kunt zien, vindt First Contentful Paint (FCP) plaats na 0,9 seconden op de pagina zonder de Script-component en na 0,4 seconden met de Script-component.

Wat is de volgende stap voor de Script-component

Hoewel de strategieopties voor afterInteractive en lazyOnload aanzienlijke controle bieden over scripts die het renderen blokkeren, onderzoeken we ook andere opties die het nut van de Script-component zouden vergroten.

Gebruik maken van webwerkers

Webwerkers kunnen worden gebruikt om onafhankelijke scripts op achtergrondthreads uit te voeren, waardoor de hoofdthread vrij kan komen om gebruikersinterfacetaken te verwerken en de prestaties te verbeteren. Web Workers zijn het meest geschikt om JavaScript-verwerking, in plaats van UI-werk, buiten de rode draad te houden. Scripts die worden gebruikt voor klantenondersteuning of marketing en die doorgaans geen interactie hebben met de gebruikersinterface, kunnen goede kandidaten zijn voor uitvoering op een achtergrondthread. Een lichtgewicht bibliotheek van derden, PartyTown , kan worden gebruikt om dergelijke scripts in een webwerker te isoleren.

Met de huidige implementatie van de scriptcomponent Next.js raden we u aan deze scripts op de hoofdthread uit te stellen door de strategie in te stellen op afterInteractive of lazyOnload . In de toekomst stellen we voor om een ​​nieuwe strategieoptie te introduceren, 'worker' , waarmee Next.js PartyTown of een aangepaste oplossing kan gebruiken om scripts op webworkers uit te voeren. We verwelkomen commentaar van ontwikkelaars op deze RFC .

CLS minimaliseren

Insluitingen van derden, zoals advertenties, video's of insluitingen van sociale media-feeds, kunnen lay-outverschuivingen veroorzaken wanneer ze lui worden geladen. Dit heeft invloed op de gebruikerservaring en de statistiek Cumulatieve lay-outverschuiving (CLS) voor de pagina. CLS kan worden geminimaliseerd door de grootte op te geven van de container waarin de insluiting wordt geladen.

De Script-component kan worden gebruikt om insluitingen te laden die lay-outverschuivingen kunnen veroorzaken. We overwegen om dit uit te breiden om configuratieopties te bieden die de CLS helpen verminderen. Dit kan beschikbaar worden gemaakt binnen de Script-component zelf of als een begeleidende component.

Wikkelcomponenten

De syntaxis en laadstrategie voor het opnemen van populaire scripts van derden, zoals Google Analytics of Google Tag Manager (GTM), staan ​​meestal vast. Deze kunnen verder worden ingekapseld in individuele wrappercomponenten voor elk type script. Slechts een minimale set applicatiespecifieke kenmerken (zoals tracking-ID) zal beschikbaar zijn voor ontwikkelaars. Wrapper-componenten helpen ontwikkelaars door:

  1. Dit maakt het voor hen gemakkelijker om populaire scripttags op te nemen.
  2. Ervoor zorgen dat het raamwerk de meest optimale strategie onder de motorkap gebruikt.

Conclusie

Scripts van derden worden meestal gemaakt om specifieke functies op de consumerende website op te nemen. Om de impact van niet-kritieke scripts te verminderen, raden we aan deze uit te stellen, wat de Next.js Script-component standaard doet. Ontwikkelaars hebben de zekerheid dat de meegeleverde scripts de kritieke functionaliteit niet zullen vertragen, tenzij ze expliciet de beforeInteractive -strategie toepassen. Net als de Next.js Script-component kunnen framework-ontwikkelaars ook overwegen deze functies in andere frameworks te bouwen. We onderzoeken actief of we een soortgelijk onderdeel kunnen lanceren met het Nuxt.js-team. Op basis van feedback hopen we ook de Script-component verder te verbeteren om aanvullende gebruiksscenario's te dekken.

Dankbetuigingen

Bedankt aan Kara Erickson , Janicklas Ralph , Katie Hempenius , Philip Walton , Jeremy Wagner en Addy Osmani voor hun feedback op dit bericht.