Le tree shaking est une technique d’optimisation du code JavaScript qui consiste à éliminer les modules ou fonctions inutilisés lors du bundling. Popularisée par les bundlers modernes comme Webpack et Rollup, elle permet de réduire considérablement la taille des fichiers livrés au navigateur, améliorant ainsi les performances et le temps de chargement. Cet article vous explique en détail ce qu’est le tree shaking, son fonctionnement, comment l’appliquer dans vos projets, et les pièges à éviter.
Qu’est-ce que le tree shaking exactement ?
Le terme tree shaking vient de l’image d’un arbre que l’on secoue pour faire tomber les feuilles mortes. En programmation, il s’agit de retirer du code mort (dead code) – c’est-à-dire des exportations non utilisées – du bundle final. Par exemple, si vous importez une bibliothèque comme Lodash, mais que vous n’utilisez que la fonction debounce, le tree shaking permet de n’inclure que cette fonction dans le bundle, et non la totalité de la bibliothèque.
Cette optimisation repose sur les modules ES (ES Modules ou ESM), qui sont statiques et analysables à la compilation. Contrairement à CommonJS (require), les imports et exports en ESM sont déclarés explicitement, ce qui permet aux bundlers de déterminer quels symboles sont réellement utilisés.
Comment fonctionne le tree shaking ?
Le processus se déroule en plusieurs étapes :
- Analyse statique : le bundler parcourt l’arbre des dépendances et repère les imports et exports. Grâce aux modules ES, il sait exactement quelles fonctions, classes ou variables sont importées.
- Identification du code inutilisé : tout symbole exporté mais jamais importé ailleurs est marqué comme dead code.
- Élimination : lors de la phase de minification (souvent avec Terser), le code mort est supprimé du bundle final.
Il est important de noter que le tree shaking ne peut pas fonctionner avec des imports dynamiques ou des modules CommonJS, car leur structure n’est pas analysable statiquement. C’est pourquoi de nombreuses bibliothèques modernes fournissent une version ESM dans leur package.
Comment appliquer le tree shaking dans vos projets ?
1. Utilisez des modules ES (ESM)
Assurez-vous que votre code et vos dépendances utilisent la syntaxe import/export. Dans votre package.json, vous pouvez spécifier "type": "module" pour que Node.js traite les fichiers .js comme des modules ES. Pour les bibliothèques, vérifiez qu’elles proposent un champ "module" ou "exports" pointant vers un fichier ESM.
2. Configurez votre bundler
Avec Webpack : depuis Webpack 2, le tree shaking est activé par défaut en mode production. Il suffit de définir mode: 'production' dans votre configuration. Vous pouvez aussi utiliser optimization.usedExports: true pour activer l’analyse des exports utilisés.
Avec Rollup : le tree shaking est natif et activé par défaut. Rollup est conçu dès le départ pour l’optimisation des modules ES.
Avec Vite : Vite utilise Rollup en production, donc le tree shaking est automatique.
3. Utilisez des imports nommés plutôt que des imports par défaut
Privilégiez les imports nommés pour faciliter l’analyse statique. Par exemple :
// ✅ Bon
import { debounce } from 'lodash-es';
// ❌ Mauvais (importe tout l'objet)
import _ from 'lodash';
Notez que lodash-es est la version ESM de Lodash, compatible avec le tree shaking.
4. Évitez les effets de bord (side effects)
Un module peut avoir des effets de bord (side effects) même si aucun de ses exports n’est utilisé – par exemple, un fichier qui modifie le prototype d’un objet ou qui exécute du code au moment de l’import. Dans ce cas, le bundler ne peut pas supprimer le module car cela modifierait le comportement global. Pour indiquer que votre code est sans effet de bord, ajoutez "sideEffects": false dans votre package.json. Si certains fichiers ont des effets de bord, vous pouvez lister ceux-ci :
{
"sideEffects": [
"./src/polyfills.js",
"*.css"
]
}
5. Minifiez le bundle
Le tree shaking ne supprime pas le code mort à lui seul ; il le marque. C’est le minificateur (comme Terser) qui l’élimine réellement. Assurez-vous que votre bundler utilise un minificateur en production. Avec Webpack, TerserWebpackPlugin est intégré par défaut en mode production.
Exemple concret : tree shaking avec Webpack
Imaginons un projet simple avec deux fichiers :
// utils.js
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
// main.js
import { add } from './utils.js';
console.log(add(2, 3));
Avec Webpack en mode production, le bundle final ne contiendra que la fonction add, pas subtract. Pour le vérifier, vous pouvez analyser le bundle avec webpack-bundle-analyzer.
Comparaison : Webpack vs Rollup pour le tree shaking
| Critère | Webpack | Rollup |
|---|---|---|
| Tree shaking natif | Oui (depuis v2) | Oui (conçu pour) |
| Support CommonJS | Oui (via plugins) | Limite (nécessite plugin) |
| Performance pour les librairies | Moyenne | Excellente |
| Idéal pour | Applications complexes | Librairies et petits bundles |
Pièges et erreurs courantes
- Utiliser des imports par défaut sur des modules CommonJS : même si vous importez une seule fonction, si la bibliothèque est en CommonJS, le tree shaking ne fonctionne pas. Préférez les versions ESM.
- Oublier de configurer
sideEffects: si votre package a des effets de bord non déclarés, le bundler peut conserver du code inutile par prudence. - Importer depuis un index barrel : les fichiers
index.jsqui réexportent tout peuvent empêcher le tree shaking si le bundler ne peut pas suivre les réexports. - Utiliser Babel avec des modules CommonJS : si Babel transforme vos imports ES en
require, le tree shaking est impossible. Configurez Babel pour préserver les modules ES (modules: false).
FAQ sur le tree shaking
Le tree shaking fonctionne-t-il avec TypeScript ?
Oui, à condition que TypeScript soit configuré pour produire des modules ES. Dans tsconfig.json, définissez "module": "esnext" ou "module": "es2015" et évitez "module": "commonjs". Le bundler se chargera ensuite du tree shaking.
Le tree shaking réduit-il le temps de build ?
Non, il peut même l’augmenter légèrement car l’analyse est plus poussée. En revanche, le temps de chargement côté navigateur est amélioré.
Peut-on appliquer le tree shaking à du CSS ?
Le tree shaking est généralement réservé au JavaScript. Pour le CSS, on parle plutôt de purge avec des outils comme PurgeCSS, qui suppriment les classes inutilisées.
Comment vérifier que le tree shaking fonctionne ?
Utilisez un analyseur de bundle comme webpack-bundle-analyzer ou source-map-explorer. Vous pouvez aussi inspecter le bundle généré et rechercher des fonctions que vous n’avez pas importées.
Checklist pour appliquer le tree shaking
- ✅ Vérifiez que votre code utilise des modules ES (import/export).
- ✅ Utilisez des imports nommés plutôt que des imports par défaut.
- ✅ Configurez votre bundler en mode production.
- ✅ Déclarez
"sideEffects": falsedans votre package.json (si applicable). - ✅ Utilisez un minificateur (Terser, esbuild).
- ✅ Préférez des bibliothèques avec un champ
"module"dans leur package.json. - ✅ Évitez les barrel files (index.js qui réexporte tout).
- ✅ Analysez votre bundle pour confirmer les gains.
Recommandations pratiques pour tirer le meilleur parti du tree shaking
Pour maximiser les bénéfices du tree shaking, commencez par auditer vos dépendances. Remplacez les grosses bibliothèques comme Lodash ou Moment.js par des alternatives plus légères ou des imports ciblés. Par exemple, utilisez date-fns plutôt que Moment.js, car date-fns est modulaire et compatible ESM.
Ensuite, structurez votre code en petits modules cohérents. Évitez les fichiers monolithiques qui exportent de nombreuses fonctions. Plus vos modules sont granulaires, plus le tree shaking sera efficace.
Enfin, intégrez le tree shaking dans votre pipeline de build dès le début du projet. Il est plus facile de partir sur de bonnes bases que de migrer un projet existant. Si vous reprenez un projet, commencez par passer en modules ES et ajustez la configuration.
Le tree shaking est un levier d’optimisation puissant, mais il ne fait pas tout. Combinez-le avec d’autres techniques comme le code splitting, le lazy loading, et la compression pour des performances optimales. En appliquant ces conseils, vous réduirez la taille de vos bundles et offrirez une meilleure expérience à vos utilisateurs.

16 Comments
Article très utile ! Je me demandais si le tree shaking pouvait être appliqué au CSS ou uniquement au JavaScript ?
Le tree shaking est spécifique au JavaScript. Pour le CSS, on parle plutôt de purge CSS (par exemple avec PurgeCSS), qui supprime les classes inutilisées. Les mécanismes sont différents mais l’objectif est similaire : réduire la taille des fichiers.
Dans mon projet, j’utilise Babel pour transpiler le code. Est-ce que cela peut casser le tree shaking ?
Oui, si Babel transforme les imports/exports ES en CommonJS (via des plugins comme `@babel/plugin-transform-modules-commonjs`), le tree shaking ne fonctionnera plus. Pour le préserver, utilisez `modules: false` dans la configuration de Babel ou désactivez la transformation des modules. De plus, assurez-vous que vos cibles (browserslist) ne nécessitent pas cette transformation.
Super explication ! Une petite précision : est-ce que Rollup est meilleur que Webpack pour le tree shaking ?
Rollup est historiquement reconnu pour un tree shaking plus efficace grâce à son analyse statique poussée et son support natif des ESM. Webpack a beaucoup progressé et offre des résultats comparables, mais Rollup reste un choix privilégié pour des bundles très optimisés, notamment pour les bibliothèques.
Article très complet, bravo ! Petite question : est-ce que le tree shaking est activé par défaut dans Create React App (CRA) ?
Oui, Create React App utilise Webpack en mode production avec le tree shaking activé par défaut. Cependant, pour les dépendances, il est important qu’elles soient en ESM. CRA inclut déjà des configurations pour gérer cela, mais si vous utilisez des bibliothèques CommonJS, le tree shaking ne sera pas optimal.
J’ai essayé d’activer le tree shaking avec Webpack mais mon bundle contient toujours des fonctions inutilisées de Lodash. Pourtant j’importe uniquement `debounce`. Une idée ?
Assurez-vous d’importer depuis le chemin ESM de Lodash, par exemple `import debounce from ‘lodash-es/debounce’` au lieu de `import { debounce } from ‘lodash’`. Vérifiez aussi que votre configuration Webpack a `mode: ‘production’` et que vous n’utilisez pas `require()` pour importer Lodash.
Merci pour le guide pratique. Une remarque : il faut aussi faire attention aux effets de bord dans les modules. Par exemple, un simple `import ‘mon-module’` peut empêcher le tree shaking si le module a des effets de bord.
Exactement. Les imports sans assignation (side-effect imports) sont conservés même si leur contenu n’est pas utilisé, car le bundler ne peut pas garantir qu’ils n’ont pas d’effets de bord. Pour éviter cela, marquez les modules sans effet de bord avec `”sideEffects”: false` dans votre package.json.
Est-ce que le tree shaking fonctionne avec TypeScript ? J’utilise beaucoup de types et d’interfaces.
Oui, le tree shaking fonctionne avec TypeScript, mais les types et interfaces sont supprimés lors de la compilation vers JavaScript, donc ils n’impactent pas le bundle final. Assurez-vous que vos imports de valeurs (fonctions, classes) sont en ESM et que vous utilisez `import type` pour les types afin d’éviter des imports inutiles.
Merci pour cet article très clair. Une question : est-ce que le tree shaking fonctionne aussi avec les importations dynamiques (import()) ?
Non, le tree shaking ne fonctionne pas avec les importations dynamiques car elles sont résolues à l’exécution, ce qui empêche l’analyse statique. Pour bénéficier du tree shaking, privilégiez les imports statiques avec la syntaxe `import { … } from ‘…’`.