Optimiser le chargement de scripts tiers dans Next.js

Découvrez la vision derrière le composant Script de Next.js, qui fournit une solution intégrée pour optimiser le chargement des scripts tiers.

Leena Sohoni
Leena Sohoni

Environ 45% des requêtes provenant de sites Web diffusés sur mobile et sur ordinateur sont des requêtes tierces, dont 33% sont des scripts. La taille, la latence et le chargement des scripts tiers peuvent avoir un impact significatif sur les performances d'un site. Le composant Script Next.js est fourni avec des bonnes pratiques intégrées et par défaut pour aider les développeurs à intégrer des scripts tiers dans leurs applications tout en résolvant les problèmes de performances potentiels.

Scripts tiers et impact sur les performances

Les scripts tiers permettent aux développeurs Web d'exploiter des solutions existantes pour implémenter des fonctionnalités courantes et réduire le temps de développement. Toutefois, les créateurs de ces scripts n'ont généralement aucune incitation à prendre en compte l'impact sur les performances du site Web qui les utilise. Ces scripts sont également une boîte noire pour les développeurs qui les utilisent.

Les scripts représentent un nombre important d'octets tiers téléchargés par les sites Web dans différentes catégories de requêtes tierces. Par défaut, le navigateur hiérarchise les scripts en fonction de leur emplacement dans le document, ce qui peut retarder la découverte ou l'exécution des scripts essentiels à l'expérience utilisateur.

Les bibliothèques tierces requises pour la mise en page doivent être chargées tôt pour afficher la page. Les tiers qui ne sont pas nécessaires pour le rendu initial doivent être différés afin qu'ils ne bloquent pas d'autres traitements sur le thread principal. Lighthouse propose deux audits pour signaler les scripts bloquant le rendu ou le thread principal.

Audits Lighthouse pour "Éliminer les ressources bloquant le rendu" et "Réduire au maximum l'utilisation de code tiers"

Il est important de tenir compte de la séquence de chargement des ressources de votre page afin que les ressources critiques ne soient pas retardées et que les ressources non critiques ne les bloquent pas.

Bien qu'il existe des bonnes pratiques pour réduire l'impact des tiers, il est possible que tout le monde ne sache pas comment les implémenter pour chaque tiers qu'il utilise. Cela peut être compliqué pour les raisons suivantes:

  • En moyenne, les sites Web utilisent 21 à 23 tiers différents (y compris des scripts) sur mobile et sur ordinateur. L'utilisation et les recommandations peuvent varier selon chacun d'eux.
  • L'implémentation de nombreux tiers peut varier selon que vous utilisez un framework ou une bibliothèque d'UI particuliers.
  • De nouvelles bibliothèques tierces sont régulièrement introduites.
  • Les exigences métier variables liées au même tiers rendent difficile la standardisation de son utilisation par les développeurs.

L'accent mis par Aurora sur les scripts tiers

La collaboration d'Aurora avec les frameworks et outils Web open source vise en partie à fournir des valeurs par défaut solides et des outils orientés pour aider les développeurs à améliorer des aspects de l'expérience utilisateur tels que les performances, l'accessibilité, la sécurité et la compatibilité avec les mobiles. En 2021, nous nous sommes concentrés sur l'amélioration de l'expérience utilisateur et des métriques Core Web Vitals des piles de frameworks.

L'une des étapes les plus importantes pour atteindre notre objectif d'améliorer les performances du framework a consisté à rechercher la séquence de chargement idéale des scripts tiers dans Next.js. Les frameworks tels que Next.js sont particulièrement adaptés pour fournir des valeurs par défaut et des fonctionnalités utiles qui aident les développeurs à charger efficacement des ressources, y compris des ressources tierces. Nous avons étudié de nombreuses données HTTP Archive et Lighthouse pour identifier les tiers qui bloquent le plus le rendu dans différents frameworks.

Pour résoudre le problème de blocage des scripts tiers utilisés dans une application par le thread principal, nous avons créé le composant Script. Le composant encapsule les fonctionnalités de séquencement pour fournir aux développeurs de meilleurs contrôles du chargement de script tiers.

Séquencer des scripts tiers sans composant de framework

Les conseils disponibles pour réduire l'impact des scripts bloquant le rendu fournissent les méthodes suivantes pour charger et séquencer efficacement les scripts tiers:

  1. Utilisez l'attribut async ou defer avec des balises <script> qui indiquent au navigateur de charger des scripts tiers non critiques sans bloquer l'analyseur de document. Les scripts qui ne sont pas nécessaires au chargement initial de la page ou à la première interaction de l'utilisateur peuvent être considérés comme non critiques.

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. Établissez des connexions anticipées avec les origines requises à l'aide de preconnect et de dns-prefetch. Cela permet de commencer le téléchargement des scripts critiques plus tôt.

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. Chargez différé les ressources et les éléments intégrés tiers une fois le contenu principal de la page chargé ou lorsque l'utilisateur fait défiler la page jusqu'à la partie où ils sont inclus.

Composant Script Next.js

Le composant Script Next.js implémente les méthodes ci-dessus pour séquencer les scripts et fournit un modèle permettant aux développeurs de définir leur stratégie de chargement. Une fois la stratégie appropriée spécifiée, elle se chargera de manière optimale sans bloquer d'autres ressources critiques.

Le composant Script s'appuie sur la balise HTML <script> et offre la possibilité de définir la priorité de chargement des scripts tiers à l'aide de l'attribut strategy.

// 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" />

L'attribut "strategy" peut prendre trois valeurs.

  1. beforeInteractive: cette option peut être utilisée pour les scripts critiques qui doivent s'exécuter avant que la page ne devienne interactive. Next.js s'assure que ces scripts sont injectés dans le code HTML initial sur le serveur et exécutés avant les autres scripts JavaScript auto-groupés. La gestion du consentement, les scripts de détection de robots ou les bibliothèques d'assistance requises pour afficher des contenus essentiels sont de bons candidats pour cette stratégie.

  2. afterInteractive: il s'agit de la stratégie appliquée par défaut, qui équivaut à charger un script avec l'attribut "defer". Il doit être utilisé pour les scripts que le navigateur peut exécuter une fois la page interactive (par exemple, les scripts d'analyse). Next.js injecte ces scripts côté client, et ils s'exécutent après l'hydratation de la page. Par conséquent, sauf indication contraire, tous les scripts tiers définis à l'aide du composant Script sont différés par Next.js, ce qui fournit une valeur par défaut solide.

  3. lazyOnload: cette option peut être utilisée pour charger de manière différée les scripts de faible priorité lorsque le navigateur est inactif. Les fonctionnalités fournies par ces scripts ne sont pas requises immédiatement après que la page est devenue interactive (par exemple, les plug-ins de chat ou de réseaux sociaux).

Les développeurs peuvent indiquer à Next.js comment leur application utilise un script en spécifiant la stratégie. Cela permet au framework d'appliquer des optimisations et des bonnes pratiques pour charger le script tout en assurant la meilleure séquence de chargement.

À l'aide du composant Script, les développeurs peuvent placer un script tiers n'importe où dans l'application pour les tiers à chargement tardif et au niveau du document pour les scripts critiques. Cela implique que le composant Script peut être colocalisé avec le composant qui utilise le script. Après l'hydratation, le script est injecté dans la section "head" du document initialement généré ou en bas du corps, en fonction de la stratégie utilisée.

Mesurer l'impact

Nous avons utilisé les modèles de l'application de commerce et du blog de démarrage Next.js pour créer deux applications de démonstration qui nous ont aidés à mesurer l'impact de l'inclusion de scripts tiers. Les tiers couramment utilisés pour Google Tag Manager et l'intégration de réseaux sociaux étaient inclus directement sur les pages de ces applications au début, puis via le composant Script. Nous avons ensuite comparé les performances de ces pages sur WebPageTest.

Scripts tiers dans une application de commerce Next.js

Des scripts tiers ont été ajoutés au modèle d'application de commerce pour la démonstration, comme indiqué ci-dessous.

Avant Après
Google Tag Manager avec asynchronie Composant de script avec stratégie = afterInteractive pour les deux scripts
Bouton "Suivre" Twitter sans asynchronie ni différé
Configuration du script et du composant de script pour la démonstration 1 avec deux scripts.

La comparaison suivante montre la progression visuelle des deux versions du kit de démarrage Commerce Next.js. Comme vous pouvez le constater, le LCP se produit près d'une seconde plus tôt lorsque le composant Script est activé avec la bonne stratégie de chargement.

Comparaison de pellicules montrant une amélioration du LCP

Scripts tiers dans un blog Next.js

Des scripts tiers ont été ajoutés à l'application de blog de démonstration, comme indiqué ci-dessous.

Avant Après
Google Tag Manager avec asynchronie Composant de script avec stratégie = lazyonload pour chacun des quatre scripts
Bouton "Suivre" Twitter avec asynchronie
Bouton "S'abonner" de YouTube sans asynchronie ni différé
Bouton "Suivre" LinkedIn sans asynchronie ni différé
Configuration du script et du composant de script pour la démonstration 2 avec quatre scripts.
Vidéo montrant la progression du chargement de la page d&#39;index avec et sans le composant Script. Le composant Script améliore le FCP de 0,5 seconde.

Comme le montre la vidéo, le First Contentful Paint (FCP) se produit en 0,9 seconde sur la page sans le composant Script et en 0,4 seconde avec le composant Script.

Prochaines étapes pour le composant Script

Bien que les options de stratégie pour afterInteractive et lazyOnload offrent un contrôle important sur les scripts bloquant le rendu, nous étudions également d'autres options qui augmenteraient l'utilité du composant Script.

Utiliser des nœuds de calcul Web

Les travailleurs Web permettent d'exécuter des scripts indépendants sur des threads en arrière-plan, ce qui peut libérer le thread principal pour qu'il gère le traitement des tâches d'interface utilisateur et améliore les performances. Les Web Workers sont particulièrement adaptés pour décharger le traitement JavaScript, plutôt que le travail d'UI, du thread principal. Les scripts utilisés pour le service client ou le marketing, qui n'interagissent généralement pas avec l'UI, peuvent être de bons candidats pour l'exécution sur un thread en arrière-plan. Une bibliothèque tierce légère, PartyTown, peut être utilisée pour isoler ces scripts dans un nœud de calcul Web.

Avec l'implémentation actuelle du composant de script Next.js, nous vous recommandons de différer ces scripts sur le thread principal en définissant la stratégie sur afterInteractive ou lazyOnload. À l'avenir, nous proposerons d'introduire une nouvelle option de stratégie, 'worker', qui permettra à Next.js d'utiliser PartyTown ou une solution personnalisée pour exécuter des scripts sur des web workers. N'hésitez pas à nous faire part de vos commentaires sur cette RFC.

Réduire la CLS

Les éléments intégrés tiers tels que les annonces, les vidéos ou les flux de réseaux sociaux peuvent entraîner des décalages de mise en page lors du chargement différé. Cela a un impact sur l'expérience utilisateur et sur la métrique CLS (Cumulative Layout Shift) de la page. Vous pouvez réduire le CLS en spécifiant la taille du conteneur dans lequel l'intégration se chargera.

Le composant Script peut être utilisé pour charger des éléments intégrés susceptibles de provoquer des décalages de mise en page. Nous envisageons de l'augmenter pour fournir des options de configuration qui aideront à réduire le CLS. Il peut être disponible dans le composant Script lui-même ou en tant que composant associé.

Composants wrapper

La syntaxe et la stratégie de chargement pour inclure des scripts tiers populaires tels que Google Analytics ou Google Tag Manager (GTM) sont généralement fixes. Ils peuvent être encapsulés dans des composants de wrapper individuels pour chaque type de script. Seul un ensemble minimal d'attributs spécifiques à l'application (tel que l'ID de suivi) sera disponible pour les développeurs. Les composants de wrapper aident les développeurs à:

  1. Ils peuvent ainsi inclure plus facilement les balises de script populaires.
  2. S'assurer que le framework utilise la stratégie la plus optimale en interne.

Conclusion

Les scripts tiers sont généralement créés pour inclure des fonctionnalités spécifiques sur le site Web qui les utilise. Pour réduire l'impact des scripts non critiques, nous vous recommandons de les différer, ce que fait le composant Script Next.js par défaut. Les développeurs ont l'assurance que les scripts inclus ne retarderont pas les fonctionnalités critiques, sauf s'ils appliquent explicitement la stratégie beforeInteractive. Comme pour le composant Script Next.js, les développeurs de framework peuvent également envisager de créer ces fonctionnalités dans d'autres frameworks. Nous étudions activement la possibilité de lancer un composant similaire avec l'équipe Nuxt.js. En fonction des commentaires, nous espérons également améliorer le composant Script pour couvrir d'autres cas d'utilisation.

Remerciements

Merci à Kara Erickson, Janicklas Ralph, Katie Hempenius, Philip Walton, Jeremy Wagner et Addy Osmani pour leurs commentaires sur cet article.