Les performances Web en toute simplicité – Google I/O, édition 2018

Lors de la Google IO 2018, nous avons présenté un ensemble d'outils, de bibliothèques et de techniques d'optimisation qui facilitent l'amélioration des performances Web. Nous les expliquons ici à l'aide de l'application Oodles Theater. Nous parlons également de nos tests du chargement prédictif et de la nouvelle initiative Guess.js.

Ewa Gasperowicz

Au cours de l'année écoulée, nous avons été très occupés à trouver des moyens d'accélérer et de rendre le Web plus performant. Nous avons donc développé de nouveaux outils, approches et bibliothèques que nous souhaitons vous présenter dans cet article. Dans la première partie, nous vous présenterons certaines techniques d'optimisation que nous avons utilisées dans la pratique lors du développement de l'application Oodles Theater. Dans la deuxième partie, nous parlerons de nos tests du chargement prédictif et de la nouvelle initiative Guess.js.

Besoin de performances

Internet devient de plus en plus lourd d'année en année. Si nous vérifions l'état du Web, nous pouvons voir qu'une page médiane sur mobile pèse environ 1,5 Mo, dont la majorité est constituée de JavaScript et d'images.

La taille croissante des sites Web, ainsi que d'autres facteurs, tels que la latence du réseau, les limites du processeur, les modèles de blocage du rendu ou le code tiers superflu, contribuent à la complexité de l'équation des performances.

La plupart des utilisateurs placent la vitesse en haut de la hiérarchie de leurs besoins en termes d'expérience utilisateur. Cela n'est pas vraiment surprenant, car vous ne pouvez pas vraiment faire grand-chose tant que le chargement d'une page n'est pas terminé. Vous ne pouvez pas en tirer de valeur, ni admirer son esthétique.

Pyramide de la hiérarchie UX
Fig. 1. Dans quelle mesure la vitesse est-elle importante pour les utilisateurs ? (Speed Matters, vol. 3)

Nous savons que les performances sont importantes pour les utilisateurs, mais il peut sembler difficile de savoir par où commencer l'optimisation. Heureusement, il existe des outils qui peuvent vous aider.

Lighthouse : base du workflow de performances

Lighthouse fait partie des outils pour les développeurs Chrome. Il vous permet d'effectuer un audit de votre site Web et de vous donner des conseils pour l'améliorer.

Nous avons récemment lancé de nombreux audits de performances qui sont très utiles dans le workflow de développement quotidien.

Nouveaux audits Lighthouse
Fig. 2. Nouveaux audits Lighthouse

Voyons comment en tirer parti avec un exemple concret : l'application Oodles Theater. Il s'agit d'une petite application Web de démonstration dans laquelle vous pouvez essayer certains de nos Doodles Google interactifs préférés et même jouer à un ou deux jeux.

Lors de la création de l'application, nous voulions nous assurer qu'elle était aussi performante que possible. Le point de départ de l'optimisation a été un rapport Lighthouse.

Rapport Lighthouse pour l'application Oodles
Fig. 3. Rapport Lighthouse pour l'application Oodles

Les performances initiales de notre application, telles qu'elles apparaissent dans le rapport Lighthouse, étaient assez mauvaises. Sur un réseau 3G, l'utilisateur devait attendre 15 secondes pour la première peinture significative ou pour que l'application devienne interactive. Lighthouse a mis en évidence de nombreux problèmes sur notre site, et le score de performances global de 23 reflète exactement cela.

La page pesait environ 3,4 Mo.Nous devions absolument réduire son poids.

C'est ainsi que nous avons commencé notre premier défi de performances: trouver des éléments que nous pouvons facilement supprimer sans affecter l'expérience globale.

Opportunités d'optimisation des performances

Supprimer les ressources inutiles

Certains éléments évidents peuvent être supprimés en toute sécurité: les espaces et les commentaires.

Avantages de la réduction
Fig. 4 Réduire la taille des ressources JavaScript et CSS et les compresser

Lighthouse met en avant cette opportunité dans l'audit CSS et JavaScript non minifiés. Nous utilisions webpack pour notre processus de compilation. Pour obtenir la minification, nous avons simplement utilisé le plug-in Uglify JS.

La minification est une tâche courante. Vous devriez donc pouvoir trouver une solution prête à l'emploi pour le processus de compilation que vous utilisez.

Un autre audit utile dans ce domaine est Activer la compression de texte. Il n'y a aucune raison d'envoyer des fichiers non compressés, et la plupart des CDN le prennent en charge dès la sortie de la boîte.

Nous utilisions Firebase Hosting pour héberger notre code, et Firebase active le compression gzip par défaut. Par conséquent, nous avons obtenu cela sans frais en hébergeant notre code sur un CDN raisonnable.

Bien que gzip soit un moyen de compression très populaire, d'autres mécanismes tels que Zopfli et Brotli gagnent également en popularité. Brotli est compatible avec la plupart des navigateurs. Vous pouvez utiliser un binaire pour précompresser vos composants avant de les envoyer au serveur.

Utiliser des règles de cache efficaces

L'étape suivante consistait à nous assurer que nous n'envoyons pas de ressources deux fois si ce n'est pas nécessaire.

L'audit Politique de cache inefficace dans Lighthouse nous a permis de constater que nous pouvions optimiser nos stratégies de mise en cache pour y parvenir. En définissant un en-tête d'expiration max-age sur notre serveur, nous nous sommes assurés qu'en cas de nouvelle visite, l'utilisateur peut réutiliser les ressources qu'il a téléchargées précédemment.

Dans l'idéal, vous devez essayer de mettre en cache autant de ressources que possible de manière sécurisée pendant la plus longue période possible et de fournir des jetons de validation pour une révalidation efficace des ressources mises à jour.

Supprimer le code inutilisé

Jusqu'à présent, nous avons supprimé les parties évidentes du téléchargement inutile, mais qu'en est-il des parties moins évidentes ? Par exemple, du code inutilisé.

Couverture de code dans les outils de développement
Fig. 5. Vérifier la couverture du code

Il arrive que nous incluions dans nos applications du code qui n'est pas vraiment nécessaire. Cela se produit en particulier si vous travaillez sur votre application pendant une longue période, que votre équipe ou vos dépendances changent, et qu'une bibliothèque orpheline est parfois laissée de côté. C'est exactement ce qui nous est arrivé.

Au début, nous utilisions la bibliothèque Material Components pour créer rapidement un prototype de notre application. Au fil du temps, nous sommes passés à un style plus personnalisé et nous avons complètement oublié cette bibliothèque. Heureusement, la vérification de la couverture du code nous a permis de le redécouvrir dans notre bundle.

Vous pouvez consulter les statistiques de couverture de code dans DevTools, à la fois pour l'environnement d'exécution et pour le temps de chargement de votre application. Vous pouvez voir les deux grandes bandes rouges dans la capture d'écran du bas. Plus de 95 % de notre CSS était inutilisé, ainsi qu'une grande quantité de JavaScript.

Lighthouse a également détecté ce problème dans l'audit des règles CSS inutilisées. Il a permis d'économiser plus de 400 ko. Nous sommes donc revenus à notre code et avons supprimé la partie JavaScript et CSS de cette bibliothèque.

Si nous supprimons l'adaptateur MVC, nos styles passent à 10 ko.
Fig. 6. Si nous abandonnons l'adaptateur MVC, nos styles passent à 10 ko.

Cela a réduit notre bundle CSS de 20 fois, ce qui est plutôt bien pour un commit minuscule de deux lignes.

Bien entendu, cela a fait grimper notre score de performances, et le temps de réponse s'est également beaucoup amélioré.

Toutefois, avec des changements comme celui-ci, il ne suffit pas de vérifier vos métriques et vos scores. La suppression de code n'est jamais sans risque. Vous devez donc toujours rechercher des régressions potentielles.

Notre code n'était pas utilisé dans 95 % des cas, mais il reste encore 5 %. Apparemment, l'un de nos composants utilisait toujours les styles de cette bibliothèque (les petites flèches dans le curseur de dessin). Comme il était très petit, nous pouvions simplement réintégrer manuellement ces styles dans les boutons.

Les boutons ont été endommagés par une bibliothèque manquante
Fig. 7. Un composant utilisait toujours la bibliothèque supprimée.

Par conséquent, si vous supprimez du code, assurez-vous simplement de disposer d'un workflow de test approprié pour vous protéger contre les régressions visuelles potentielles.

Évitez d'énormes charges utiles de réseau

Nous savons que les ressources volumineuses peuvent ralentir le chargement des pages Web. Elles peuvent coûter de l'argent à nos utilisateurs et avoir un impact important sur leurs forfaits de données. Il est donc très important d'en tenir compte.

Lighthouse a détecté un problème avec certaines de nos charges utiles réseau à l'aide de l'audit Charge utile réseau énorme.

Détecter d'énormes charges utiles de réseau
Fig. 8. Détecter d'énormes charges utiles réseau

Nous avons constaté que plus de 3 Mo de code étaient envoyés, ce qui est assez important, en particulier sur mobile.

Tout en haut de cette liste, Lighthouse a mis en évidence que nous avions un bundle de fournisseurs JavaScript de 2 Mo de code non compressé. C'est également un problème mis en évidence par webpack.

Comme dit le proverbe, la requête la plus rapide est celle qui n'est pas envoyée.

Idéalement, vous devez mesurer la valeur de chaque élément que vous diffusez auprès de vos utilisateurs, mesurer les performances de ces éléments et déterminer s'il est vraiment utile de les diffuser avec l'expérience initiale. En effet, ces composants peuvent parfois être différés, chargés de manière paresseuse ou traités pendant les temps d'inactivité.

Dans notre cas, comme nous traitons de nombreux bundles JavaScript, nous avons eu de la chance, car la communauté JavaScript dispose d'un ensemble complet d'outils d'audit des bundles JavaScript.

Audit des bundles JavaScript
Figure 9. Audit des bundles JavaScript

Nous avons commencé avec l'analyseur de bundle webpack, qui nous a informés que nous incluions une dépendance appelée unicode, qui représentait 1,6 Mo de code JavaScript analysé, ce qui est assez important.

Nous sommes ensuite passés à notre éditeur et, à l'aide du plug-in de coût d'importation pour le code visuel, nous avons pu visualiser le coût de chaque module que nous importions. Cela nous a permis de découvrir quel composant incluait du code qui faisait référence à ce module.

Nous avons ensuite passé à un autre outil, BundlePhobia. Il s'agit d'un outil qui vous permet de saisir le nom de n'importe quel package NPM et de voir quelle est sa taille estimée en minifié et en gzippé. Nous avons trouvé une bonne alternative au module slug que nous utilisions, qui ne pèse que 2,2 ko.Nous l'avons donc remplacé.

Cela a eu un impact important sur nos performances. Entre ce changement et la découverte d'autres possibilités de réduire la taille de notre bundle JavaScript, nous avons économisé 2,1 Mo de code.

Nous avons constaté une amélioration de 65% dans l'ensemble, en tenant compte de la taille compressée et minifiée de ces bundles. Nous avons constaté que ce processus était vraiment utile.

En règle générale, essayez d'éliminer les téléchargements inutiles sur vos sites et dans vos applications. Faire l'inventaire de vos composants et mesurer leur impact sur les performances peut avoir un impact très important. Veillez donc à auditer vos composants assez régulièrement.

Réduire le temps de démarrage JavaScript avec la division du code

Bien que les charges utiles réseau volumineuses puissent avoir un impact important sur notre application, il existe un autre élément qui peut avoir un impact très important : JavaScript.

JavaScript est votre actif le plus coûteux. Sur mobile, si vous envoyez de gros bundles de code JavaScript, cela peut retarder le temps d'interaction des utilisateurs avec les composants de votre interface utilisateur. Cela signifie qu'ils peuvent appuyer sur l'interface utilisateur sans que rien de significatif ne se produise. Il est donc important de comprendre pourquoi JavaScript coûte si cher.

C'est ainsi qu'un navigateur traite JavaScript.

Traitement JavaScript
Fig. 10. Traitement JavaScript

Nous devons d'abord télécharger ce script. Nous disposons d'un moteur JavaScript qui doit ensuite analyser ce code, le compiler et l'exécuter.

Ces phases ne prennent pas beaucoup de temps sur un appareil haut de gamme comme un ordinateur de bureau ou un ordinateur portable, voire un téléphone haut de gamme. Toutefois, sur un téléphone mobile moyen, ce processus peut prendre entre cinq et dix fois plus de temps. C'est ce qui retarde l'interactivité. Il est donc important que nous essayions de réduire ce délai.

Pour vous aider à identifier ces problèmes dans votre application, nous avons ajouté un nouvel audit du temps de démarrage JavaScript à Lighthouse.

Délai de démarrage de JavaScript
Fig. 11 Audit du temps de démarrage JavaScript

Dans le cas de l'application Oodle, il nous a indiqué que le démarrage JavaScript avait pris 1,8 seconde. Nous importions de manière statique tous nos routes et composants dans un seul bundle JavaScript monolithique.

Pour contourner ce problème, vous pouvez utiliser la division du code.

La division du code est comme une pizza

Le fractionnement du code consiste à ne pas fournir à vos utilisateurs une pizza entière de code JavaScript, mais une seule part à la fois, selon leurs besoins.

La division du code peut être appliquée au niveau d'un itinéraire ou d'un composant. Il fonctionne parfaitement avec React et React Loadable, Vue.js, Angular, Polymer, Preact et plusieurs autres bibliothèques.

Nous avons intégré la division du code dans notre application. Nous sommes passés des importations statiques aux importations dynamiques, ce qui nous a permis de charger de manière asynchrone le code à mesure que nous en avions besoin.

Fractionnement du code avec des importations dynamiques
Fig. 13 Fractionnement du code avec des importations dynamiques

Cela a permis de réduire la taille de nos bundles, mais aussi le temps de démarrage de JavaScript. Le temps d'exécution est ainsi passé à 0,78 seconde, ce qui a rendu l'application 56% plus rapide.

En général, si vous créez une expérience axée sur JavaScript, veillez à n'envoyer à l'utilisateur que le code dont il a besoin.

Profitez de concepts tels que le fractionnement du code, explorez des idées comme le ramassage d'arbres et consultez le dépôt webpack-libs-optimizations pour obtenir quelques idées sur la façon de réduire la taille de votre bibliothèque si vous utilisez webpack.

Optimiser les images

Blague sur les performances de chargement des images

Dans l'application Oodle, nous utilisons beaucoup d'images. Malheureusement, Lighthouse a été beaucoup moins enthousiaste que nous. En fait, nous avons échoué aux trois audits liés aux images.

Nous avons oublié d'optimiser nos images, nous ne les avons pas dimensionnées correctement et nous pourrions gagner à utiliser d'autres formats d'images.

Audits des images
Fig. 14 Audits d'images Lighthouse

Nous avons commencé par optimiser nos images.

Pour une optimisation ponctuelle, vous pouvez utiliser des outils visuels tels que ImageOptim ou XNConvert.

Une approche plus automatisée consiste à ajouter une étape d'optimisation des images à votre processus de compilation, avec des bibliothèques telles que imagemin.

Vous vous assurez ainsi que les images ajoutées à l'avenir seront optimisées automatiquement. Certains CDN, comme Akamai, ou des solutions tierces telles que Cloudinary, Fastly ou Uploadcare, proposent des solutions d'optimisation d'image complètes. Vous pouvez donc également héberger simplement vos images sur ces services.

Si vous ne souhaitez pas le faire en raison des coûts ou des problèmes de latence, des projets tels que Thumbor ou Imageflow proposent des alternatives auto-hébergées.

Avant et après l'optimisation
Figure 15 Avant et après l'optimisation

Notre PNG d'arrière-plan a été signalé comme étant trop volumineux dans webpack, et à juste titre. Après l'avoir correctement dimensionné pour la fenêtre d'affichage et l'avoir exécuté avec ImageOptim, nous sommes passés à 100 ko, ce qui est acceptable.

En répétant cette opération pour plusieurs images de notre site, nous avons pu réduire considérablement le poids global de la page.

Utiliser le format adapté aux contenus animés

Les GIF peuvent être très coûteux. Étonnamment, le format GIF n'a jamais été conçu comme une plate-forme d'animation. Par conséquent, passer à un format vidéo plus adapté vous permet de réaliser d'importantes économies en termes de taille de fichier.

Dans l'application Oodle, nous utilisions un GIF comme séquence d'introduction sur la page d'accueil. Selon Lighthouse, nous pourrions économiser plus de 7 Mo en passant à un format vidéo plus efficace. Notre extrait pesait environ 7, 3 Mo, bien trop pour un site Web raisonnable.Nous l'avons donc transformé en élément vidéo avec deux fichiers sources : un MP4 et un WebM pour une compatibilité plus large avec les navigateurs.

Remplacer les GIF animés par des vidéos
Figure 16 Remplacer les GIF animés par des vidéos

Nous avons utilisé l'outil FFmpeg pour convertir notre animation GIF en fichier MP4. Le format WebM vous permet de réaliser des économies encore plus importantes. L'API ImageOptim peut effectuer cette conversion pour vous.

ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4

Nous avons réussi à économiser plus de 80% de notre poids total grâce à cette conversion. Nous sommes ainsi passés à environ 1 Mo.

Toutefois, 1 Mo est une ressource importante à transmettre par câble, en particulier pour un utilisateur dont la bande passante est limitée. Heureusement, nous pouvons utiliser l'API Effective Type pour déterminer qu'ils utilisent une bande passante lente et leur fournir un fichier JPEG beaucoup plus petit à la place.

Cette interface utilise la valeur effective du temps aller-retour et de la mise hors service pour estimer le type de réseau utilisé par l'utilisateur. Il renvoie simplement une chaîne, 2G lente, 2G, 3G ou 4G. En fonction de cette valeur, si l'utilisateur dispose d'une connexion inférieure à la 4G, nous pouvons remplacer l'élément vidéo par l'image.

if (navigator.connection.effectiveType) { ... }

Cela réduit un peu l'expérience, mais au moins le site est utilisable avec une connexion lente.

Chargement différé des images hors écran

Les carrousels, les curseurs ou les pages très longues chargent souvent des images, même si l'utilisateur ne peut pas les voir immédiatement sur la page.

Lighthouse signalera ce comportement dans l'audit des images hors écran. Vous pouvez également le constater par vous-même dans le panneau "Network" (Réseau) de DevTools. Si vous voyez de nombreuses images entrantes alors que seules quelques-unes sont visibles sur la page, vous pouvez envisager de les charger de manière différée.

Le chargement paresseux n'est pas encore pris en charge en mode natif dans le navigateur. Nous devons donc utiliser JavaScript pour ajouter cette fonctionnalité. Nous avons utilisé la bibliothèque Lazysizes pour ajouter un comportement de chargement paresseux à nos couvertures Oodle.

<!-- Import library -->
import lazysizes from 'lazysizes'  <!-- or -->
<script src="lazysizes.min.js"></script>

<!-- Use it -->

<img data-src="image.jpg" class="lazyload"/>
<img class="lazyload"
    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w"/>

Lazysizes est intelligent, car il ne suit pas seulement les modifications de visibilité de l'élément, mais précharge également de manière proactive les éléments proches de la vue pour une expérience utilisateur optimale. Il propose également une intégration facultative de IntersectionObserver, qui vous permet d'effectuer des recherches de visibilité très efficaces.

Depuis cette modification, nos images sont extraites à la demande. Pour en savoir plus sur ce sujet, consultez images.guide, une ressource très pratique et complète.

Aider le navigateur à fournir des ressources critiques plus tôt

Tous les octets envoyés au navigateur par le biais du fil n'ont pas le même degré d'importance, et le navigateur le sait. De nombreux navigateurs utilisent des heuristiques pour décider de ce qu'ils doivent récupérer en premier. Il arrive donc qu'ils récupèrent le CSS avant les images ou les scripts.

Il peut être utile que nous, en tant qu'auteurs de la page, informions le navigateur de ce qui est vraiment important pour nous. Heureusement, au cours des deux dernières années, les fournisseurs de navigateurs ont ajouté un certain nombre de fonctionnalités pour nous aider, par exemple des indices de ressources tels que link rel=preconnect, preload ou prefetch.

Ces fonctionnalités apportées à la plate-forme Web aident le navigateur à récupérer le bon élément au bon moment. Elles peuvent être un peu plus efficaces que certaines des approches de chargement personnalisé basées sur la logique qui sont effectuées à l'aide de scripts.

Voyons comment Lighthouse nous aide à utiliser efficacement certaines de ces fonctionnalités.

La première chose que Lighthouse nous demande de faire est d'éviter les allers-retours multiples et coûteux vers n'importe quelle origine.

Éviter les allers-retours multiples et coûteux vers n&#39;importe quelle origine
Figure 17 : Éviter les allers-retours multiples et coûteux vers n'importe quelle origine

Dans le cas de l'application Oodle, nous utilisons beaucoup Google Fonts. Chaque fois que vous insérez une feuille de style de police Google sur votre page, elle se connecte à deux sous-domaines. Lighthouse nous indique que si nous pouvions préparer cette connexion, nous pourrions économiser jusqu'à 300 millisecondes sur notre temps de connexion initial.

En profitant de la préconnexion de lien rel, nous pouvons masquer efficacement cette latence de connexion.

Cela peut avoir un impact particulièrement important avec des éléments tels que Google Fonts, où le CSS de nos polices de caractères est hébergé sur googleapis.com et nos ressources de polices sur Gstatic. Nous avons donc appliqué cette optimisation et gagné quelques centaines de millisecondes.

Lighthouse suggère ensuite de précharger les requêtes clés.

Précharger les requêtes de clé
Figure 18 : Précharger les requêtes de clé

<link rel=preload> est très puissant. Il informe le navigateur qu'une ressource est nécessaire dans le cadre de la navigation en cours et tente de le récupérer dès que possible.

Ici, Lighthouse nous indique que nous devrions précharger nos principales ressources de polices Web, car nous chargeons deux polices Web.

Le préchargement dans une police Web se présente comme suit : en spécifiant rel=preload, vous transmettez as avec le type de police, puis vous spécifiez le type de police que vous essayez de charger, par exemple woff2.

L'impact que cela peut avoir sur votre page est assez important.

Impact du préchargement des ressources
Fig. 19 Impact du préchargement des ressources

Normalement, sans utiliser le préchargement de lien rel, si les polices Web sont essentielles à votre page, le navigateur doit d'abord récupérer votre code HTML, analyser votre code CSS, puis récupérer vos polices Web.

Avec le préchargement de lien rel, dès que le navigateur a analysé votre code HTML, il peut commencer à extraire ces polices Web beaucoup plus tôt. Dans le cas de notre application, cela nous a permis de gagner une seconde sur le temps nécessaire pour afficher du texte à l'aide de nos polices Web.

Toutefois, si vous essayez de précharger des polices à l'aide de Google Fonts, il existe un piège.

Les URL de polices Google que nous spécifions pour nos polices dans nos feuilles de style sont mises à jour assez régulièrement par l'équipe chargée des polices. Ces URL peuvent expirer ou être mises à jour régulièrement. Nous vous suggérons donc d'héberger vous-même vos polices Web si vous souhaitez contrôler entièrement votre expérience de chargement de polices. Cela peut être très utile, car cela vous permet d'accéder à des éléments tels que le préchargement de liens rel.

Dans notre cas, l'outil Google Web Fonts Helper nous a été très utile pour nous aider à mettre hors connexion certaines de ces polices Web et à les configurer localement. N'hésitez donc pas à l'essayer.

Que vous utilisiez des polices Web dans vos ressources essentielles ou que ce soit JavaScript, essayez d'aider le navigateur à diffuser vos ressources essentielles le plus rapidement possible.

Expérimental: Indices de priorité

Nous avons quelque chose de spécial à vous annoncer aujourd'hui. En plus de fonctionnalités telles que les optimisations de ressources et le préchargement, nous avons travaillé sur une toute nouvelle fonctionnalité expérimentale de navigateur que nous appelons "hints de priorité".

Définir la priorité du contenu initialement visible
Fig. 20 Conseils de priorité

Il s'agit d'une nouvelle fonctionnalité qui vous permet d'indiquer au navigateur l'importance d'une ressource. Elle expose un nouvel attribut (importance) avec les valeurs basse, élevée ou automatique.

Cela nous permet de réduire la priorité des ressources moins importantes, telles que les styles, les images ou les appels d'API de récupération non critiques, afin de réduire les conflits. Nous pouvons également augmenter la priorité des éléments plus importants, comme nos images de héros.

Dans le cas de notre application Oodle, cela nous a permis d'identifier un point pratique à optimiser.

Définir la priorité du contenu initialement visible
Fig. 21 Définissez la priorité du contenu initialement visible.

Avant d'ajouter le chargement paresseux à nos images, le navigateur avait un carrousel d'images avec tous nos gribouillages. Il récupérait toutes les images au tout début du carrousel avec une priorité élevée. Malheureusement, ce sont les images au milieu du carrousel qui étaient les plus importantes pour l'utilisateur. Nous avons donc défini l'importance de ces images de fond sur très faible, et celle des images de premier plan sur très élevée. Cela a eu un impact de deux secondes sur la 3G lente, et sur la rapidité avec laquelle nous avons pu extraire et afficher ces images. C'est donc une expérience positive.

Nous espérons déployer cette fonctionnalité dans Canary dans quelques semaines. Tenez-vous prêt.

Avoir une stratégie de chargement de polices Web

La typographie est essentielle à une bonne conception. Si vous utilisez des polices Web, vous ne devez pas bloquer le rendu de votre texte et vous ne devez pas afficher de texte invisible.

Nous le soulignons désormais dans Lighthouse avec l'audit Éviter le texte invisible pendant le chargement des polices Web.

Éviter le texte invisible pendant le chargement des polices Web
Fig. 22. Éviter le texte invisible pendant le chargement des polices Web

Si vous chargez vos polices Web à l'aide d'un bloc de polices, le navigateur décide de la marche à suivre si l'extraction de cette police Web prend beaucoup de temps. Certains navigateurs attendent jusqu'à trois secondes avant de revenir à une police système, et ils la remplaceront par la police téléchargée.

Nous essayons d'éviter ce texte invisible. Dans ce cas, nous n'aurions pas pu voir les doodles classiques de cette semaine si la police Web avait pris trop de temps. Heureusement, grâce à une nouvelle fonctionnalité appelée font-display, vous pouvez mieux contrôler ce processus.

    @font-face {
      font-family: 'Montserrat';
      font-style: normal;
      font-display: swap;
      font-weight: 400;
      src: local('Montserrat Regular'), local('Montserrat-Regular'),
          /* Chrome 26+, Opera 23+, Firefox 39+ */
          url('montserrat-v12-latin-regular.woff2') format('woff2'),
            /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
          url('montserrat-v12-latin-regular.woff') format('woff');
    }

L'affichage des polices vous aide à déterminer comment les polices Web seront affichées ou remplacées en fonction du temps nécessaire à leur remplacement.

Dans ce cas, nous utilisons l'échange d'affichage de la police. Le swap attribue à la police une période de blocage de zéro seconde et une période de swap infinie. Cela signifie que le navigateur va dessiner votre texte assez rapidement avec une police de remplacement si le chargement de la police prend un certain temps. Il va le remplacer une fois que la police sera disponible.

Dans le cas de notre application, cela nous a permis d'afficher du texte pertinent très tôt et de passer à la police Web une fois qu'elle était prête.

Résultat de l&#39;affichage de la police
Fig. 23 : Résultat de l'affichage de la police

En règle générale, si vous utilisez des polices Web, comme le fait une grande partie du Web, mettez en place une bonne stratégie de chargement de polices Web.

De nombreuses fonctionnalités de plate-forme Web peuvent être utilisées pour optimiser l'expérience de chargement des polices. Consultez également le dépôt de recettes de polices Web de Zach Leatherman, car il est vraiment excellent.

Réduire les scripts bloquant le rendu

Il existe d'autres parties de notre application que nous pourrions transférer plus tôt dans la chaîne de téléchargement afin de fournir au moins une expérience utilisateur de base un peu plus tôt.

Sur la bande de la chronologie Lighthouse, vous pouvez voir que pendant ces premières secondes où toutes les ressources sont en cours de chargement, l'utilisateur ne voit pas vraiment de contenu.

Réduire les possibilités de feuilles de style bloquant le rendu
Fig. 24 : Réduire les possibilités de feuilles de style bloquant le rendu

Le téléchargement et le traitement des feuilles de style externes empêchent notre processus de rendu de progresser.

Nous pouvons essayer d'optimiser notre chemin de rendu critique en fournissant certains des styles un peu plus tôt.

Si nous extrayons les styles responsables de ce rendu initial et les insérons dans notre code HTML, le navigateur peut les afficher immédiatement sans attendre l'arrivée des feuilles de styles externes.

Dans notre cas, nous avons utilisé un module NPM appelé Critical pour intégrer notre contenu critique dans index.html lors d'une étape de compilation.

Bien que ce module ait effectué la majeure partie du travail pour nous, il a tout de même été un peu difficile de le faire fonctionner correctement sur différents itinéraires.

Si vous ne faites pas attention ou si la structure de votre site est vraiment complexe, il peut être très difficile d'introduire ce type de modèle si vous n'avez pas prévu d'architecture de shell d'application dès le départ.

C'est pourquoi il est si important de prendre en compte les performances dès le départ. Si vous ne concevez pas pour les performances dès le départ, vous risquez de rencontrer des problèmes plus tard.

Au final, notre risque a payé, nous avons réussi à le faire fonctionner et l'application a commencé à diffuser du contenu beaucoup plus tôt, ce qui a considérablement amélioré notre temps de première peinture significative.

Résultat

Voici une longue liste d'optimisations de performances que nous avons appliquées à notre site. Examinons le résultat. Voici comment notre application se chargeait sur un appareil mobile de taille moyenne sur un réseau 3G, avant et après l'optimisation.

Le score de performances Lighthouse est passé de 23 à 91. C'est un bon progrès en termes de vitesse. Toutes les modifications ont été apportées grâce à la vérification et au suivi continus du rapport Lighthouse. Si vous souhaitez découvrir comment nous avons implémenté techniquement toutes les améliorations, n'hésitez pas à consulter notre dépôt, en particulier les PR qui y ont été publiés.

Performances prédictives : expériences utilisateur basées sur les données

Nous pensons que le machine learning représente une opportunité intéressante pour l'avenir dans de nombreux domaines. Nous espérons que cette idée, qui peut vraiment guider les expériences utilisateur que nous créons, incitera à davantage d'expérimentations à l'avenir.

Aujourd'hui, nous prenons de nombreuses décisions arbitraires sur ce que l'utilisateur pourrait vouloir ou avoir besoin, et donc sur ce qui mérite d'être préchargé, prétéléchargé ou pré-mis en cache. Si nous faisons le bon choix, nous pouvons hiérarchiser un petit nombre de ressources, mais il est très difficile de l'appliquer à l'ensemble du site Web.

Nous disposons actuellement de données qui nous permettent de mieux orienter nos optimisations. Grâce à l'API Google Analytics Reporting, nous pouvons examiner la page suivante et les pourcentages de sortie pour n'importe quelle URL de notre site, et ainsi tirer des conclusions sur les ressources à prioriser.

Si nous combinons cela à un bon modèle de probabilité, nous évitons de gaspiller les données de nos utilisateurs en préchargeant de manière excessive le contenu. Nous pouvons exploiter ces données Google Analytics, et utiliser le machine learning et des modèles tels que les chaînes de Markov ou les réseaux de neurones pour les implémenter.

Regroupement basé sur les données pour les applications Web
Fig. 25. Regroupement basé sur les données pour les applications Web

Pour faciliter ces tests, nous sommes heureux d'annoncer une nouvelle initiative baptisée Guess.js.

Guess.js
Fig. 26. Guess.js

Guess.js est un projet axé sur les expériences utilisateur basées sur les données pour le Web. Nous espérons qu'il vous inspirera à utiliser les données pour améliorer les performances Web et au-delà. Tout est Open Source et disponible sur GitHub dès aujourd'hui. Il a été créé en collaboration avec la communauté Open Source par Minko Gechev, Kyle Matthews de Gatsby, Katie Hempenius et plusieurs autres personnes.

Découvrez Guess.js et dites-nous ce que vous en pensez.

Résumé

Les scores et les métriques sont utiles pour améliorer la vitesse du Web, mais ce ne sont que des moyens, et non des objectifs en soi.

Nous avons tous déjà connu des chargements de pages lents en déplacement, mais nous avons désormais la possibilité d'offrir à nos utilisateurs des expériences plus agréables qui se chargent très rapidement.

L'amélioration des performances est un processus. De nombreux petits changements peuvent entraîner de grands gains. En utilisant les outils d'optimisation appropriés et en gardant un œil sur les rapports Lighthouse, vous pouvez offrir une expérience meilleure et plus inclusive à vos utilisateurs.

Avec un remerciement spécial à: Ward Peeters, Minko Gechev, Kyle Mathews, Katie Hempenius, Dom Farolino, Yoav Weiss, Susie Lu, Yusuke Utsunomiya, Tom Ankers, Lighthouse et Google Doodles.