Opcjonalne zależności w npm?

23

Mam pytanie podobne do tego , ale nie całkiem to samo.

Chciałbym, aby użytkownik mojej aplikacji zainstalował ją bez względu na zależności potrzebne do sposobu, w jaki chciałby z niej korzystać. Na przykład, jeśli chcą pozostać w MongoDB, wówczas zostaną zainstalowane tylko biblioteki związane z Mongo, ale jeśli chcą pozostać w Redis, zostaną zainstalowane tylko biblioteki związane z Redis. Nie chcę, aby pobierały i instalowały biblioteki, których nie będą używać.

Wiem, że mogę to zrobić w celach programistycznych devDependencies, ale to idzie dalej. Jak mówi odpowiedź na powyższe pytanie, jest to ściślej powiązane setuptools extras_requirez leiningenprofilami Pythona i Clojure . Coś takiego w npm? Naprawdę uważam, że devDependenciespowinienem być devprofilem bardziej uniwersalnego sposobu określania zależności.

imiryczny
źródło
To tylko myśl, ale możesz skorzystać z wielu pakietów. MyPackage-Core MyPackage-Db-Mongo MyPackage-Db-Redisitd.… w podobny sposób ludzie robią moduły altanowe, które mają na celu rozszerzenie angularjs .
Mike
@Mike: Hmm dzięki, rozważę to. Nadal uważam, że jest to ograniczenie, package.jsonktóre zostało rozwiązane w innych menedżerach pakietów.
imiric
1
To świetne pytanie, ale myślę, że jest nie na temat, ponieważ dotyczy użycia jakiegoś narzędzia. Takie pytania są na temat tylko wtedy, gdy dotyczą integracji narzędzia z jakimś procesem programowania - w końcu ta strona dotyczy inżynierii oprogramowania. Szczegółowe informacje można znaleźć w naszym centrum pomocy . Przeczytaj: Gdzie idzie moje pytanie dotyczące narzędzia? Korzystanie z narzędzi programistycznych, takich jak NPM, byłoby na temat przepełnienia stosu.
amon

Odpowiedzi:

9

Moduł współuzależnienie może być to, czego szukasz, lub cokolwiek, co robi coś podobnego do:

  • zadeklaruj opcjonalne zależności package.json, które nie zostaną automatycznie zainstalowane npm install, powiedzmyoptionalPeerDependencies
  • requirefunkcja stylu niestandardowego, która wie optionalPeerDependenciesi robi właściwe rzeczy, w tym rzucanie / ostrzeganie, gdy nie zostanie znalezione nic, co spełnia wymaganą klasę modułów (np. nie są zainstalowane ani redis, ani mongo, ani mysqlitd.).
  • udokumentuj oczekiwania, że ​​konsumenci tego modułu zainstalują co najmniej 1 opcjonalny moduł równorzędny

Jedna z odmian byłaby taka, gdyby podstawowa funkcjonalność modułu działała bez żadnych opcjonalnych zależności (np. Wzorca wtyczki), bez błędu / ostrzeżenia, gdy nie znaleziono niczego, co spełniałoby zależność równorzędną.

Inną odmianą jest wykonanie powyższej listy przy jednoczesnym uwzględnieniu zależności produkcji od rozwoju, tj. Analog dla dependenciesi devDependencies.

Być może w połączeniu z wymaganiem na żądanie , że opcjonalne moduły są wymagane leniwie, np .:

exports = {
    Core : require('./core'),
    get redis(){ return require('./redis'); },
    get mongo(){ return require('./mongo'); }
}
pasek narzędzi
źródło
Nie potrzebowałem tego przez jakiś czas, ale myślę, że to rozwiązuje problem, który miałem. Dzięki!
imiric
2
Tak, doszedłem do wniosku, że w wieku kilku miesięcy prawdopodobnie to wymyśliłeś lub przeszedłeś. Znalazłem twoje pytanie, kiedy sam szukałem odpowiedzi, więc dotyczyło to głównie potomności. Nieraz szukałem, tylko po to, by znaleźć odpowiedź od siebie napisaną kilka lat wcześniej. Zastanów się więc nad tym oświeconym interesem własnym. Zaktualizowałem również odpowiedź, aby opisać ogólnie to, co codependencymoduł zapewnia w przypadku, gdy moduł wyparuje z NPM i ponieważ linki bez fragmentów są złym formularzem SO.
toolbear
9

Jeśli chcesz prostych opcjonalnych zależności, takich jak wtyczki, np. Jeśli zainstalujesz foo, uruchomisz go kolorowo, ale jeśli nie zostanie zainstalowany, nie będziesz mieć problemu i zobaczysz go w kolorze szarym, możesz użyć opcjonalnegoDependecies w pliku package.json :

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

I w kodzie:

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

Wyodrębniono z dokumentacji package.json .

PhoneixS
źródło
1

To, co robię, to skonfigurowanie skryptu instalacyjnego w mojej paczce.json, wewnątrz scripts, w następujący sposób:

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

Będzie działać zaraz po npm installzakończeniu. Używam go głównie do automatycznego generowania .envpliku z ustawieniami domyślnymi.

my-install.jsSkrypt może uruchomić różne polecenia, tworzyć pliki, poprosić o dane wprowadzone przez użytkownika, więc nie można powiedzieć „Chcę Redis lub 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');

To jest bardzo szybka odpowiedź, sprawdź readout do poprawnego odczytu danych wejściowych użytkownika i proces potomny do uruchamiania poleceń i przetwarzania danych wyjściowych itp.

Zauważ też, że skrypt instalacyjny może być dowolny (python, bash itp.)

aesede
źródło
2
Proszenie użytkownika o podanie danych popsunie automatyczne kompilacje. Uruchomiony npm installponownie wewnątrz skryptu instalacyjnego może również wywołać niezamierzone działanie. Nie polecam tego rozwiązania.
Lambda Fairy
1

npm naprawdę nie został zaprojektowany do tego, ponieważ jedną z najtrudniejszych części zarządzania zależnościami jest zapewnienie szybkich, powtarzalnych kompilacji, które są łatwe i względnie bezpieczne. Ale wierzę, że istnieje przypadek użycia i na pewno był dla mnie. Więc napisałem pakiet, aby zrobić dokładnie to, o co prosisz.

Mój pakiet jest install-subseti można go instalować globalnienpm install -g install-subset

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

Najpierw budujesz białe i czarne listy dla nazwanych podzbiorów instalacji w pliku package.json w następujący sposób:

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

Następnie nazwij to na przykład install-subset test

Spowoduje to tymczasowe przepisanie pliku package.json, aby nie instalować tych pakietów na czarnej liście, a następnie przywrócić go, co w zależności od pakietów może zaoszczędzić dużo czasu i przepustowości.

Współpracuje również z przędzą, jest oprogramowaniem typu open source i problemy / PR są mile widziane.

W wielu przypadkach używam tego na naszym serwerze ci, aby skrócić czas kompilacji, a w naszym najnowszym projekcie React Native wziąłem typową świeżą instalację programisty z 72 sekund do około 20 sekund.

tabrindle
źródło