DĂ©pendances JavaScript de Road to Hell

Chaque projet JavaScript commence par de bonnes intentions, Ă  savoir que ses crĂ©ateurs se promettent de ne pas utiliser trop de packages NPM lors de son dĂ©veloppement. Mais mĂȘme si les dĂ©veloppeurs font des efforts considĂ©rables pour tenir cette promesse, les packages NPM pĂ©nĂštrent progressivement leurs projets. La taille du fichier package.jsonaugmente avec le temps. Et avec l' package-lock.jsoninstallation des dĂ©pendances, une vĂ©ritable horreur se produit, exprimĂ©e en ajouts et suppressions de packages, surtout perceptible avec le prochain PR ... "Tout va bien", explique le chef d'Ă©quipe. Le reste de l'Ă©quipe acquiesce d'un signe de tĂȘte. Que faire d'autre? Nous apprĂ©cions tous le fait que l'Ă©cosystĂšme JavaScript est bel et bien vivant. Nous n'avons pas besoin de rĂ©inventer la roue Ă  chaque fois et d'essayer de rĂ©soudre les problĂšmes qui ont dĂ©jĂ  Ă©tĂ© rĂ©solus par la communautĂ© open source.





Supposons que vous allez créer un blog et que vous souhaitiez utiliser Gatsby.js. Essayez d'ajouter ce générateur de site en fonction de votre projet. Maintenant, félicitations. Votre projet venait d'avoir 19 000 dépendances supplémentaires. C'est normal? Dans quelle mesure un arbre de dépendance JavaScript peut-il devenir complexe? Comment un arbre de dépendance se transforme-t-il en enfer? Voyons cela.

Qu'est-ce qu'un package JavaScript?


NPM (Node Package Manager, Node Package Manager) stocke le plus grand registre de packages au monde. Ce sont des packages JavaScript. NPM est plus que RubyGems, PyPi et Maven rĂ©unis. Cette conclusion peut ĂȘtre tirĂ©e sur la base de l'analyse des donnĂ©es du projet Module Counts , qui surveille le nombre de packages dans les registres populaires.


Données sur le nombre de packages dans les registres populaires

Vous pourriez penser que de trĂšs grandes quantitĂ©s de code sont reprĂ©sentĂ©es sur ce graphique. C'est comme ça. Pour transformer un projet en package NPM, ce package doit avoir un fichierpackage.json. Un tel package peut ĂȘtre envoyĂ© au registre NPM.

Qu'est-ce que package.json?


Voici les tùches qu'il résout package.json:

  • Il rĂ©pertorie les packages dont dĂ©pend votre projet (il s'agit d'une liste de dĂ©pendances de projet).
  • Dans ce document, en utilisant les rĂšgles de gestion de versions sĂ©mantique, les versions des packages de dĂ©pendances que votre projet peut utiliser sont dĂ©finies.
  • Il vous permet de reproduire l'environnement nĂ©cessaire au fonctionnement du package et, par consĂ©quent, simplifie le transfert du projet Ă  d'autres dĂ©veloppeurs.

Un fichier package.jsonpeut ĂȘtre considĂ©rĂ© comme un fichier READMEpompĂ© de stĂ©roĂŻdes. Ici, vous pouvez dĂ©crire les dĂ©pendances de votre package, ici vous pouvez Ă©crire des scripts qui sont exĂ©cutĂ©s pendant l'assemblage et le test du projet. Le mĂȘme fichier contient des informations sur la version du projet spĂ©cifiĂ©e par son dĂ©veloppeur et une description du projet. Nous sommes particuliĂšrement intĂ©ressĂ©s par la possibilitĂ© package.jsonde spĂ©cifier les dĂ©pendances du projet.

Peut-ĂȘtre que le fait que les dĂ©pendances du projet soient indiquĂ©es dans ce fichier semble quelque peu alarmant. Imaginez qu'il existe un package qui dĂ©pend d'un autre package, et cet autre package dĂ©pend d'un autre package. Une telle chaĂźne de dĂ©pendances peut ĂȘtre arbitrairement longue. Pour cette raison, l'installation du seul package, Gatsby.js, signifie Ă©quiper le projet de 19 000 dĂ©pendances supplĂ©mentaires.

Types de dépendances dans package.json


Afin de mieux comprendre comment les listes de dĂ©pendances de projet augmentent au fil du temps, parlons des diffĂ©rents types de dĂ©pendances qu'un projet peut avoir. A savoir, les package.jsonsections suivantes peuvent ĂȘtre trouvĂ©es qui dĂ©crivent diverses dĂ©pendances:

  • dependencies - ce sont des dĂ©pendances ordinaires, dont la fonctionnalitĂ© est utilisĂ©e dans le projet, et qui sont accessibles Ă  partir de son code.
  • devDependencies- ce sont des dĂ©pendances de dĂ©veloppement. Par exemple, la plus jolie bibliothĂšque utilisĂ©e pour formater le code.
  • peerDependencies - si des dĂ©pendances sont Ă©crites dans cette section, le dĂ©veloppeur du package informe ainsi celui qui va l'installer qu'il aura besoin d'une version spĂ©cifique du package spĂ©cifiĂ©e dans cette section.
  • optionalDependencies - ils listent les dĂ©pendances optionnelles, telles que l'impossibilitĂ© d'installation qui ne violera pas le processus d'installation du package.
  • bundledDependencies — , . , NPM, , .

package-lock.json


Nous savons tous que le dossier package-lock.json, au cours des travaux sur le projet, subit constamment des modifications. Quelque chose en est supprimĂ©, quelque chose y est ajoutĂ©. Cela est particuliĂšrement visible lorsque vous visualisez PR contenant une version mise Ă  jour de ce fichier. Nous le tenons souvent pour acquis. Un fichier est package-lock.jsongĂ©nĂ©rĂ© automatiquement chaque fois qu'un fichier package.jsonou un dossier change node_modules. Cela vous permet de conserver le contenu de l'arborescence de dĂ©pendances exactement tel qu'il Ă©tait lorsque vous avez installĂ© les dĂ©pendances du projet. Cela permet, lors de l'installation du projet, de reproduire l'arborescence des dĂ©pendances. Cela rĂ©sout le problĂšme d'avoir diffĂ©rentes versions du mĂȘme package de diffĂ©rents dĂ©veloppeurs.

Prenons un projet dont les dépendances incluent React. L'entrée correspondante est disponible sur package.json. Si vous regardez le fichierpackage-lock.json de ce projet, vous pouvez voir quelque chose comme ceci:

    "react": {
      "version": "16.13.0",
      "resolved": "https://registry.npmjs.org/react/-/react-16.13.0.tgz",
      "integrity": "sha512-TSavZz2iSLkq5/oiE7gnFzmURKZMltmi193rm5HEoUDAXpzT9Kzw6oNZnGoai/4+fUnm7FqS5dwgUL34TujcWQ==",
      "requires": {
        "loose-envify": "^1.1.0",
        "object-assign": "^4.1.1",
        "prop-types": "^15.6.2"
      }
    }

Un fichier package-lock.jsonest une grande liste de dépendances de projet. Voici les versions de dépendance, les chemins (URI) vers les modules, les hachages utilisés pour vérifier l'intégrité du module et les packages nécessaires à ce module. Si vous lisez ce fichier, vous pouvez trouver des enregistrements de tous les packages dont React a besoin. C'est là que réside l'enfer des dépendances. Tout ce dont le projet a besoin est décrit ici.

Comprendre les dépendances de Gatsby.js


Comment se fait-il qu'ayant établi une seule dépendance, nous ajoutions jusqu'à 19 000 dépendances au projet? Tout dépend des dépendances de dépendance. C'est pourquoi nous avons ce que nous avons:

$ npm install --save gatsby

...

+ gatsby@2.19.28
added 1 package from 1 contributor, removed 9 packages, updated 10 packages and audited 19001 packages in 40.382s

Si vous regardez package.jsondedans, vous ne pouvez trouver qu'une seule dĂ©pendance. Mais si vous le regardez package-lock.json, il s'avĂšre que devant nous se trouve un monstre de presque 14 kilo-octets. Une rĂ©ponse plus dĂ©taillĂ©e sur ce que toutes les lignes de code qui tombent dans ce moyen package-lock.jsonpeut ĂȘtre trouvĂ© dans le fichier package.jsondans le rĂ©fĂ©rentiel Gatsby.js . Il y a beaucoup de dĂ©pendances directes, Ă  savoir, selon les calculs de npm , 132. Si chacune de ces dĂ©pendances a au moins une autre dĂ©pendance, alors le nombre total de dĂ©pendances du projet doublera - et il aura 264 dĂ©pendances. Bien sĂ»r, dans le monde rĂ©el, ce n'est pas le cas. Chaque dĂ©pendance de projet directe a plus d'une dĂ©pendance inhĂ©rente. Par consĂ©quent, la liste des dĂ©pendances du projet est trĂšs longue.

Par exemple, nous allons nous intĂ©resser au nombre de fois oĂč la bibliothĂšque lodash est utilisĂ©e comme dĂ©pendance pour d'autres packages :

$ npm ls lodash
example-js-package@1.0.0
└─┬ gatsby@2.19.28
  â”œâ”€â”Ź @babel/core@7.8.6
  â”‚ ├─┬ @babel/generator@7.8.6
  â”‚ │ └── lodash@4.17.15  deduped
  â”‚ ├─┬ @babel/types@7.8.6
  â”‚ │ └── lodash@4.17.15  deduped
  â”‚ └── lodash@4.17.15  deduped
  â”œâ”€â”Ź @babel/traverse@7.8.6
  â”‚ └── lodash@4.17.15  deduped
  â”œâ”€â”Ź @typescript-eslint/parser@2.22.0
  â”‚ └─┬ @typescript-eslint/typescript-estree@2.22.0
  â”‚   └── lodash@4.17.15  deduped
  â”œâ”€â”Ź babel-preset-gatsby@0.2.29
  â”‚ └─┬ @babel/preset-env@7.8.6
  â”‚   ├─┬ @babel/plugin-transform-block-scoping@7.8.3
  â”‚   │ └── lodash@4.17.15  deduped
  â”‚   ├─┬ @babel/plugin-transform-classes@7.8.6
  â”‚   │ └─┬ @babel/helper-define-map@7.8.3
  â”‚   │   └── lodash@4.17.15  deduped
  â”‚   ├─┬ @babel/plugin-transform-modules-amd@7.8.3
  â”‚   │ └─┬ @babel/helper-module-transforms@7.8.6
  â”‚   │   └── lodash@4.17.15  deduped
  â”‚   └─┬ @babel/plugin-transform-sticky-regex@7.8.3
  â”‚     └─┬ @babel/helper-regex@7.8.3
  â”‚       └── lodash@4.17.15  deduped
  ...

Heureusement, la plupart de ces dĂ©pendances sont reprĂ©sentĂ©es par la mĂȘme version de lodash. Et avec cette approche, il n'y node_modulesaura qu'un seul dossier de bibliothĂšque lodash. Certes, ce n'est gĂ©nĂ©ralement pas tout Ă  fait le cas. Parfois, diffĂ©rents packages nĂ©cessitent diffĂ©rentes versions du mĂȘme package. C'est pourquoi de nombreuses blagues sont apparues sur la taille Ă©norme du dossier node_modules. Dans notre cas, cependant, tout n'est pas si mal:

$ du -sh node_modules
200M    node_modules

200 mégaoctets n'est pas si mal. J'ai vu comment la taille de ce dossier atteint facilement 700 Mo. Si vous souhaitez savoir quels modules occupent le plus d'espace, vous pouvez exécuter la commande suivante:

$ du -sh ./node_modules/* | sort -nr | grep '\dM.*'
 17M    ./node_modules/rxjs
8.4M    ./node_modules/@types
7.4M    ./node_modules/core-js
6.8M    ./node_modules/@babel
5.4M    ./node_modules/gatsby
5.2M    ./node_modules/eslint
4.8M    ./node_modules/lodash
3.6M    ./node_modules/graphql-compose
3.6M    ./node_modules/@typescript-eslint
3.5M    ./node_modules/webpack
3.4M    ./node_modules/moment
3.3M    ./node_modules/webpack-dev-server
3.2M    ./node_modules/caniuse-lite
3.1M    ./node_modules/graphql
...

Oui, rxjs est un paquet insidieux.

Voici une commande simple qui permet de réduire la taille du dossier node_moduleset de simplifier sa structure:

$ npm dedup
moved 1 package and audited 18701 packages in 4.622s

51 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Pendant la dĂ©duplication, npm essaie de simplifier la structure de l'arborescence de dĂ©pendances en recherchant les dĂ©pendances utilisĂ©es par d'autres dĂ©pendances et en les dĂ©plaçant afin qu'elles puissent ĂȘtre partagĂ©es. Cela s'applique Ă  notre exemple lodash. De nombreux packages sont utilisĂ©s lodash @4.17.15, par consĂ©quent, pour garantir leur opĂ©rabilitĂ©, il suffit d'installer cette version de la bibliothĂšque une seule fois. Bien sĂ»r, c'est la situation dans laquelle nous nous trouvons depuis le tout dĂ©but, uniquement en Ă©tablissant des dĂ©pendances. Si dans le processus de travail sur un projet package.jsonajouter de nouvelles dĂ©pendances, il est parfois recommandĂ© de se souvenir de l'Ă©quipe npm dedup. Si vous utilisez le gestionnaire de paquets de fils, une commande similaire ressemble Ă  la dĂ©duplication de fils. Mais, en fait, cela n'est pas nĂ©cessaire, car l'optimisation des dĂ©pendances est effectuĂ©e automatiquement lorsque la commande est exĂ©cutĂ©e yarn install.

Visualisation des dépendances


Intéressé par une représentation graphique des dépendances de votre projet? Si c'est le cas, vous pouvez créer une telle présentation à l'aide d'outils spéciaux. Examinons certains d'entre eux.

Ce qui suit est un résultat de visualisation de dépendance obtenu en utilisant npm.anvaka.com/ .


Visualisation des dépendances à l'aide de npm.anvaka.com

Vous pouvez voir ici les dĂ©pendances des dĂ©pendances du package de projet Gatsby.js. Le rĂ©sultat est similaire Ă  un Ă©norme site Web. Le projet Gatsby.js a tellement de dĂ©pendances que ce «web» a presque «bloqué» mon navigateur. Maintenant , si vous ĂȘtes intĂ©ressĂ©, un lien vers ce diagramme. Il peut ĂȘtre prĂ©sentĂ© sous forme 3D.

Voici une visualisation réalisée à l'aide de npm.broofa.com .


Un fragment d'une visualisation de dépendance faite en utilisant npm.broofa.com

Ceci est similaire Ă  un organigramme. Elle, pour Gatsby.js, s'avĂšre trĂšs compliquĂ©e. Vous pouvez y jeter un Ɠil ici . ÉlĂ©mentscircuit peuvent ĂȘtre colorĂ©s selon les estimations de npms.io . Vous pouvez tĂ©lĂ©charger votre propre fichier sur le sitepackage.json.

L'outil Package Phobia vous permet de déterminer l'espace dont il a besoin avant d'installer un package.


Informations sur le package reçues à l'aide de Phobie du package

Vous pouvez découvrir ici la taille du package publié et la quantité d'espace disque nécessaire aprÚs l'installation.

Conclusion: une grande puissance s'accompagne d'une grande responsabilité


En fin de compte, je tiens à dire que JavaScript et NPM sont d'excellents outils. La bonne chose est que les développeurs modernes ont la possibilité d'utiliser un énorme ensemble de dépendances. L'exécution de la commande npm installpour vous éviter d'écrire quelques lignes de code est si facile que nous oublions parfois les conséquences.

Maintenant que vous avez lu jusqu'à présent, vous devriez avoir une compréhension plus complÚte des fonctionnalités de l'arborescence des dépendances de npm-project. Si vous ajoutez une bibliothÚque au projet qui est trÚs grande, ou si vous explorez simplement les dépendances de votre projet, vous pouvez toujours profiter de ce que nous avons discuté ici et analyser les dépendances.

Chers lecteurs! Voulez-vous utiliser le moins de dépendances possible dans vos projets npm?


All Articles