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 :
- Le parsing HTML s'arrête immédiatement
- Le navigateur télécharge le fichier JavaScript
- Le script s'exécute
- Le parsing HTML reprend seulement après
<script src="app.js"></script> 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 :
- Le parsing HTML continue normalement
- Le script se télécharge en parallèle
- Dès que le téléchargement est fini, le parsing HTML se met en pause
- Le script s'exécute immédiatement
- Le parsing HTML reprend
<script async src="analytics.js"></script> À 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 :
- Le parsing HTML continue normalement
- Le script se télécharge en parallèle
- Le parsing HTML se termine complètement
- Le script s'exécute seulement après
<script defer src="app.js"></script> À 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 :
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 !
Que fait un script sans attribut async ou defer ?
Sans attribut, le navigateur arrete tout, telecharge le script, l'execute, puis reprend l'affichage.