Dépendances optionnelles dans npm?


23

J'ai une question similaire à celle-ci , mais pas tout à fait la même.

Je voudrais que l'utilisateur de mon application l'installe avec toutes les dépendances nécessaires pour la façon dont il voudrait l'utiliser. Ainsi, par exemple, s'ils souhaitent persister sur MongoDB, seules les bibliothèques liées à Mongo seront installées, mais si elles souhaitent persister sur Redis, seules les bibliothèques liées à Redis seront installées. Je ne veux pas leur faire télécharger et installer des bibliothèques qu'ils n'utiliseront pas.

Je sais que je peux le faire à des fins de développement avec devDependencies, mais cela va plus loin que cela. Comme le dit la réponse à la question ci-dessus, cela est plus étroitement lié aux profils de Python setuptools extras_requireet de Clojure leiningen. Quelque chose comme ça dans npm? Je pense vraiment que devDependenciesdevrait être le devprofil d'une manière plus polyvalente de spécifier les dépendances.


Juste une idée, mais vous pouvez utiliser plusieurs packages. MyPackage-Core MyPackage-Db-Mongo MyPackage-Db-Redisetc ... beaucoup comme les gens font des modules bower qui sont destinés à étendre angularjs .
Mike

@Mike: Hmm merci, je vais y réfléchir. Je pense toujours que c'est une limitation package.jsonqui a été résolue dans d'autres gestionnaires de packages.
imiric

1
C'est une excellente question, mais je pense que c'est hors sujet car il s'agit d'utiliser un outil. Ces questions ne sont sur le sujet que si elles couvrent la façon dont l'outil s'intègre dans un processus de développement - après tout, ce site concerne le génie logiciel. Consultez notre centre d'aide pour plus de détails. Veuillez lire: Où va ma question sur l'outil? L'utilisation d'outils de développement tels que NPM serait sur le sujet de Stack Overflow.
amon

Réponses:


9

Le module de codépendance peut être ce que vous recherchez, ou tout ce qui fait quelque chose de similaire à:

  • déclarer des dépendances facultatives package.jsonqui ne sont pas automatiquement installées par npm install, par exempleoptionalPeerDependencies
  • une requirefonction de style personnalisé qui connaît optionalPeerDependencieset fait la bonne chose, y compris lancer / avertissement quand rien n'est trouvé qui remplit une classe requise de modules (par exemple ni redis, ni mongo, ni mysql, etc. ne sont installés).
  • documenter l'attente que les consommateurs de ce module installent au moins 1 des modules homologues en option

Une variante serait que si la fonctionnalité de base du module fonctionne sans aucune dépendance facultative (par exemple le modèle de plugin), pas d'erreur / d'avertissement lorsque rien n'est trouvé qui remplit une dépendance entre pairs.

Une autre variante consiste à faire la liste ci-dessus tout en tenant compte des dépendances de production et de développement, c'est-à-dire un analogue pour dependencieset devDependencies.

Peut-être combiné avec un besoin à la demande tel que des modules optionnels sont requis paresseusement, par exemple:

exports = {
    Core : require('./core'),
    get redis(){ return require('./redis'); },
    get mongo(){ return require('./mongo'); }
}

Je n'ai pas eu besoin de cela depuis un moment, mais je pense que cela résout le problème que j'avais. Merci!
imiric

2
Ouais, je pensais que ça faisait des mois que vous l'aviez probablement compris ou passé à autre chose. J'ai trouvé votre question en cherchant moi-même des réponses, donc c'était surtout pour la postérité. Plus d'une fois, je suis allé chercher, seulement pour trouver une réponse de moi-même écrite quelques années auparavant. Considérez donc cet intérêt personnel éclairé. En outre, mise à jour de la réponse pour décrire en général ce que le codependencymodule fournit dans le cas où le module s'évapore du NPM et parce que les liens sans extraits sont de mauvaise forme SO.
toolbear

9

Si vous voulez de simples dépendances optionnelles comme des plugins, par exemple si vous installez foo vous l'exécuterez coloré mais s'il n'est pas installé, vous n'avez aucun problème et le voyez en gris, alors vous pouvez utiliser optionalDependecies dans le package.json :

{
  "name": "watchit",
  "version": "1.2.3",
  "optionalDependencies": {
    "foo": "^2.0.0"
  }
}

Et dans le code:

try {
  var foo = require('foo')
  var fooVersion = require('foo/package.json').version
} catch (er) {
  foo = null
}
if ( notGoodFooVersion(fooVersion) ) {
  foo = null
}

// .. then later in your program ..

if (foo) {
  foo.doFooThings()
}

Extrait de la documentation package.json .


1

Ce que je fais, c'est configurer un script d'installation dans mon package.json, à l'intérieur scripts, comme ceci:

"install": "node ./my-tools/my-install.js",

Il se déroulera juste après npm install arrivées. Je l'utilise principalement pour générer automatiquement un .envfichier avec des valeurs par défaut.

Le my-install.jsscript peut exécuter différentes commandes, créer des fichiers, demander une entrée utilisateur, vous pouvez donc dire "Vous voulez Redis ou Mongo?":

const exec = require('child_process').exec;
const readline = require('readline');

// Insert "Ask question script" here
// using readline core module

if ( option == 'mongo' )
  exec('npm install mongoose');

if ( option == 'redis' )
  exec('npm install redis');

Ceci est une réponse très rapide, consultez readline pour lire correctement les entrées utilisateur et le processus enfant pour exécuter les commandes et traiter la sortie, etc.

Notez également que le script d'installation peut être celui que vous souhaitez (python, bash, etc.)


2
Demander la contribution de l'utilisateur va bousiller les versions automatisées. Une npm installnouvelle exécution à l'intérieur d'un script d'installation peut également déclencher un comportement inattendu. Je ne recommande pas cette solution.
Lambda Fairy

1

npm n'a vraiment pas été conçu pour cela, car l'une des parties les plus difficiles de la gestion des dépendances consiste à garantir des versions rapides et reproductibles, faciles et relativement sûres. Mais je crois qu'il y a un cas d'utilisation, et il y en avait certainement pour moi. J'ai donc écrit un package pour faire exactement ce que vous demandez.

Mon package est install-subsetet peut être installé globalement avecnpm install -g install-subset

https://www.npmjs.com/package/install-subset

Tout d'abord, vous créez des listes blanches et des listes noires pour les sous-ensembles d'installation nommés dans votre package.json comme ceci:

"subsets": {
    "build": {
        "whitelist": [
            "babel-cli",
            "dotenv"
        ]
    },
    "test": {
        "blacklist": [
            "eslint",
            "lint-rules",
            "prettier"
        ]
    }
}

Appelez-le ensuite avec, par exemple, install-subset test

Cela réécrira temporairement votre package.json pour ne pas installer ces packages sur liste noire, puis le restaurera, ce qui, selon les packages, peut économiser beaucoup de temps et de bande passante.

Fonctionne également avec le fil, est open source et les problèmes / relations publiques sont les bienvenus.

Dans de nombreux cas, j'utilise cela sur notre serveur ci pour réduire le temps de construction, et sur notre dernier projet React Native, notre installation de développeur typique de 72 secondes à environ 20 secondes.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.