Quelle est la différence entre les dépendances, devDependencies et peerDependencies dans le fichier npm package.json ?

[Cette documentation][1] répond très mal à ma question. Je n&#8217ai pas compris ces explications. Quelqu'un peut-il me répondre avec des mots plus simples ? Peut-être avec des exemples si c&#8217est difficile de choisir des mots simples ?

EDIT J'ai également ajouté peerDependencies, qui est étroitement lié et peut prêter à confusion.

[1] : https://docs.npmjs.com/files/package.json

Solution

Résumé des différences de comportement importantes :

  • Les [dépendances][1] sont installées sur les deux :
    • npm install depuis un répertoire qui contient package.json
    • npm install $package dans tout autre répertoire.
  • Les [devDependencies][2] sont :
    • également installés par npm install sur un répertoire contenant package.json, sauf si vous passez le drapeau --production (allez upvotez la réponse de Gayan Charith).
    • ne sont pas installés par npm install "$package" sur un autre répertoire, sauf si vous lui donnez l'option --dev.
    • ne sont pas installés de manière transitive.
  • [peerDependencies][4] :
    • avant 3.0 : sont toujours installées si elles sont manquantes, et lèvent une erreur si plusieurs versions incompatibles de la dépendance seraient utilisées par différentes dépendances.
    • prévue à partir de la 3.0 (non testée) : donne un avertissement si elle est manquante sur npm install, et vous devez résoudre la dépendance vous-même manuellement. Lors de l'exécution, si la dépendance est manquante, vous obtenez une erreur (mentionné par [@nextgentech][6]).
  • Transitivité (mentionné par [Ben Hutchison][7]) :
    • Les dependencies sont installées de manière transitive : si A nécessite B, et que B nécessite C, alors C est installé, sinon, B ne pourrait pas fonctionner, et A non plus.
    • devDependencies n'est pas installé de manière transitive. Par exemple, nous n'avons pas besoin de tester B pour tester A, donc les dépendances de test de B peuvent être laissées de côté. Options connexes non discutées ici :
  • bundledDependencies qui est discuté à la question suivante : https://stackoverflow.com/questions/11207638/advantages-of-bundleddependencies-over-normal-dependencies-in-npm?lq=1
  • optionalDependencies][8] (mentionné [par Aidan Feldman][9])

    devDependencies

    Les dependencies sont nécessaires à l'exécution, les devDependencies uniquement au développement, par exemple : tests unitaires, transpilation CoffeeScript vers JavaScript, minification, ... Si vous allez développer un paquet, vous le téléchargez (par exemple via git clone), allez à sa racine qui contient package.json, et exécutez :

npm install

Puisque vous avez la source réelle, il est clair que vous voulez la développer, donc par défaut, les deux dépendances dependencies (puisque vous devez, bien sûr, exécuter pour développer) et devDependency sont également installées. Si toutefois, vous n'êtes qu'un utilisateur final qui veut juste installer un paquetage pour l'utiliser, vous le ferez depuis n'importe quel répertoire :

npm install "$package"

Dans ce cas, vous ne voulez normalement pas les dépendances de développement, donc vous obtenez juste ce qui est nécessaire pour utiliser le paquet : dependencies. Si vous voulez vraiment installer les paquets de développement dans ce cas, vous pouvez mettre l'option de configuration dev à true, éventuellement à partir de la ligne de commande comme :

npm install "$package" --dev

L'option est false par défaut car c'est un cas beaucoup moins fréquent.

peerDependencies

(Testé avant 3.0) Source : https://nodejs.org/en/blog/npm/peer-dependencies/ Avec les dépendances normales, vous pouvez avoir plusieurs versions de la dépendance : elles sont simplement installées dans les node_modules de la dépendance. Par exemple, si dependency1 et dependency2 dépendent tous les deux de dependency3 à des versions différentes, l'arbre du projet ressemblera à ça :

root/node_modules/
                 |
                 +- dependency1/node_modules/
                 |                          |
                 |                          +- dependency3 v1.0/
                 |
                 |
                 +- dependency2/node_modules/
                                            |
                                            +- dependency3 v2.0/

Les plugins, cependant, sont des paquets qui normalement ne nécessitent pas l'autre paquet, qui est appelé le host dans ce contexte. Au contraire :

  • les plugins sont requis par l'hôte
  • les plugins offrent une interface standard que l'hôte s'attend à trouver
  • seul l'hôte sera appelé directement par l'utilisateur, donc il doit y avoir une seule version de celui-ci. Par exemple, si dependency1 et dependency2 dépendent de dependency3, l'arbre du projet ressemblera à :
root/node_modules/
                 |
                 +- dependency1/
                 |
                 +- dependency2/
                 |
                 +- dependency3 v1.0/

Cela se produit même si vous ne mentionnez jamais dependency3 dans votre fichier package.json. Je pense qu'il s'agit d'une instance du modèle de conception [Inversion of Control][10]. Un exemple prototypique de dépendances entre pairs est Grunt, l'hôte, et ses plugins. Par exemple, sur un plugin Grunt comme https://github.com/gruntjs/grunt-contrib-uglify, vous verrez que :

  • grunt est une peer-dependency (dépendance entre pairs)
  • le seul require('grunt') est sous tests/ : il n'est pas réellement utilisé par le programme. Ensuite, lorsque l'utilisateur utilisera un plugin, il requerra implicitement le plugin depuis le Gruntfile en ajoutant une ligne grunt.loadNpmTasks('grunt-contrib-uglify'), mais c'est grunt que l'utilisateur appellera directement. Cela ne fonctionnerait pas alors si chaque plugin nécessitait une version différente de Grunt.

    Manuel

    Je pense que la documentation répond assez bien à la question, peut-être que vous n'êtes pas assez familier avec node / autres gestionnaires de paquets. Je ne le comprends probablement que parce que je connais un peu Ruby bundler. La ligne clé est :

    Ces éléments seront installés lors de l'exécution de npm link ou npm install à partir de la racine d'un paquet et peuvent être gérés comme tout autre paramètre de configuration de npm. Voir npm-config(7) pour plus d'informations sur le sujet. Et ensuite sous npm-config(7) trouvez dev :

Default: false
Type: Boolean

Install dev-dependencies along with packages.

[1] : https://github.com/npm/npm/blob/2e3776bf5676bc24fec6239a3420f377fe98acde/doc/files/package.json.md#dependencies [2] : https://github.com/npm/npm/blob/2e3776bf5676bc24fec6239a3420f377fe98acde/doc/files/package.json.md#devdependencies

[4] : https://github.com/npm/npm/blob/2e3776bf5676bc24fec6239a3420f377fe98acde/doc/files/package.json.md#peerdependencies

[6] : https://stackoverflow.com/users/1997767/nextgentech [7] : https://stackoverflow.com/questions/18875674/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies/22004559#comment57650997_22004559 [8] : https://docs.npmjs.com/files/package.json#optionaldependencies [9] : https://stackoverflow.com/questions/18875674/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies/22004559#comment62749434_18875674 [10] : http://en.wikipedia.org/wiki/Inversion_of_control

Commentaires (22)

Par exemple, mocha serait normalement une devDependency, puisque les tests ne sont pas nécessaires en production, alors qu'express serait une dependency.

Commentaires (6)

Il existe des modules et des paquets nécessaires uniquement pour le développement, qui ne sont pas nécessaires en production. Comme il est dit dans la [documentation][1] :

Si quelqu'un prévoit de télécharger et d'utiliser votre module dans son programme, alors il ne veut ou ne doit probablement pas télécharger et construire le test externe ou le cadre de documentation que vous utilisez. Dans ce cas, il est préférable de lister ces éléments supplémentaires dans un hash devDependencies.

[1] : https://npmjs.org/doc/json.html#devDependencies

Commentaires (2)