Un petit peu d'optimisation de ce site
Un petit peu de travail pour optimiser le chargement de ce site et obtenir le “Saint Gral” : 100/100 au test Google Page Speed Insights, que ce soit sur mobile ou sur navigateur classique.
C’est désormais chose faite. Pour y parvenir, voici les étapes que j’ai franchies.
J’utilise un thème Hugo pré-construit (coder). Comme de nombreux thèmes, celui-ci s’appuie énormément sur les CDN pour servir les ressources habituelles :
- font-awesome
- polices chez Google
La partie facile : tout ramener en local et ne plus dépendre des CDN externes
La premère étape a été de tout rappatrier en local pour éviter de faire un trop grand nombre de requêtes sur de nombreux sites différents. Cela peut paraitre contre-intuitif, car l’objet de ces CDN est bien d’éviter à chacun de télécharger toujours les mêmes ressources à de multiples reprises, dans les faits, on n’y gagne pas tant que cela (tout le monde utilise des versions différentes) et surtout on dépend très fortement de ces CDN !
Ainsi, très facile de télécharger en local les CSS concernés et de changer le chemin vers elles dans le template. Mais cette recette n’est pas adaptée pour les ressources plus complexes telles que les polices de caractères (Google Fonts et Font-Awesome), il faut faire quelques petits efforts suppplémentaires.
font-awesome
font-awesome est une combinaison (complexe) de feuilles de style, de javascript, de polices et d’images… Tout ça pour quelques utilisations rares sur ce site.
Sur leur blog on trouve tout de même de quoi faire le travail espéré :
- il faut télécharger le dossier “free” et le dézipper en local
- sélectonner ce dont vous avez besoin uniquement, en général :
- le fichier
all.css
qui est indipensable - le dossier
webfonts
qui est le minimum que j’utilise. Ce dossier est à placer à la racine de votre site, tout est référencé dans la CSS en mode/webfonts
- le fichier
Une fois cela réalisé, vous servez font-awesome depuis votre site !
Google Fonts
J’ai trouvé l’article How to Self-Host Google Fonts on Your Own Server qui résume parfaitement les étapes à faire pour y parvenir. Pour chaque police dont vous dépendez :
- rendez-vous sur google-webfonts-helper
- recherchez votre police
- sélectionnez les tailles demandées pour votre police. Par exemple, dans mon thème, il y avait la ligne suivante :
<link href="https://fonts.googleapis.com/css?family=Lato:400,700%7CMerriweather:300,700%7CSource+Code+Pro:400,700&display=swap" rel="stylesheet">
- dans cette ligne, on lit pour la police
Lato
les tailles400
et700
- copiez la CSS proposée (j’ai choisi la version normale non optimisée pour supporter les anciens navigateurs) dans une feuille de style dédiée
- téléhargez et dézippez la police et placez-là par exemple dans un dossier
fonts
à la racine de votre site
J’ai donc fait un feuille de style fonts.css
et j’y ai ajouté toutes les polices de Google.
Je vous invite également à lire Should you self-host Google Fonts? qui est très complet sur le sujet (je ne l’ai trouvé que plus tard) :
To answer the question in the title of this post: yes it’s better to self-host as the performance gains are substantial.
Il nous reste encore un peu de chemin à parcourir pour obtenir la note parfaite.
Optimiser le chargement de la page
En s’appuyant sur les recommandations proposées par Google Page Speed Insights, on se rend vite compte qu’on peut gagner quelques points facilement :
- diminuer le nombre de requêtes HTTP
- diminuer la taille des resources statiques
- ne pas faire de rendu bloquant
Voyons voir comment je m’y suis pris…
Diminuer le nombre de requêtes HTTP
Le pluis simple pour réaliser cela, c’est de mettre toutes vos CSS dans un seul fichier ; attention cela peut avoir un impact négatif si vous avez de nombreux styles qui bloquent le rendu. Le sujet est vaste, on ne va pas l’aborder ici.
J’ai pour ma part 3 CSS que je voulais charger dans un seul fichier. J’utilise Hugo pour générer ce site, j’ai eu quelques difficultés à comprendre comment fonctionnait la fonction resources.Get
.
En effet, comme les CSS sont des fichiers statiques, ils doivent se trouver dans le dossier static
et hugo les recopie à la racine du sité généré, tels quels.
Pour combiner plusieurs fichiers statiques, il faut considérer ces fichiers comme des ressources pour que Hugo réalise un traitement dessus. Pour que hugo les voit, ces fichiers doivent être présents dans un dossier assets
. Après les avoir déplacés, ils sont accessibles par leur nom avec resources.Get
. Ainsi, on charge chaque CSS dans une variable avec resources.Get
, ensuite on les combine ensemble avec resources.Concat
:
{{- $fontCss := resources.Get "css/fonts.css" }}
{{- $normalizeCss := resources.Get "css/normalize-8.0.1.css" }}
{{- $customCss := resources.Get "css/custom.css" }}
{{- $css := slice $fontCss $normalizeCss $customCss | resources.Concat "css/mytheme.css" }}
<link rel="stylesheet" href="{{ $css.Permalink }}" media="screen"/>
On passe ainsi de 3 requêtes à une seule. On peut faire de même pour les fichiers javascript également.
Diminuer la taille des resources statiques
Hugo permet de minifier les contenus qu’il génère :
- pour tout le site, à la construction, avec l’option
hugo --minify
qui va compresser tous les fichiers générés (HTML, json, XML) - pour les ressources statiques avec le pipe
resources.Minify
qu’il suffit d’ajouter à la création de la variable$css
:{{- $css := slice $fontCss $normalizeCss $customCss | resources.Concat "css/mytheme.css" | resources.Minify }}
On peut aller plus ploin et en profiter pour faire du fingerprinting et du SRI de nos ressources statiques avec le pipe resources.Fingerprint
. Cela nous donne le template suivant :
{{- $fontCss := resources.Get "css/fonts.css" }}
{{- $normalizeCss := resources.Get "css/normalize-8.0.1.css" }}
{{- $customCss := resources.Get "css/custom.css" }}
{{- $css := slice $fontCss $normalizeCss $customCss | resources.Concat "css/mytheme.css" | resources.Minify | resources.Fingerprint "sha512" }}
<link rel="stylesheet" href="{{ $css.Permalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous" media="screen"/>
La code généré dans la page HTML est le suivant :
<link rel=stylesheet
href=https://jp.caruana.fr/css/mytheme.min.48d62b9e7e906ff0bfd3b5e106f8d66d8c89924348bd360f2bde5455abdd74c60884498e89d3b75708cd183e9f195f148074ee33375453adb3b3d5b816453564.css
integrity="sha512-SNYrnn6Qb/C/07XhBvjWbYyJkkNIvTYPK95UVavddMYIhEmOidO3VwjNGD6fGV8UgHTuMzdUU62zs9W4FkU1ZA=="
crossorigin=anonymous media=screen>
Eviter les rendus bloquants
Je me suis rendu-compte que le chargement des polices pouvoit bloquer le rendu. L’option CSS font-display: swap
permet de dire au navigateur de dessiner les mots sur la page avant la fin du téléchargement de toutes les polices, quitte à changer l’affichage final de manière un peu brutale (on peut observer un effet de clignotement). Pour que cela fonctionne, il faut bien sûr utiliser les bonnes pratiques du web en préciser à chaque fois un famille de police de plus en plus générale, par exemple : text-font-family: Merriweather, Georgia, serif;
@font-face {
...
font-display: swap;
}
Enfin, le chargement de font-awesome pesait lourd dans le rendu, j’ai donc choisi de la déplacer en fin de document, hors de la balise <head>
, juste avant la balise </body>
.
Avec toutes ces mesures, j’ai pu atteindre la note maximale :
Réactions
Je viens d’ajouter la recherche sur ce site : elle est disponible depuis le lien /search. Enjoy 😉
J’ai eu quelques difficultés à la mettre en place : la documentation sur hugo à ce sujet est difficle à comprendre et vraiment pas claire du tout ; poser des questions sur le forum amène souvent à des réponse de la forme “lis la doc” qui n’aident pas du tout au regard de la complexité de celle-ci. Il existe un grand nombre d’articles sur le sujet, mais hugo a évolué tellement que la plupart de ces articles proposent quelque chose qui ne fonctionne pas.
Je me suis fortement inspiré de ce gist. Contraitement à ce qu’on trouve en général sur internet, cette implémentation s’appuie sur fuse.js et non sur lunr.js comme on trouve habituellement aujourd’hui. Je n’ai pas d’avis sur la question, mais en tout cas cela fonctionne pour moi, c’est la première qualité du code !
Par contre je suis un peu “chagrin” car il a fallu que j’implémente à nouveau un peu de templating du site pour les réponses à une recherche, mais en js/html plutot que en hugo : de la duplication pas facile à faire sauter… J’ai également fait le choix de ne pas servir les fichiers javascript supplémentaires (fuse, jquery) par mon site mais de passer par les CDN existants (contrairement à ce que j’ai fait dans Un petit peu d’optimisation de ce site) car je me dis que la recherche sera très peu utilisée et qu’il n’est pas nécessaire d’en optimiser le chargement.
Mais alors, pourquoi l’avoir implémentée cette recherche ?
J’avance bien sur mon passage en niveau 2 qui est constitué des éléments suivants :
Il ne me reste plus qu’un point à résoudre pour arriver au niveau 2, le niveau 3 implique de faire toutes ses interractions, y compris avec twitter et autres, depuis son propre site… exitant !