Optionale Abhängigkeiten in npm?


23

Ich habe eine ähnliche Frage zu diesem , aber nicht ganz dasselbe.

Ich möchte, dass der Benutzer meiner App sie mit den Abhängigkeiten installiert, die für die Art und Weise erforderlich sind, wie er sie verwenden möchte. Wenn sie beispielsweise in MongoDB bleiben möchten, werden nur Bibliotheken mit Bezug zu Mongo installiert. Wenn sie jedoch in Redis bleiben möchten, werden nur Bibliotheken mit Bezug zu Redis installiert. Ich möchte nicht, dass sie Bibliotheken herunterladen und installieren, die sie nicht verwenden.

Ich weiß, dass ich das für Entwicklungszwecke mit machen kann devDependencies, aber das geht noch weiter. Wie die Antwort in der obigen Frage besagt, hängt dies enger mit setuptools extras_requireden leiningenProfilen von Python und Clojure zusammen . Sowas in npm? Ich bin wirklich der Meinung, devDependenciesdass es ein devProfil für eine vielseitigere Art der Spezifizierung von Abhängigkeiten sein sollte.


Nur ein Gedanke, aber Sie könnten mit mehreren Paketen gehen. MyPackage-Core MyPackage-Db-Mongo MyPackage-Db-Redisusw ... so wie die Leute Laubenmodule bauen , die dazu gedacht sind , eckige Module zu erweitern .
Mike

@ Mike: Hmm danke, ich werde es in Betracht ziehen. Ich denke immer noch, dass dies eine Einschränkung package.jsonist, die in anderen Paketmanagern behoben wurde.
Imiric

1
Dies ist eine großartige Frage, aber ich denke, dass sie nicht zum Thema gehört, da es um die Verwendung eines Tools geht. Solche Fragen sind nur zum Thema , wenn sie , wie das Werkzeug integriert in eine Entwicklung abdecken Prozess - schließlich, diese Seite über Software Engineering ist. Weitere Informationen finden Sie in unserer Hilfe . Bitte lesen Sie: Wohin geht meine Werkzeugfrage? Die Verwendung von Entwicklungstools wie z. B. NPM ist ein Thema für den Stapelüberlauf.
Amon

Antworten:


9

Das Codependenzmodul ist möglicherweise das, wonach Sie suchen, oder alles, was etwas Ähnliches bewirkt wie:

  • deklarieren optionale Abhängigkeiten , package.jsondie nicht werden , indem es automatisch installiert npm install, sagen wiroptionalPeerDependencies
  • eine benutzerdefinierte requireFunktion, optionalPeerDependenciesdie das Richtige kennt und tut, einschließlich Werfen / Warnen, wenn nichts gefunden wird, das eine erforderliche Klasse von Modulen erfüllt (z. B. sind weder redisnoch mongonoch mysqlusw. installiert).
  • Dokumentieren Sie die Erwartung, dass Kunden dieses Moduls mindestens 1 der optionalen Peer-Module installieren

Eine Variation wäre, wenn die Kernfunktionalität des Moduls ohne optionale Abhängigkeiten (z. B. Plugin-Muster) funktioniert, kein Fehler / Warnung, wenn nichts gefunden wird, das eine Peer-Abhängigkeit erfüllt.

Eine andere Variante ist die oben aufgeführte Liste, bei der die Produktions- und Entwicklungsabhängigkeiten berücksichtigt werden, dh eine analoge für dependenciesund devDependencies.

Möglicherweise kombiniert mit einer On-Demand-Anforderung, sodass optionale Module träge benötigt werden, z. B .:

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

Ich habe das eine Weile nicht gebraucht, aber ich denke, es löst das Problem, das ich hatte. Vielen Dank!
Imiric

2
Ja, ich dachte, es wäre Monate alt, du hättest es wahrscheinlich herausgefunden oder bist weitergezogen. Ich habe Ihre Frage gefunden, als ich selbst nach Antworten gesucht habe. Das war also hauptsächlich für die Nachwelt. Mehr als einmal bin ich auf die Suche gegangen, nur um eine Antwort von mir zu finden, die ein paar Jahre zuvor geschrieben wurde. Betrachten Sie also dieses aufgeklärte Eigeninteresse. Außerdem wurde die Antwort aktualisiert, um allgemein zu beschreiben, was das codependencyModul für den Fall bietet, dass das Modul aus dem NPM verdampft und Links ohne Auszüge eine schlechte SO-Form haben.
Toolbear

9

Wenn Sie einfache optionale Abhängigkeiten wie Plugins möchten, z. B. wenn Sie foo installieren, werden Sie es bunt ausführen, aber wenn es nicht installiert ist, haben Sie kein Problem und sehen es grau, dann können Sie optionalDependecies in der package.json verwenden :

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

Und im 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()
}

Aus der package.json-Dokumentation extrahiert .


1

Ich konfiguriere ein Installationsskript in meinem package.json scriptswie folgt :

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

Es wird direkt nach dem npm installEnde ausgeführt. Ich benutze es hauptsächlich zum automatischen Generieren einer .envDatei mit Standardeinstellungen.

Das my-install.jsSkript kann verschiedene Befehle ausführen, Dateien erstellen und nach Benutzereingaben fragen, sodass Sie "Want Redis or Mongo?" Sagen können:

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');

Dies ist eine sehr schnelle Antwort. Lesen Sie die Readline, um Benutzereingaben richtig zu lesen, und den Child-Prozess, um Befehle auszuführen und Ausgaben zu verarbeiten usw.

Beachten Sie auch, dass das Installationsskript beliebig sein kann (Python, Bash usw.).


2
Wenn Sie nach Benutzereingaben fragen, werden automatisierte Builds durcheinander gebracht. Das npm installerneute Ausführen innerhalb eines Installationsskripts kann ebenfalls ein unbeabsichtigtes Verhalten auslösen. Ich empfehle diese Lösung nicht.
Lambda Fairy

1

npm war wirklich nicht dafür ausgelegt, da einer der schwierigsten Teile des Abhängigkeitsmanagements darin besteht, schnelle, reproduzierbare Builds zu gewährleisten, die einfach und relativ ausfallsicher sind. Aber ich glaube, es gibt einen Anwendungsfall, und der war mit Sicherheit für mich. Also habe ich ein Paket geschrieben, um genau das zu tun, wonach du fragst.

Mein Paket ist install-subsetund kann global mit installiert werdennpm install -g install-subset

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

Zunächst erstellen Sie Whitelists und Blacklists für benannte Installations-Subsets in Ihrer package.json wie folgt:

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

Rufen Sie es dann zum Beispiel mit install-subset test

Dadurch wird die Datei package.json vorübergehend neu geschrieben, sodass diese Pakete nicht auf der schwarzen Liste installiert und anschließend wiederhergestellt werden. Dies kann je nach Paket viel Zeit und Bandbreite sparen.

Arbeitet auch mit Garn, ist Open Source und Fragen / PRs sind willkommen.

In vielen Fällen verwende ich dies auf unserem ci-Server, um die Erstellungszeit zu verkürzen, und bei unserem neuesten React Native-Projekt dauerte die typische Installation neuer Entwickler von 72 Sekunden auf etwa 20 Sekunden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.