Une confession difficile…

Patricia Filiatrault fait présentement une promo sur sa formation SEO et m’a demandé un petit coup de main pour en faire la promo.

Avant de faire mon contenu pour l’aider, j’ai été sur Google Analytics pour voir ce qui se passait de ce côté-là avec La Tranchée et ce que j’ai vue m’a pétrifié.

image

Je suis passé de 50 000 utilisateurs mensuels générés par Google à environ 10 000, une baisse de 80%.

Je ne pouvais donc pas, en bonne conscience, te dire de mettre le SEO dans tes priorités sans d’abord le mettre dans les miennes.

J’ai donc travaillé 12 heures par jour depuis mercredi passé pour trouver et régler tous les problèmes de SEO de mon site web.

J’ai détaillé ma démarche dans cet article de blogue:

https://www.latranchee.com/une-confession-difficile/

J’ai vraiment travaillé fort pour optimiser la plateforme. Si jamais tu as des questions ou commentaires, ne te gêne surtout pas!

9 « J'aime »

Probablement que grâce à ta confession, on sera plusieurs à prendre le SEO plus au sérieux. Merci d’oser te dévoiler :wink:

4 « J'aime »

Hehehe! Si je partage mes bons coups, c’est normal que je partage les moins bons! L’important, c’est d’apprendre et corriger le tir.

J’ai reçu plusieurs courriels de gens qui ont vécu une situation similaire. De grosses pertes de trafic pour des erreurs SEO qui auraient pu facilement être évités!

J’ai continué de faire quelques tweaks depuis mardi. Je suis rendu vraiment obsédé de l’optimisation du site! :laughing:

J’ai peur de faire peur aux gens en parlant du côté plus techniques, puisque c’est assez facile d’optimiser un site WordPress et Shopify fait presque tout la job pour toi.

@Alexe a partagé un screenshot de son rapport GTmetrix sur son Instagram:

image

Après qu’on a un bon score comme ça, ne reste plus qu’à se concentrer sur la création de contenu!

3 « J'aime »

Moi aussi je suis vraiment obsédé par l’optimisation c’est pour ça que j’héberge des sites wordpress maintenant

Ce site est fait avec DIVI qui n’est pas une référence pour la rapidité.

image

et d’autres sites que j’héberge et optimise pour des clients (noter que page load n’est pas la même chose que LCP)
image

2 « J'aime »

Outre que ça aide pour ton classement, avoir un site qui est chargé en 0,8s vs 12s pour ton compétiteurs ça te donne un méchant avantage.

2 « J'aime »

Définitivement! Et ça fidélise la clientèle. Un site lent, ce n’est pas le fun et ça ne donne pas le goût de l’utiliser.

J’ai longtemps été coupable de me dire que, puisque La Tranchée est un site de formation, personne n’écoute des formations sur son cellulaire. :joy: Et ceux qui le font ont tort et devraient sortir leur laptop.

Bien en optimisant pour mobile, je me suis rendu compte que, quand ça va bien, c’est quand même cool de pouvoir suivre une formation pendant que tu es sur la :toilet:! 🫣

3 « J'aime »

Si proche de la perfection :slight_smile:


1 « J'aime »

La dette d’une mauvaise conception

Bref, après plus de 100 heures passées à tout reprogrammer mon site, j’ai ENFIN réussi à obtenir un résultat “acceptable”.

Quand la conception est mal faite au début, on paie très cher pour corriger les erreurs de conceptions.

Sans passer le bulldozer sur ta plateforme @Olivier_Lambert, tu pourrais changer ou optimiser la conception de la partie blogue. Voici quelques pistes…

Mauvais framework pour un site web

Le problème que je constate souvent avec les « vieux » sites écrient en javascript comme Nuxt, c’est qu’il bundle le code pour des applications (portail privé pour les plus vieux lecteurs) où le SEO et la performance n’est pas une priorité comme pour un site web.

Heureusement, il y a eux des énormes progrès depuis quelques mois à ce niveau. Il permet de partitionner ton bundle.js qui est envoyé sur ton site web et de les charger après le contenu de ton blogue. Il permet même d’optimiser automatiquement les images pour les navigateurs et le SSR!


Pourquoi charger l’api Stripe sur le blogue?

Diviser pour mieux régner.

Ce que je conseille, c’est de déployer des sites web en jamstack et de déployer en îles des parties qui demande du javascript (vue.js/react/svelte/nameit 3.0!). Exemple: bouton d’achat, commentaires, etc.

La résilience, on aime ça!

De plus, avec le déploiement statique, tu vas pouvoir bénéficier de la puissance du réseau de ton CDN. Ce qui veut dire que si ton Wordpress est hors-ligne, ton site web fonctionne encore :exploding_head:.

Voici quelques références pour mieux comprendre le sujet:

Framework jamstack (générateur de site web statique)

Astro: (poly framework compatible vue.js)

Svelte Kit : utilisé par le New York Times

J’espère que mes conseilles non sollicités :grin: peuvent aider @Olivier_Lambert ou quelqu’un d’autre qui fait leur site web sans passer par DIVI/Elementor ou des thèmes Wordpress

1 « J'aime »

Je n’ai pas été dans le technique, mais c’est exactement ce que je voulais dire lorsque j’ai dit:

Nuxt est fantastique. C’est la première plateforme qui a permis de faire du Server Side Rendering (SSR) avec Vue.

Sans Nuxt, Google n’aurait vue que des pages blanches. C’est donc essentiel que les pages soient générés côté serveur avant d’être envoyés vers le client.

Maintenant, pour ce qui concerne la méthodologie Jamstack, l’idée est de servir des générer des pages STATIQUES et de les déployer le plus près du visiteur.

Le problème avec ça, c’est que les pages de La Tranchée ne sont toutes statiques. Si tu es connecté, tu as une page différente de celle que tu reçois si tu n’es pas connecté.

La solution à ce problème est donc de servir certaines sections de ton application de façon dynamique et d’autres de façon statique. On dit que ce genre de déploiement est « hybride ».

Le problème avec Nuxt2, c’est qu’il ne permet pas ce genre de déploiement. Soit que tout est statique, soit que tout est interactif. Nuxt3 vient donc à la rescousse pour régler ce problème avec le déploiement hybride.

Pour ce qui est du développement en île, c’est déjà l’approche que j’utilise et c’est un des changements techniques que j’ai apporté au site.

Avant, le serveur générait une version différente du contenu de chaque page « on the spot » à chaque chargement, ce qui rendait le serveur lent à répondre.

Maintenant, j’utilise Redis pour mettre la version de base en cache et de la servir ultra rapidement au client. Par la suite, une fois le module en vue, la personnalisation se charge:

En d’autres mots, je « lazy load » toutes les composantes du sites qui n’ont pas besoin d’être affichées dès le départ.

J’ai également utilisé Cloudinary pour optimiser le chargement des images. Maintenant, que tu sois sur mobile, tablette ou ordinateur, une version spécifique de l’image est utilisée.

La version des images change dynamiquement selon la taille du navigateur.

J’ai aussi supprimé la police d’icône et j’ai remplacé l’ensemble des icônes du site en SVG, ce qui sauve environ ~500K de données au premier chargement du site.

Quill.Js, l’éditeur que j’utilisais pour le texte, était également chargé partout. Il était quand même lourd alors je l’ai remplacé par un éditeur que j’ai créé avec TipTap. De cette façon, je peut le charger dynamiquement uniquement lorsqu’on en a besoin.

Les plus gros changements que j’ai fait sont surtout côté serveur:

  1. J’ai réduit les données au stricte minimum. Le serveur ne sert que les données que le client utilise. J’ai passé la taille des données d’une page de 500K à ~12K.
  2. J’ai mis à jour et optimisé ma base de donnée, ce qui a accéléré la vitesse des requêtes d’environ 80%.

Finalement, j’ai utilisé PurgeCSS pour me permettre d’inclure uniquement le CSS utilisé, ce qui m’a permi de faire passer les feuilles de style de 50 à à ~2kb.

Pour améliorer encore la vitesse du site, j’ai pas mal juste 2 choses sur ma To Do:

  • Utiliser Redisearch pour refaire le module de recherche du site. C’est une tâche de 3-4 jours.
  • Migrer vers Nuxt3, c’est plus un projet de 2-3 mois. J’aime mieux attendre qu’ils aient une version stable avant de me lancer. :stuck_out_tongue:

Nuxt3 va me permettre d’activer le Edge caching, une fonction vraiment cool qui permet de stocker ton app, non pas dans un SERVEUR près du client, mais dans la mémoire du fournisseur Internet que la personne utilise! Ce n’est pas Bell/Vidéotron qui appel le serveur le plus près, mais bien Bell qui génère et te sers le site directement.

On peut lire plus sur Nuxt3 + Netlify ici: Nuxt 3 - Netlify


Bref, je n’ai pas abordé tout ça dans l’article puisque ce ne sont pas des choix que les gens normaux doivent faire.

Si tu es sur WordPress, les chances sont que tu roules un thème monté en PHP et que tu peux profiter de la suite de plugins d’optimisation qui existe déjà.

Tout ce que je dis ne concerne que les gens qui décident de faire une applicaiton web. Dans le cas de La Tranchée, j’y ai été un peu overkill sans trop savoir dans quoi je m’embarquais. Au final, je suis content de l’avoir fait, mais c’est définitivement une courbe d’apprentissage.

Pour la détection de la fraude tout simplement. Puisque le script est loadé avec le tag « DEFER », ça n’impact pas vraiment le temps avant l’interactivité, le gros problème que j’ai présentement!

1 « J'aime »

C’est très bien ce que tu as fait jusqu’à présent avec la cache redis et les optimisations.

Actuellement, j’ai l’impression qu’il y a beaucoup de code mort qui se charge et s’exécute inutilement (56% javascript et 72% en CSS) quand on navigue sur https://www.latranchee.com/une-confession-difficile/ .

Si tu génères un rapport Lighthouse pour le post de cet article en version mobile, par exemple, tu as tes bundles js qui prennent un 4,87s (dans mon environnement). Avec le même code en production et un algorithme de tree sacking avec ton bundler webpack ou vite.js, tu pourrais atteindre plus que la moitié de chargement de la version actuelle avec Nuxt 2.

Le problème avec ça, c’est que les pages de La Tranchée ne sont toutes statiques. Si tu es connecté, tu as une page différente de celle que tu reçois si tu n’es pas connecté.

Pour ton blogue? Je ne crois pas. Si tu parles de menu si tu es connectés, il y a moyen.

Ça serait pertinent dans ton cas que le serveur ou le CDN livre le plus possible du HTML et CSS et garder que le js pour tes analytics. Quand un utilisateur embarque sur une autre portion du site web, là tu pourras charger les composantes nécessaires pour faire la recherche dans redis par exemple ou charger ton éditeur.

Le principe, c’est que tout ce que tu utilises par la portion formation, forums ou autres fonctionnalités ne doit pas être là pour alourdir les pages de code mort.

En conclusion, c’est que les critères de Google vont être plus sévères dans 4 ans. Ça sera à refaire pour garder un bon score! Vive le progrès!

Je n’ai pas le code source sous les yeux, mais je suis presque certain que c’est possible avec Nuxt2. Si tu as besoin d’éclaircissement, je pourrais t’aider à t’aligner avec ce que tu as si tu es intéressé par mon aide.

Il y a du code qui t’attend! :nerd_face:

J’ai déjà le Tree Shaking d’activé hahahaha! Je n’ai pas beaucoup de contrôle sur le bundle size de Nuxt. La version 3 est sensé avoir un bundle size environ 75 fois plus petit. :sweat_smile:

Je crois que vite.js est pour du hot swapping de code en production alors ça ne devrait pas avoir d’impact sur la performance une fois déployé. Ça accélère le build time par contre!

En même temps, les appareils sont de plus en plus rapides. Je ne sais pas à quel point l’accélération des bandes passantes et des appareils mobiles ne vont pas justement rendre les critères plus flexible. En bout de ligne, c’est l’expérience utilisateur qui compte!

Ce qui me dérange vraiment avec la façon dont les tests sont construits est que Nuxt pré-render la page a affiché, l’affiche sur le client et le client ensuite « hydrate » la page.

Ça veut dire que la page prend environ 1 secondes à charger et 100% du contenu essentiel est déjà afficher. L’expérience pour le client est vraiment bonne!

Par contre, l’hydration du site, c.a.d. l’activation de l’interactivité des composantes chez le client, prend quelques secondes tout dépendant de la vitesse de l’appareil.

Cette étape ne nuit aucunement à l’expérience. Autant qu’on peut truquer les test avec mon petit hack sur le Largest Contentful Paint, autant que ces test se trompent dans leur évaluation.

Exemple, ma page « /accueil » tu dois la voir en navigation privée, charge instantanément.

Par contre, à cause du slider de fond, GTmetrix pense qu’elle prend 8.5s à charger. :sweat_smile:

L’autre truc qui me met un gros point d’interrogation sur la tête est que, si je fini par générer le site de façon hybride, c’est-à-dire que j’ai certains urls qui sont pré-compilés à l’avance et qui n’ont pas besoin d’interagir avec ma base de données pour être livrés au client, comment est-ce que je fais pour que les nouveaux articles de blogues soient compilés et déployés automatiquement? Si quelqu’un fait une modification, comment faire pour remplacer le fichier générés chez les CDN?

In any case, je vais attendre la période de 28 jours de Google Search Console. Good enough is perfect. Si Google juge mes URLS « bonnes » autant sur desktop que mobile, je vais pouvoir mettre une pin dans l’optimisation pendant un 6-7 mois et mesurer l’impact sur le SEO.

En fait, le tree shaking permet juste d’importer les fonctions qu’utilises sur tes dépendances internes ou externes (node_modules) comme expliquées dans cette documentation. Une fois le bundle produit, ça reste le même pour l’ensemble de ton site web même si dedans il y a une bonne partie de code mort pour le contexte de ta page.

https://rollupjs.org/guide/en/#tree-shaking

En fait, vite.js c’est une couche de rollup.js qui est utilisée pour bundler ton code en production. La surcouche vite est pour la partie HRM (Hot reload modules) quand tu fais du développement.

Une méthode possible : mettre un webhook sur ton CI/CD comme Github Actions ou Gitlab CI/CD pour tes articles. Si tu es familier avec les CI/CD, tu peux automatiser le build pour générer tes fichiers statiques et ensuite les déployer sur un CDN. Tu peux aussi le faire sur les commentaires à une fréquence acceptable avec un scheduler ou par webhook.

Pour la partie hybride, tu peux utiliser des imports dynamiques pour dire à ton bundler de splitter ton code en plusieurs bundles. Par exemple, la partie blogue pourra seulement charger dynamiquement, après l’affichage, juste le code concerné.

https://rollupjs.org/guide/en/#dynamic-import

La performance au niveau du temps de chargement avant interaction, c’est une question de compromis.

Par exemple, tu pourrais enlever le statut des notifications sur ta partie blogue et tu élimines peut-être une fonctionnalité que tes membres n’utilisent pas ou vois très peu de valeur. Parfois, less is more.

Fear of churn for vanity features is your enemy.

Bonne continuation!

1 « J'aime »

Exact, je prend le TreeShaking de Vuetify pour n’importer que les composantes requises dans mon bundle.

En tout cas, merci beaucoup pour tous tes commentaires! Ça m’a forcer à pousser ma réflexion et je vois mieux comment je vais pouvoir m’enligner pour la suite des choses!

Si tu connais quelqu’un qui serait capable de m’aider à faire la transition vers Nuxt3, dis-lui de me contacter!

Excellent post! Pour ma part, je trouve que ta plateforme va super bien. Merci pour le tip à propos de Gmetrix. Je suis allé faire le test pour mon site web et il me reste des croutes à manger… Au moins je sais à quoi m’attendre et sur quoi travailler pour améliorer mon score. Là je dois simplement enlever mon vidéo en background, mais même en super basse résolution, mon site score D avec Gmetrix. Aussi, j’ai bien aimé ton Hack pour contrer le Largest Content Paint. Very clever Oli.

1 « J'aime »

Ça me fait plaisir d’avoir pu t’aider à pousser ta réflexion.

Je ne conseille pas d’aller chercher spécifiquement quelqu’un qui fait du Nuxt, c’est un atout seulement, mais qui connait bien l’écosystème autour de la technologie JavaScript/node.js et l’architecture logiciel pour découpler les services.

Je te conseille de contacter Cliento.ca. J’ai déjà travaillé avec elle. Je crois que c’est la meilleure personne au Québec pour t’aider à ce sujet au niveau service-conseil.

Sinon, tu peux prendre rendez-vous avec moi (single-use link). Tous mes projets de service-conseil touchent node.js.

Petit update! J’ai continué de faire des micro optimisations ici et là au fur et à mesure que j’ai eue plus d’idées!

On y est presque! :slight_smile:

2 « J'aime »

Je viens de trouver les métriques qu’ils utilisent pour Lighthouse!

https://googlechrome.github.io/lighthouse/scorecalc/#FCP=1346&SI=5015&FMP=1407&TTI=11500&FCI=6500&LCP=1780&TBT=698&CLS=0&device=mobile&version=9

Quand même cool!

On peut rouler LightHouse en local aussi en allant dans la console.

Si je roule LightHouse dans mon environnement, ça donne ça sur mobile:

Et ça sur desktop:

Si seulement tout le monde avait des ordis de gamer! :stuck_out_tongue:

Pour m’aider à optimiser, j’ai fait une page complètement vide avec du contenu de base: www.latranchee.com/benchmark

Comme ça, je peux essayer d’estimer l’impact de chaque composantes sur le temps de chargement du site.

La chose qui me gosse le plus du rapport lighthouse est le « time to interactive ».

Sur mobile, ils me donnent 11 secondes, ce qui est juste complètement irréaliste. Même avec un Motorolla Razer dans un ascenseur c’est moins long que ça! :stuck_out_tongue:

1 « J'aime »

si tu roule dans la console va y en mode incognito.

mes 2 autres stops sont

1 « J'aime »

Après avoir continuer de tout essayer, je crois enfin avoir trouvé une solution à mon problème!

J’ai déployé 2 versions du site:

La première version est en mode statique et implémente la plupart des recommandations de @ebauger, c’est à dire que le site est généré statiquement et que les pages sont répartie sur un CDN.

La deuxième version est en mode SSR (comme c’était le cas jusqu’à présent).

Dans ma configuration NGINX, je demande au site de commencer par essayer de charger la version statique. Si elle n’existe pas, on sers la version SSR.

location / {
	error_page 418 = @proxy;
	expires $expires;
	if ( $query_string = "ssr=true" ) { 
		return 418;
	}
	try_files $uri $uri/index.html @proxy;
}

location @proxy {
	proxy_redirect                      off;
	proxy_set_header Host               $host;
	proxy_set_header X-Real-IP          $remote_addr;
	proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto  $scheme;
	proxy_http_version          1.1;
	proxy_read_timeout          1m;
	proxy_connect_timeout       1m;
	proxy_pass                  http://127.0.0.1:1000;
	proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
}

J’ai aussi ajouté le paramètre d’url ssr=true qui force le site dans sa version SSR pour me permettre de plus facilement tester et débuguer.

Chaque jour à 2h, j’ai une tâche cron qui regénère le site au complet. Dans la génération du build, j’ai exclu les pages qui ne sont pas indexés par Google.

Le flow de déploiement est plus clunky, mais bon! Il faut ce qu’il faut!

Voici le résultat avec le paramètre SSR:

Et sans:

Il me reste quelques améliorations à faire, surtout dans ce qui concerne le « blocking time ». Je ne suis pas certains de ce que je peux faire pour ça par contre… :thinking: Je vais continuer de faire mes devoirs! Le résultat n’est pas encore super dans lighthouse.

1 « J'aime »