Dipendenze opzionali in npm?


23

Ho una domanda simile a questa , ma non è la stessa cosa.

Vorrei che l'utente della mia app lo installasse con qualsiasi dipendenza sia necessaria per il modo in cui vorrebbe usarlo. Ad esempio, se vogliono persistere su MongoDB, verranno installate solo le librerie relative a Mongo, ma se vogliono persistere su Redis, verranno installate solo le librerie relative a Redis. Non voglio farli scaricare e installare librerie che non useranno.

So che posso farlo per scopi di sviluppo devDependencies, ma questo va oltre. Come dice la risposta alla domanda sopra, questo è più strettamente correlato ai profili di Python setuptools extras_requiree Clojure leiningen. Qualcosa del genere in npm? Credo davvero che devDependenciesdovrebbe essere il devprofilo di un modo più versatile di specificare le dipendenze.


Solo un pensiero ma potresti andare con più pacchetti. MyPackage-Core MyPackage-Db-Mongo MyPackage-Db-Redisecc ... in modo molto simile a come fanno le persone a formare moduli che hanno lo scopo di estendere angularjs .
Mike,

@ Mike: Hmm grazie, lo prenderò in considerazione. Penso ancora che questa sia una limitazione package.jsonrisolta in altri gestori di pacchetti.
imiric

1
Questa è un'ottima domanda, ma penso che sia fuori tema perché si tratta di utilizzare alcuni strumenti. Tali domande sono in discussione solo se riguardano il modo in cui lo strumento si integra in alcuni processi di sviluppo - dopotutto, questo sito riguarda l'ingegneria del software. Consulta il nostro centro assistenza per i dettagli. Si prega di leggere: dove va la domanda del mio strumento? L'uso di strumenti di sviluppo come NPM sarebbe in argomento su StackTranslate.it.
amon

Risposte:


9

Il modulo di codipendenza può essere quello che stai cercando o qualcosa che fa qualcosa di simile a:

  • dichiarare dipendenze opzionali package.jsonche non sono installate automaticamente da npm install, diciamooptionalPeerDependencies
  • una requirefunzione in stile personalizzato che conosce optionalPeerDependenciese fa la cosa giusta, incluso il lancio / avvertimento quando non viene trovato nulla che soddisfi una classe richiesta di moduli (ad esempio né installato redismongoné né né mysqlinstallato).
  • documentare le aspettative che gli utenti di questo modulo installino almeno 1 dei moduli peer opzionali

Una variazione potrebbe essere se la funzionalità principale del modulo funziona senza dipendenze opzionali (ad es. Modello di plug-in), nessun errore / avviso quando non viene trovato nulla che soddisfi una dipendenza peer.

Un'altra variazione sta facendo la lista sopra mentre tiene conto della produzione rispetto alle dipendenze di sviluppo, cioè un analogo per dependenciese devDependencies.

Forse combinato con un on-demand richiede che i moduli opzionali siano richiesti pigramente, ad esempio:

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

Non ne ho avuto bisogno per un po ', ma penso che risolva il problema che avevo. Grazie!
imiric,

2
Sì, ho pensato che da mesi l'avresti probabilmente capito o passato. Ho trovato la tua domanda mentre cercavo le risposte, quindi questo era principalmente per i posteri. Più di una volta sono andato a cercare, solo per trovare una mia risposta scritta qualche anno prima. Quindi considera questo interesse personale illuminato. Inoltre, ho aggiornato la risposta per descrivere in generale cosa codependencyfornisce il modulo nel caso in cui il modulo evapori da NPM e perché i collegamenti senza estratti sono in forma SO scadente.
toolbear,

9

Se vuoi semplici dipendenze opzionali come plug-in, ad esempio se installi foo lo eseguirai colorato ma se non installato, non hai alcun problema e lo vedi in grigio, quindi puoi usare optionalDependecies nel pacchetto.json :

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

E nel codice:

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

Estratto dalla documentazione di package.json .


1

Quello che faccio è configurare uno script di installazione nel mio package.json, all'interno scripts, in questo modo:

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

Funzionerà subito dopo aver npm installterminato. Lo uso principalmente per generare automaticamente un .envfile con valori predefiniti.

Lo my-install.jsscript potrebbe eseguire diversi comandi, creare file, chiedere input all'utente, quindi puoi dire "Vuoi Redis o 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');

Questa è una risposta molto rapida, controlla readline per leggere correttamente l'input dell'utente e il processo figlio per eseguire comandi ed elaborare output, ecc.

Si noti inoltre che lo script di installazione potrebbe essere quello che si desidera (python, bash, ecc.)


2
Chiedere l'input dell'utente rovinerà le build automatizzate. L'esecuzione di npm installnuovo all'interno di uno script di installazione può anche innescare comportamenti involontari. Non consiglio questa soluzione.
Lambda Fairy,

1

npm in realtà non è stato progettato per questo, poiché una delle parti più difficili della gestione delle dipendenze è garantire build veloci e riproducibili che siano facili e relativamente sicure. Ma credo che ci sia un caso d'uso, e sicuramente lo è stato per me. Quindi ho scritto un pacchetto per fare esattamente quello che stai chiedendo.

Il mio pacchetto è install-subsete può essere installato a livello globale connpm install -g install-subset

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

Innanzitutto, crei whitelist e blacklist per sottoinsiemi di installazione con nome nel tuo package.json in questo modo:

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

Quindi chiamalo con, ad esempio, install-subset test

Questo riscriverà temporaneamente il tuo package.json per non installare quei pacchetti nella lista nera, quindi ripristinarlo, che a seconda dei pacchetti può risparmiare molto tempo e larghezza di banda.

Funziona anche con i filati, è open source e sono benvenute le emissioni / PR.

In molti casi lo uso sul nostro server ci per ridurre i tempi di costruzione e, nel nostro ultimo progetto React Native, ho impiegato la nostra tipica installazione di nuovi sviluppatori da 72 secondi a circa 20 secondi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.