Vous importez une seule fonction d'une bibliothèque qui en propose deux cents. Les cent quatre-vingt-dix-neuf autres n'ont aucune raison de voyager jusqu'au navigateur du visiteur.
Le tree shaking sert exactement à cela : secouer l'arbre des dépendances et laisser tomber les branches mortes.
Définition
Le tree shaking est l'élimination, au moment du build, du code exporté qu'aucun fichier n'importe. Un Bundler (empaqueteur) construit le graphe des imports, marque ce qui est réellement atteint, puis écrit le fichier final sans le reste.
// outils.js
export function formaterPrix(valeur) {
return valeur.toFixed(2) + " EUR";
}
export function genererFacturePdf(commande) {
// 40 Ko de dépendances mobilisées ici
return commande;
}
// main.js
import { formaterPrix } from './outils.js';
console.log(formaterPrix(12.5)); // 12.50 EUR
// Dans le fichier produit : genererFacturePdf a disparu,
// et ses 40 Ko de dépendances avec elle.Le gain vient rarement de votre propre code. Il vient des dépendances, où un import mal ciblé embarque une bibliothèque entière pour trois lignes utiles.
Pourquoi cela n'est possible qu'avec les modules ES
Un Module ES déclare ses imports et ses exports de façon fixe, en tête de fichier, sans condition. L'outil peut donc décider avant toute exécution ce qui est utilisé.
Avec CommonJS, require() est un appel ordinaire, dont le chemin peut être calculé et le résultat modifié en cours de route. Aucune analyse fiable n'est possible, donc rien n'est retiré. C'est l'argument technique le plus fort en faveur des modules ES sur du code neuf.
Un import de la forme import * as tout from './outils.js' suivi d'un accès dynamique par variable rend l'analyse impossible : le bundler ne peut pas savoir quelle propriété sera lue, donc il garde tout.
Ce qui empêche l'élagage
- Les effets de bord : un module qui, au chargement, modifie un objet global ou installe un écouteur ne peut pas être retiré sans risque, même si aucun de ses exports n'est utilisé.
- Le doute : dans l'incertitude, un bundler conserve. Sa priorité est de ne rien casser, pas de gagner un kilo-octet.
- Une déclaration manquante : le champ
"sideEffects": falsed'un package.json annonce qu'un paquet peut être élagué sans crainte. Sans lui, l'outil reste prudent.
Questions fréquentes
Faut-il activer le tree shaking ?
Il l'est déjà dans la configuration de production des outils courants. La vraie question porte sur les conditions à réunir pour qu'il opère : des modules ES, des imports nommés, et des dépendances distribuées dans un format analysable.
Comment vérifier qu'il a fonctionné ?
En regardant le rapport de composition du bundle, que tous les empaqueteurs savent produire. Il montre le poids réel de chaque module dans le fichier final. Chercher au hasard le nom d'une fonction dans le fichier minifié ne prouve rien, puisque les noms internes ont changé.
Pourquoi une bibliothèque reste-t-elle entière dans mon bundle ?
Trois causes principales : elle n'est publiée qu'en CommonJS, elle est importée en bloc plutôt que par exports nommés, ou elle exécute du code au chargement. Beaucoup de paquets proposent une version en modules ES : c'est celle qu'il faut viser.