Retour à l'accueil

Ballonnement des dépendances npm : 3 causes et solutions

L'article décompose trois raisons de la croissance des dépendances npm : support d'environnement legacy, architecture atomique et ponyfills obsolètes. Décrit les problèmes de duplication, les risques de chaîne d'approvisionnement et les recommandations de nettoyage. Matériel destiné aux développeurs middle/senior.

Trois raisons du « bloat » des dépendances npm en JS
Advertisement 728x90

Pourquoi les arbres de dépendances npm gonflent : trois raisons clés

Les arbres de dépendances dans les projets JavaScript grossissent souvent à cause de paquets obsolètes et de fonctionnalités redondantes. Cela entraîne des coûts de téléchargement inutiles, des conflits de versions et des vulnérabilités dans la chaîne d'approvisionnement. Explorons trois scénarios typiques qui expliquent cette situation et comment y remédier.

Prise en charge d'environnements anciens et problèmes spécifiques aux réalms

De nombreux paquets comme is-string ou hasown existent pour assurer la compatibilité avec des environnements d'exécution anciens, tels que ES3 (IE6/7, Node.js précoce). Ils implémentent des méthodes manquantes : Array.prototype.forEach, Array.prototype.reduce, Object.keys, Object.defineProperty.

Motivations supplémentaires :

Google AdInline article slot
  • Protection de l'espace de noms global : Node importe des primordiales (par exemple, Map) pour éviter les ruptures dues aux surcharges. Des paquets comme math-intrinsics réexportent Math.* dans le même but.
  • Compatibilité entre réalms : instanceof ne fonctionne pas entre un iframe et son parent (constructeurs RegExp différents). Une alternative est Object.prototype.toString.call(val) === '[object RegExp]', utilisée dans chai ou is-string pour new String(val).
const shebangRegex = /^#!(.*)/;
export default shebangRegex;

Pour la plupart des développeurs de niveau intermédiaire à senior, c'est excessif : Node moderne (pas plus vieux que 10 ans) et les navigateurs ne nécessitent pas de tels bidouillages. Recommandation : vérifiez votre browserslist et supprimez les polyfills inutiles.

Architecture atomique : de la théorie aux problèmes

La philosophie des paquets 'atomiques' consiste à découper le code en blocs minimaux pour la réutilisation. Un exemple est le graphe de dépendances de execa avec des paquets comme shebang-regex (5 lignes de code).

Utilitaires atomiques typiques :

Google AdInline article slot
  • arrify : Array.isArray(val) ? val : [val]
  • slash : normalisation des barres obliques dans les chemins
  • cli-boxes : JSON avec bordures d'éléments d'interface
  • path-key : env['PATH'] || env['Path']
  • onetime : appel de fonction unique
  • is-wsl : process.platform === 'linux' && /microsoft/.test(os.release())
  • is-windows : process.platform === 'win32

En théorie, cela simplifie la construction d'outils en ligne de commande. En pratique :

  • Utilisation unique : shebang-regex n'est utilisé que par shebang-command (même auteur) ; cli-boxes — uniquement par boxen/ink.
  • Duplication par hoisting : Dans nuxt, des doublons comme is-docker, is-stream, is-wsl (2 versions chacune). Dupliquer le code en ligne est gratuit, sans surcharge npm.
  • Risques pour la chaîne d'approvisionnement : Plus de paquets signifie plus de vulnérabilités. Compromettre un mainteneur (comme l'an dernier) a affecté des centaines de dépendances.

Solution : intégrez les fonctions simples, utilisez le tree-shaking et pnpm avec hoisting strict.

Ponyfills qui ont survécu à leur époque

Les ponyfills sont des polyfills sans mutation des globaux, importés directement. Utiles pour les bibliothèques : @fastly/performance-observer-polyfill permet d'utiliser PerformanceObserver sans altérer l'environnement.

Google AdInline article slot

Problème : ils ne sont pas supprimés après l'arrivée du support natif.

Exemples de ponyfills obsolètes (avec téléchargements hebdomadaires) :

  • globalthis — pour globalThis (supporté depuis 2019, 49M téléchargements/semaine)
  • indexof — pour Array.prototype.indexOf (depuis 2010, 2,3M/semaine)
  • object.entries — pour Object.entries (depuis 2017, 35M/semaine)

Dans eslint-plugin-react, la moitié du graphe est constituée de polyfills hérités. Pour les bibliothèques : comptez sur les polyfills côté consommateur (core-js). Vérifiez caniuse.com avant d'ajouter.

Points clés à retenir

  • Optimisez l'héritage : 90 % des paquets n'ont pas besoin de polyfills ES3/ES5 ; utilisez typeof au lieu de is-string.
  • L'atomicité nuit : Intégrez les fonctions de 5 lignes pour réduire les doublons et la surface d'attaque.
  • Auditez les ponyfills : Supprimez les paquets pour des fonctionnalités supportées depuis plus de 5 ans dans l'environnement cible.
  • Outils : Utilisez npm ls --depth=0, depcheck, npm-check-updates pour l'analyse.
  • Initiative e18e : Concentrez-vous sur le nettoyage des dépendances obsolètes pour la performance.

Étapes pratiques de nettoyage

  • Exécutez npm dedupe et npm prune.
  • Ajoutez overrides dans package.json pour forcer le hoisting.
  • Utilisez esbuild/vite avec tree-shaking.
  • Surveillez la taille du bundle avec webpack-bundle-analyzer.

Cela peut réduire la taille du bundle de 20 à 50 % sans perte de fonctionnalité.

— Editorial Team

Advertisement 728x90

Lire ensuite