Cours Web Performances & SEO
Session 2 Module 7 12 min

Optimisation JavaScript

Minification, defer/async, tree-shaking

1) Le problème : JavaScript bloque l'affichage

Par défaut, quand le navigateur rencontre une balise <script>, il arrête tout. Il télécharge le fichier JS, l'exécute, et seulement après il continue à afficher la page. Pendant ce temps : écran blanc.

C'est pour ça qu'on conseillait avant de mettre les scripts "tout en bas de page", juste avant </body>. Mais aujourd'hui, on a mieux : les attributs async et defer.

2) Sans attribut : le comportement par défaut

Quand le navigateur rencontre une balise <script> sans attribut, voici ce qui se passe :

  1. Le parsing HTML s'arrête immédiatement
  2. Le navigateur télécharge le fichier JavaScript
  3. Le script s'exécute
  4. Le parsing HTML reprend seulement après
<script src="app.js"></script>
HTML
Parsing
Bloqué
Parsing
Script
Download
Exécution
Le HTML est complètement bloqué pendant le téléchargement ET l'exécution

Problème : si ton script est gros (200 Ko, 500 Ko...), l'utilisateur voit un écran blanc pendant tout ce temps. Mauvais pour l'expérience utilisateur ET pour le SEO.

3) Avec async : téléchargement en parallèle

Avec async, le navigateur fait les choses différemment :

  1. Le parsing HTML continue normalement
  2. Le script se télécharge en parallèle
  3. Dès que le téléchargement est fini, le parsing HTML se met en pause
  4. Le script s'exécute immédiatement
  5. Le parsing HTML reprend
<script async src="analytics.js"></script>
HTML
Parsing
Pause
Parsing
Script
Download
Exécution
Téléchargement en parallèle, exécution dès que le script est prêt
Idéal pour : Analytics, tracking, scripts indépendants qui n'interagissent pas avec la page
💡

À retenir : avec async, le script s'exécute dès qu'il est prêt, même si la page n'est pas encore complètement chargée. L'ordre d'exécution n'est pas garanti si tu as plusieurs scripts async.

4) Avec defer : exécution après le HTML

Avec defer, le comportement est encore meilleur pour la plupart des cas :

  1. Le parsing HTML continue normalement
  2. Le script se télécharge en parallèle
  3. Le parsing HTML se termine complètement
  4. Le script s'exécute seulement après
<script defer src="app.js"></script>
HTML
Parsing complet
Terminé
Script
Download
Exécution
📋 Téléchargement en parallèle, exécution après que le HTML soit complètement parsé
Idéal pour : Scripts du site, interactions UI, tout code qui manipule le DOM
💡

À retenir : avec defer, le script s'exécute après que toute la page soit prête. Si tu as plusieurs scripts defer, ils s'exécutent dans l'ordre où ils apparaissent dans le HTML.

5) Récapitulatif : quand utiliser quoi ?

Attribut Téléchargement Exécution Ordre garanti ?
Rien Bloque le HTML Immédiate Oui
async En parallèle Dès que prêt Non
defer En parallèle Après le HTML Oui
Pourquoi ne pas tout mettre en async ?

Avec async, le script s'exécute dès qu'il est téléchargé, même si la page n'est pas encore prête. Deux problèmes :

  • Erreurs potentielles : si ton script essaie de manipuler un élément HTML qui n'existe pas encore, ça plante
  • Ordre non garanti : si tu as script A qui dépend de script B, et que A se télécharge plus vite, il s'exécutera avant B = erreur
Pourquoi ne pas tout mettre en defer ?

Avec defer, le script attend que toute la page soit affichée. C'est parfait pour la plupart des cas. Mais pour certains scripts comme Google Analytics, on veut qu'ils commencent à tracker le plus tôt possible, sans attendre la fin du chargement. D'où l'intérêt de async pour ce type de script.

💡

Règle simple :

  • Rien (bloquant) : scripts critiques qui DOIVENT s'exécuter avant le rendu (détection dark mode, polyfills...). C'est rare, mais ça existe.
  • defer : 90% des scripts de ton site (navigation, formulaires, sliders...)
  • async : scripts tiers indépendants (Analytics, Facebook Pixel, Hotjar)

6) Exemple d'un <head> bien optimisé

Voici un exemple concret avec différentes stratégies de chargement. Chaque script a un rôle différent, donc une stratégie différente :

Exemple : un <head> bien optimisé
📄 index.html
 
preload
Police critique : on dit au navigateur "télécharge ça en priorité absolue". Utilisé pour la police principale qui s'affiche dès le premier écran.
async
Google Analytics : peut s'exécuter n'importe quand, pas besoin d'attendre que la page soit prête. Il compte juste les visites.
defer
Code du site : attend que la page soit complètement affichée avant de s'exécuter. C'est le comportement recommandé pour 90% des scripts.
type="module"
JavaScript moderne : les modules sont automatiquement "defer". Pas besoin d'ajouter l'attribut, c'est le comportement par défaut.
Résumé : preload pour les ressources critiques, async pour le tracking, defer pour tout le reste. Simple !

7) Minification JavaScript

Comme pour le CSS, la minification supprime les espaces, commentaires et raccourcit les noms de variables. Un fichier JS peut perdre 30 à 60% de sa taille.

Outils de minification

Bonne nouvelle : si tu utilises un outil moderne, c'est déjà fait automatiquement.

  • Frameworks modernes : Vite, Next.js, Nuxt, Astro minifient automatiquement
  • WordPress : WP Rocket, Autoptimize, LiteSpeed Cache
  • Outils en ligne : JavaScript Minifier

8) Supprimer les scripts inutiles

Chaque script a un coût. Même avec defer, le navigateur doit quand même tout télécharger et exécuter. L'optimisation la plus efficace : supprimer ce qui ne sert pas.

Les coupables habituels
  • Plugins WordPress : beaucoup chargent leur JS sur TOUTES les pages, même là où tu n'en as pas besoin
  • Widgets sociaux : les boutons "J'aime" Facebook ou "Partager" Twitter chargent souvent 500 Ko à 1 Mo de JS chacun
  • Chat en ligne : Intercom, Crisp, Drift... pratiques mais très lourds (200-500 Ko)
  • Analytics en double : Google Analytics installé 2 fois, ou GA + GTM mal configuré

Comment auditer : Chrome DevTools → onglet Network → filtre par "JS". Tu verras tous les fichiers JavaScript et leur poids. Pour chacun, demande-toi : "Ce script est-il vraiment utile ici ?"

9) Charger les scripts au bon moment

Certains scripts n'ont pas besoin d'être là dès le départ. Pourquoi charger le chat alors que 90% des visiteurs ne l'utiliseront jamais ?

Stratégies de chargement intelligent
  • Au scroll : charger quand l'utilisateur commence à scroller
  • Au clic : charger le chat uniquement quand on clique sur "Nous contacter"
  • Après X secondes : attendre 5-10 secondes après le chargement
📋

Exemple YouTube : au lieu d'embarquer directement la vidéo (1-2 Mo de JS), affiche juste l'image miniature. Le lecteur YouTube ne se charge que quand on clique sur "Play". On appelle ça une façade.

10) Pour aller plus loin

Ces techniques sont plus avancées mais bonnes à connaître :

  • Code splitting : diviser le JS en plusieurs fichiers. Chaque page ne charge que ce dont elle a besoin.
  • Tree shaking : quand tu utilises une librairie, l'outil de build ne garde que les fonctions utilisées.
  • Partytown : fait tourner les scripts tiers (analytics, pubs) dans un processus séparé.
💡

Si tu utilises un framework moderne (Next.js, Nuxt, Astro...), le code splitting et le tree shaking sont déjà activés. Tu n'as rien à faire !

Question 1/4

Que fait un script sans attribut async ou defer ?

Sans attribut, le navigateur arrete tout, telecharge le script, l'execute, puis reprend l'affichage.