Ga terug

Een Next.js-website optimaliseren

Een duik in het proces van het verbeteren van een reeks optimalisaties voor een van onze Next.js-websites, gebaseerd op Google's PageSpeed Insights.

Onlangs kregen we het verzoek om wat tijd te besteden aan het optimaliseren van een website die we een paar jaar geleden hebben gebouwd. De website was nog geen Next.js-site, wat al een paar jaar onze standaard is. We hebben de klant ervan overtuigd dat een upgrade naar Next.js een waardevolle stap zou zijn voor een betere SEO, onderhoudbaarheid en snelheid.

De website was opgezet met een ontkoppelde Laravel-configuratie. Laravel was verantwoordelijk voor het ophalen van CMS-gegevens en leverde die in de vorm van een JSON-object aan de React-frontend. De React-applicatie werd gebruikt om deze gegevens daadwerkelijk als een website weer te geven. Een van de nadelen van deze opzet was dat we geen server-side-rendered HTML hadden, wat een van de vele redenen was waarom we wilden overstappen naar Next.js.

Na het opzetten van de nieuwe code en na grondig testen waren we klaar om het naar productie te brengen. De pagina-snelheid was echter niet op het niveau dat we hadden gehoopt. Een magere prestatiescore van 45% op Google's PageSpeed Insights voldeed niet aan onze verwachtingen.

Een aanzienlijke negatieve invloed kwam door het gebruik van externe code (bijv. Google Tag Manager, Google Analytics, sociale integraties, enz.):

We hebben geconcludeerd dat het zinvol zou zijn om te beginnen met het uitschakelen van externe code en te beginnen met het optimaliseren van onze eigen codebase.

Een van de belangrijkste voordelen van het gebruik van Vercel om Next.js-websites te hosten, is dat dit het testen van nieuwe versies een fluitje van een cent maakt. Elke code-commit wordt opgepikt door Vercel, wat een nieuwe build met een unieke URL creƫert. Hierdoor kunnen we snel en eenvoudig de impact van individuele commits testen.

Het maken van een nieuwe release, met externe scripts uitgeschakeld, resulteerde in een aanzienlijk betere, maar nog steeds ondermaatse score van 64%.

We besloten dat het het meest zinvol zou zijn om de lijst met voorgestelde verbeteringen af te lopen en hun impact te testen.

Bovenaan de lijst stond het gebruik van passieve luisteraars om de scrollprestaties te verbeteren:

Hiervoor moesten we in de debugger duiken om erachter te komen welk deel van onze code bepaalde touch-events aanriep zonder de "passive"-vlag te specificeren. Dit is mogelijk in een productiebuild, gebaseerd op de hint (regelnummer en bestand) die wordt gegeven door PageSpeed Insights, maar het vergt enige inspanning zoals hieronder weergegeven.

Een eenvoudigere oplossing hiervoor (en voor de meeste andere diagnostieken) is het draaien van een lokale versie en het rechtstreeks gebruiken van de Lighthouse-scan vanuit de "developer tools"-tab in de browser. Hierdoor worden de regelnummers in de originele broncode aangegeven in plaats van de geminimaliseerde versie.

Dus, wat bleek de oorzaak te zijn? Ons gebruik van de Embla Carousel library. Uit onderzoek in de GitHub-issues van deze library bleek dat dit al was gemeld. En nog beter, de nieuwste versie bevatte al een oplossing. Dus door simpelweg deze library te upgraden, hebben we ons eerste probleem opgelost! šŸŽ‰

Het eenvoudigweg committen van de wijziging in GIT en het opnieuw controleren van onze score liet geen directe verbetering zien. Wanneer je dieper ingaat op de metrieken die worden gebruikt om prestatiescores te berekenen, is dit logisch. Desalniettemin kan de algehele ervaring voor eindgebruikers verbeteren, wat altijd positief is.

Volgende op de lijst: efficiƫnte cachebeleidsregels voor onze afbeeldingen:

Ons headless CMS wordt aangedreven door PHP en gehost op een traditionele, gedeelde PHP-server. Content-editors kunnen afbeeldingen bijwerken die vervolgens op die server worden opgeslagen. We kiezen er meestal voor om de URL waarop het CMS wordt gehost volledig transparant te maken voor onze gebruikers, wat wordt bereikt door Next.js-rewrites te gebruiken om verzoeken voor assets (afbeeldingen/documenten) te proxyen.

Een belangrijk aandachtspunt bij deze opzet is dat Next.js simpelweg de cachecontroleheaders van de originele afbeeldingen kopieert. In ons geval waren ze verkeerd geconfigureerd, wat leidde tot problemen met de opnieuw geschaalde afbeeldingen die door Next.js worden aangemaakt. Het repareren van het .htaccess-bestand dat wordt gebruikt op de Apache-server van ons CMS loste het probleem met de headers op.

Daarna, Adobe Typekit (dat werd gebruikt voor de lettertypen op deze website):

Hiervoor was een update in de Adobe Fonts Typekit-configuratie vereist. Het wijzigen van de weergave van het lettertype naar "swap" verhielp dit probleem.

Overige problemen: te veel werk op de main-thread uitgevoerd door onze applicatie:

Dit hangt sterk samen met een grote bundelgrootte. Next.js toont de bundelgrootte bij elke build en de onze was inderdaad gemarkeerd in het rood met een grootte van 200kb.

Een aantal verbeteringen hebben ons in staat gesteld de bundelgrootte met ongeveer 60kb te verminderen:

  • Een grote interactieve SVG was niet dynamisch gebundeld, maar opgenomen in de hoofdbundel die door alle pagina's werd gebruikt (30 kb)
  • Het verwijderen van de afhankelijkheid van Axios ten gunste van het gebruik van native browser fetch (15 kb)
  • Het verwijderen van react-hook-form uit de hoofdbundel door de implementatie van 2 kleine formulieren die op alle pagina's werden gebruikt te wijzigen (10 kb)
  • Het verwijderen van date-fns uit de clientbundel en alle datagerelateerde logica op de server uitvoeren (5 kb)

Het verkleinen van de bundelgrootte was de laatste mogelijkheid/diagnose die door Google werd genoemd. In tegenstelling tot de andere genoemde optimalisaties had dit ook directe invloed op onze prestatiescore, die nu op 83% stond.

Op dit punt had Google geen kant-en-klare suggesties meer voor ons, maar we waren nog niet helemaal tevreden met het eindresultaat. Het grootste deel van de prestatiescore heeft betrekking op hoe snel inhoud boven de fold wordt weergegeven. We hebben enkele animaties gebruikt om het algehele uiterlijk en gevoel wat dynamischer te maken. Het testen van de impact van deze animaties, vooral die boven de vouw, leek een heel redelijke volgende stap.

We hadden de meeste van onze blokken geĆÆmplementeerd als client-componenten om animaties toe te voegen. Ik heb de fade-in functionaliteit (die enige kennis van de client vereiste, zoals weten welke elementen momenteel in beeld zijn) verwijderd en verplaatst naar een aparte component. Dit stelde ons in staat om de "use client" instructie uit de meeste van onze blokken te verwijderen en bleek ons uiteindelijk in de "groene zone" te brengen.

Samenvatting

  • Het lijkt erop dat de "dynamic" import van Next.js (momenteel) niet altijd de verwachte resultaten oplevert. Zorg ervoor dat je de werkelijke bundelgroottes dubbel controleert bij het uitvoeren van dergelijke optimalisaties.
  • Next.js kopieert de headers van de originele afbeeldingen, zorg ervoor dat de caching headers correct zijn geconfigureerd.
  • Onderzoek zorgvuldig het gebruik van npm-libraries die je in een project opneemt. Probeer het aantal afhankelijkheden laag te houden en geef de voorkeur aan het gebruik van libraries aan de serverzijde in plaats van aan de clientzijde wanneer mogelijk.
  • Geef de voorkeur aan servercomponenten boven clientcomponenten wanneer mogelijk, dit kan een positieve invloed hebben op de snelheid van je pagina.

Ben je op zoek naar een ervaren webontwikkelaar in Belgiƫ om een bestaand project te ondersteunen of iets nieuws op te zetten?

Contacteer ons