Installieren Sie Abhängigkeiten global und lokal mit package.json

189

Mit npm können wir die Module mithilfe der -gOption global installieren . Wie können wir dies in der Datei package.json tun?

Angenommen, dies sind meine Abhängigkeiten in der Datei package.json

"dependencies": {
    "mongoose": "1.4.0",
    "node.io" : "0.3.3",
    "jquery"  : "1.5.1",
    "jsdom"   : "0.2.0",
    "cron"    : "0.1.2"
  }

Wenn ich laufe npm install, möchte ich nur node.ioglobal installiert werden, der Rest andere sollten lokal installiert werden. Gibt es dafür eine Option?

Madhusudhan
quelle
11
Das kannst du nicht. Sie können jedoch "preferGlobal": truein package.json ein Modul festlegen.
Raynos
Ja, ich weiß über <code> bevorzugenGlobal </ code> Bescheid, aber das würde alle Abhängigkeiten global installieren ... trotzdem Danke! Ich denke, es gibt keine
Madhusudhan
3
Ich glaube nicht. Das aktuelle Modul wird global installiert. Wenn für eine einzelne Abhängigkeit true festgelegt ist, kann sie auch global installiert werden. Wirklich sollten Sie nur @isaacs in # node.js
Raynos
3
Globale Installationen können zur Hölle der Abhängigkeit führen. Angenommen, Paket A benötigt Version 0.3.3 und Paket B Version 0.3.4 und beide funktionieren nicht mit der anderen Version. Dann benötigen Sie zwei Maschinen, um die beiden Pakete aufzunehmen.
Nalply
6
Keiner dieser Kommentare hilft mir bei diesem Problem ... es wäre schön, wenn Sie mir mehr als nur Code zeigen "preferGlobal":true... Ich weiß nicht wirklich, wo ich das in package.json einfügen soll. npmjs.org/doc/json.html In der NPM-Dokumentation heißt es, dass prepareGlobal für Ihr eigenes Paket bestimmt ist und dass durch die Einstellung Ihr eigenes Paket als globales Paket installiert wird. es scheint jedoch eher ein Leitfaden zu sein.
PPPaul

Antworten:

216

Neuer Hinweis: Sie möchten oder müssen dies wahrscheinlich nicht tun. Was Sie wahrscheinlich tun möchten, ist, diese Arten von Befehlsabhängigkeiten für Build / Test usw. in den devDependenciesAbschnitt Ihrer package.json einzufügen. Jedes Mal, wenn Sie etwas aus scriptspackage.json verwenden, verhalten sich Ihre devDependencies-Befehle (in node_modules / .bin) so, als ob sie sich in Ihrem Pfad befinden.

Beispielsweise:

npm i --save-dev mocha # Install test runner locally
npm i --save-dev babel # Install current babel locally

Dann in package.json:

// devDependencies has mocha and babel now

"scripts": {
  "test": "mocha",
  "build": "babel -d lib src",
  "prepublish": "babel -d lib src"
}

Dann können Sie an Ihrer Eingabeaufforderung Folgendes ausführen:

npm run build # finds babel
npm test # finds mocha

npm publish # will run babel first

Aber wenn Sie wirklich global installieren möchten, können Sie eine Preinstall in der Skripte Abschnitt des package.json hinzu:

"scripts": {
  "preinstall": "npm i -g themodule"
}

Also führt meine npm-Installation die npm-Installation erneut aus. Das ist seltsam, scheint aber zu funktionieren.

Hinweis: Möglicherweise treten Probleme auf, wenn Sie das am häufigsten verwendete Setup für die npmInstallation des globalen Knotenpakets verwenden sudo. Eine Möglichkeit besteht darin, Ihre npmKonfiguration so zu ändern , dass dies nicht erforderlich ist:

npm config set prefix ~/npmFügen Sie $ PATH $ HOME / npm / bin hinzu, indem Sie export PATH=$HOME/npm/bin:$PATHan Ihren anhängen ~/.bashrc.

Jason Livesay
quelle
3
Ich konnte das nicht zum Laufen bringen npm i -g underscore-cli. Es gibt eine Warnung, dass WD falsch ist. wd bedeutet Arbeitsverzeichnis, denke ich. Wenn ich dies manuell in der Kommandozeile npm install
mache, läuft
3
PPPaul - Ich hatte das gleiche Problem, als ich diesen Trick kürzlich erneut versuchte. Vielleicht ist mein Setup jetzt anders oder es funktioniert nur mit bestimmten Modulen. Ansonsten hat sich wohl etwas mit npm geändert?
Jason Livesay
9
Darüber hinaus können Sie vorab prüfen, ob das Paket bereits installiert ist: npm list module -g || npm install module -gas npm gibt die richtigen Exit-Werte zurück.
M90
3
@CMCDragonkai: Dies sollte wirklich eine separate Frage sein. Sie fügen Ihre Befehle jedoch in ein Skript ein und geben das Skript als auszuführenden Befehl an (wie "preinstall" : "scripts/preinstall.sh").
Wir sind alle Monica
1
@CMCDragonkai concat sie &&zum Beispiel mitnpm install -g bower && npm install -g grunt-cli
Matsemann
12

Aufgrund der unten beschriebenen Nachteile würde ich empfehlen, der akzeptierten Antwort zu folgen:

Verwenden Sie npm install --save-dev [package_name]dann Skripte mit:

$ npm run lint
$ npm run build
$ npm test

Meine ursprüngliche, aber nicht empfohlene Antwort folgt.


Anstatt eine globale Installation zu verwenden, können Sie das Paket zu Ihrem devDependencies( --save-dev) hinzufügen und dann die Binärdatei von einer beliebigen Stelle in Ihrem Projekt aus ausführen:

"$(npm bin)/<executable_name>" <arguments>...

In deinem Fall:

"$(npm bin)"/node.io --help

Dieser Ingenieur hat einen npm-execAlias ​​als Verknüpfung bereitgestellt . Dieser Ingenieur verwendet ein Shellscript namens env.sh. Ich bevorzuge jedoch die $(npm bin)direkte Verwendung , um zusätzliche Dateien oder Einstellungen zu vermeiden.

Obwohl es jeden Anruf etwas größer macht, sollte es einfach funktionieren und Folgendes verhindern:

  • Mögliche Abhängigkeitskonflikte mit globalen Paketen (@nalply)
  • der Bedarf an sudo
  • die Notwendigkeit, ein npm-Präfix einzurichten (obwohl ich die Verwendung eines Präfixes trotzdem empfehle)

Nachteile:

  • $(npm bin) funktioniert nicht unter Windows.
  • Werkzeuge, die sich tiefer in Ihrem Entwicklungsbaum befinden, werden nicht im npm binOrdner angezeigt. (Installieren Sie npm-run oder npm-which , um sie zu finden.)

Es scheint eine bessere Lösung zu sein, allgemeine Aufgaben (wie das Erstellen und Minimieren) im Abschnitt "Skripte" von Ihnen zu platzieren package.json, wie Jason oben demonstriert.

joeytwiddle
quelle
Fügen Sie einen Alias ​​hinzu .bashrc, um das bin/Verzeichnis einfach zu Ihrer PATHUmgebungsvariablen hinzuzufügen : alias nodebin='export PATH=$(npm bin)/:$PATH'. Ausführen nodebinund dann können Sie einfach Ihre Befehle wie gewohnt eingeben.
Gitaarik
Ich weiß nicht, warum es für Teams nicht funktionieren würde. Natürlich müssen Sie es einrichten, und wenn Sie den Alias ​​nicht verwenden möchten, haben Sie die Wahl. Aber es kann nicht schaden, es in einem Team einzusetzen.
Gitaarik
9

Das ist ein bisschen alt, aber ich bin auf die Anforderung gestoßen. Hier ist die Lösung, die ich gefunden habe.

Das Problem:

Unser Entwicklungsteam verwaltet viele .NET-Webanwendungsprodukte, die wir auf AngularJS / Bootstrap migrieren. VS2010 eignet sich nicht einfach für benutzerdefinierte Build-Prozesse, und meine Entwickler arbeiten routinemäßig an mehreren Releases unserer Produkte. Unser VCS ist Subversion (ich weiß, ich weiß. Ich versuche, zu Git zu wechseln, aber meine lästigen Marketingmitarbeiter sind so anspruchsvoll) und eine einzige VS-Lösung wird mehrere separate Projekte enthalten. Ich brauchte meine Mitarbeiter, um eine gemeinsame Methode zum Initialisieren ihrer Entwicklungsumgebung zu haben, ohne dieselben Knotenpakete (gulp, bower usw.) mehrmals auf demselben Computer installieren zu müssen.

TL; DR:

  1. Benötigen Sie "npm install", um die globale Node / Bower-Entwicklungsumgebung sowie alle lokal erforderlichen Pakete für ein .NET-Produkt zu installieren.

  2. Globale Pakete sollten nur installiert werden, wenn sie noch nicht installiert sind.

  3. Lokale Links zu globalen Paketen müssen automatisch erstellt werden.

Die Lösung:

Wir haben bereits ein gemeinsames Entwicklungsframework, das von allen Entwicklern und allen Produkten gemeinsam genutzt wird. Daher habe ich ein NodeJS-Skript erstellt, um die globalen Pakete bei Bedarf zu installieren und die lokalen Links zu erstellen. Das Skript befindet sich in ".... \ SharedFiles" relativ zum Produktbasisordner:

/*******************************************************************************
* $Id: npm-setup.js 12785 2016-01-29 16:34:49Z sthames $
* ==============================================================================
* Parameters: 'links' - Create links in local environment, optional.
* 
* <p>NodeJS script to install common development environment packages in global
* environment. <c>packages</c> object contains list of packages to install.</p>
* 
* <p>Including 'links' creates links in local environment to global packages.</p>
* 
* <p><b>npm ls -g --json</b> command is run to provide the current list of 
* global packages for comparison to required packages. Packages are installed 
* only if not installed. If the package is installed but is not the required 
* package version, the existing package is removed and the required package is 
* installed.</p>.
*
* <p>When provided as a "preinstall" script in a "package.json" file, the "npm
* install" command calls this to verify global dependencies are installed.</p>
*******************************************************************************/
var exec = require('child_process').exec;
var fs   = require('fs');
var path = require('path');

/*---------------------------------------------------------------*/
/* List of packages to install and 'from' value to pass to 'npm  */
/* install'. Value must match the 'from' field in 'npm ls -json' */
/* so this script will recognize a package is already installed. */
/*---------------------------------------------------------------*/
var packages = 
  {
  "bower"                      :                      "[email protected]", 
  "event-stream"               :               "[email protected]",
  "gulp"                       :                       "[email protected]",
  "gulp-angular-templatecache" : "[email protected]",
  "gulp-clean"                 :                 "[email protected]", 
  "gulp-concat"                :                "[email protected]",
  "gulp-debug"                 :                 "[email protected]",
  "gulp-filter"                :                "[email protected]",
  "gulp-grep-contents"         :         "[email protected]",
  "gulp-if"                    :                    "[email protected]", 
  "gulp-inject"                :                "[email protected]", 
  "gulp-minify-css"            :            "[email protected]",
  "gulp-minify-html"           :           "[email protected]",
  "gulp-minify-inline"         :         "[email protected]",
  "gulp-ng-annotate"           :           "[email protected]",
  "gulp-processhtml"           :           "[email protected]",
  "gulp-rev"                   :                   "[email protected]",
  "gulp-rev-replace"           :           "[email protected]",
  "gulp-uglify"                :                "[email protected]",
  "gulp-useref"                :                "[email protected]",
  "gulp-util"                  :                  "[email protected]",
  "lazypipe"                   :                   "[email protected]",
  "q"                          :                          "[email protected]",
  "through2"                   :                   "[email protected]",

  /*---------------------------------------------------------------*/
  /* fork of 0.2.14 allows passing parameters to main-bower-files. */
  /*---------------------------------------------------------------*/
  "bower-main"                 : "git+https://github.com/Pyo25/bower-main.git" 
  }

/*******************************************************************************
* run */
/**
* Executes <c>cmd</c> in the shell and calls <c>cb</c> on success. Error aborts.
* 
* Note: Error code -4082 is EBUSY error which is sometimes thrown by npm for 
* reasons unknown. Possibly this is due to antivirus program scanning the file 
* but it sometimes happens in cases where an antivirus program does not explain 
* it. The error generally will not happen a second time so this method will call 
* itself to try the command again if the EBUSY error occurs.
* 
* @param  cmd  Command to execute.
* @param  cb   Method to call on success. Text returned from stdout is input.
*******************************************************************************/
var run = function(cmd, cb)
  {
  /*---------------------------------------------*/
  /* Increase the maxBuffer to 10MB for commands */
  /* with a lot of output. This is not necessary */
  /* with spawn but it has other issues.         */
  /*---------------------------------------------*/
  exec(cmd, { maxBuffer: 1000*1024 }, function(err, stdout)
    {
    if      (!err)                   cb(stdout);
    else if (err.code | 0 == -4082) run(cmd, cb);
    else throw err;
    });
  };

/*******************************************************************************
* runCommand */
/**
* Logs the command and calls <c>run</c>.
*******************************************************************************/
var runCommand = function(cmd, cb)
  {
  console.log(cmd);
  run(cmd, cb);
  }

/*******************************************************************************
* Main line
*******************************************************************************/
var doLinks  = (process.argv[2] || "").toLowerCase() == 'links';
var names    = Object.keys(packages);
var name;
var installed;
var links;

/*------------------------------------------*/
/* Get the list of installed packages for   */
/* version comparison and install packages. */
/*------------------------------------------*/
console.log('Configuring global Node environment...')
run('npm ls -g --json', function(stdout)
  {
  installed = JSON.parse(stdout).dependencies || {};
  doWhile();
  });

/*--------------------------------------------*/
/* Start of asynchronous package installation */
/* loop. Do until all packages installed.     */
/*--------------------------------------------*/
var doWhile = function()
  {
  if (name = names.shift())
    doWhile0();
  }

var doWhile0 = function()
  {
  /*----------------------------------------------*/
  /* Installed package specification comes from   */
  /* 'from' field of installed packages. Required */
  /* specification comes from the packages list.  */
  /*----------------------------------------------*/
  var current  = (installed[name] || {}).from;
  var required =   packages[name];

  /*---------------------------------------*/
  /* Install the package if not installed. */
  /*---------------------------------------*/
  if (!current)
    runCommand('npm install -g '+required, doWhile1);

  /*------------------------------------*/
  /* If the installed version does not  */
  /* match, uninstall and then install. */
  /*------------------------------------*/
  else if (current != required)
    {
    delete installed[name];
    runCommand('npm remove -g '+name, function() 
      {
      runCommand('npm remove '+name, doWhile0);
      });
    }

  /*------------------------------------*/
  /* Skip package if already installed. */
  /*------------------------------------*/
  else
    doWhile1();
  };

var doWhile1 = function()
  {
  /*-------------------------------------------------------*/
  /* Create link to global package from local environment. */
  /*-------------------------------------------------------*/
  if (doLinks && !fs.existsSync(path.join('node_modules', name)))
    runCommand('npm link '+name, doWhile);
  else
    doWhile();
  };

Wenn ich nun ein globales Tool für unsere Entwickler aktualisieren möchte, aktualisiere ich das Objekt "packages" und checke das neue Skript ein. Meine Entwickler checken es aus und führen es entweder mit "node npm-setup.js" oder mit "npm install" von einem der in der Entwicklung befindlichen Produkte aus, um die globale Umgebung zu aktualisieren. Das Ganze dauert 5 Minuten.

Um die Umgebung für einen neuen Entwickler zu konfigurieren, müssen diese zunächst nur NodeJS und GIT für Windows installieren, ihren Computer neu starten, den Ordner "Freigegebene Dateien" und alle in der Entwicklung befindlichen Produkte überprüfen und mit der Arbeit beginnen.

Die Datei "package.json" für das .NET-Produkt ruft dieses Skript vor der Installation auf:

{ 
"name"                    : "Books",
"description"             : "Node (npm) configuration for Books Database Web Application Tools",
"version"                 : "2.1.1",
"private"                 : true,
"scripts":
  {
  "preinstall"            : "node ../../SharedFiles/npm-setup.js links",
  "postinstall"           : "bower install"
  },
"dependencies": {}
}

Anmerkungen

  • Beachten Sie, dass die Skriptreferenz auch in einer Windows-Umgebung Schrägstriche erfordert.

  • "npm ls" gibt "npm ERR! extraneous:" Nachrichten für alle lokal verknüpften Pakete aus, da sie nicht in den "package.json" "Abhängigkeiten" aufgeführt sind.

Bearbeiten 29.01.16

Das oben aktualisierte npm-setup.jsSkript wurde wie folgt geändert:

  • Paket "Version" in var packagesist jetzt der Wert für "Paket", der npm installin der Befehlszeile übergeben wird. Dies wurde geändert, um die Installation von Paketen von einem anderen Ort als dem registrierten Repository zu ermöglichen.

  • Wenn das Paket bereits installiert ist, aber nicht angefordert wird, wird das vorhandene Paket entfernt und das richtige installiert.

  • Aus unbekannten Gründen gibt npm bei der Installation oder Verknüpfung regelmäßig einen EBUSY-Fehler (-4082) aus. Dieser Fehler wird abgefangen und der Befehl erneut ausgeführt. Der Fehler tritt selten ein zweites Mal auf und scheint sich immer zu klären.

sthames42
quelle
Dies ist ein Lebensretter @ sthames42! Ich habe stundenlang versucht, genau herauszufinden, wie das geht. Klar, umfassend, im Allgemeinen fantastisch. #Punkte Fragen: (a) Warum befindet sich Bower in der Nachinstallation, wenn es bereits in der Paketliste enthalten ist? (b) Wie kann man die globalen Pakete NICHT lokal verknüpfen? Nur keine "Links" in den Befehl aufnehmen?
MaxRocket
@ MaxRocket: Ich bin froh, dass ich helfen konnte. Ich habe die Antwort so aktualisiert, dass sie meine neueste enthält, die viel besser funktioniert. Antworten: (a) Der Befehl 'bower install' wird ausgeführt, nachdem 'npm install' ausgeführt wurde, um die Bower-Komponenten zu installieren, die in der hier nicht gezeigten Datei bower.json aufgeführt sind. Ich wollte, dass meine Mitarbeiter in der Lage sind, 'npm install' einzugeben und ihre Umgebung vollständig eingerichtet zu haben, ohne einen anderen Befehl eingeben zu müssen. (b) Ja.
sthames42
Die aktuelle Version dieses Skripts wird jetzt hier gepflegt .
sthames42
6

Sie können npm_globals.txtstattdessen eine separate Datei verwenden package.json. Diese Datei würde jedes Modul in einer neuen Zeile wie dieser enthalten:

mongoose@1.4.0
node.io@0.3.3
jquery@1.5.1
jsdom@0.2.0
cron@0.1.2

Dann in der Kommandozeile ausführen,

< npm_globals.txt xargs npm install -g

Überprüfen Sie, ob sie ordnungsgemäß installiert wurden mit,

npm list -g --depth=0

Ob Sie dies tun sollten oder nicht, hängt meiner Meinung nach vom Anwendungsfall ab. Für die meisten Projekte ist dies nicht erforderlich. Es package.jsonwird sehr bevorzugt, wenn Ihre Projekte diese Tools und Abhängigkeiten zusammenfassen.

Aber heutzutage stelle ich fest, dass ich immer create-react-appandere CLIs global installiere, wenn ich auf einen neuen Computer springe. Es ist schön, eine einfache Möglichkeit zu haben, ein globales Tool und seine Abhängigkeiten zu installieren, wenn die Versionierung keine große Rolle spielt.

Und heute, ich verwende npx, ein npm Paket Läufer , statt Pakete global installieren.

Atav32
quelle
3

Alle Module aus package.json werden unter ./node_modules/ installiert.

Ich konnte dies nicht explizit angeben, aber dies ist die package.json-Referenz für NPM .

Knabberbot
quelle
1

Erstellen Sie Ihr eigenes Skript, um globale Abhängigkeiten zu installieren. Es braucht nicht viel. package.json ist ziemlich erweiterbar.

const {execSync} = require('child_process');

JSON.parse(fs.readFileSync('package.json'))
     .globalDependencies.foreach(
         globaldep => execSync('npm i -g ' + globaldep)
     );

Mit dem oben genannten können Sie es sogar unten inline machen!

Schauen Sie sich die Vorinstallation unten an:

{
  "name": "Project Name",
  "version": "0.1.0",
  "description": "Project Description",
  "main": "app.js",
  "scripts": {
    "preinstall": "node -e \"const {execSync} = require('child_process'); JSON.parse(fs.readFileSync('package.json')).globalDependencies.foreach(globaldep => execSync('npm i -g ' + globaldep));\"",
    "build": "your transpile/compile script",
    "start": "node app.js",
    "test": "./node_modules/.bin/mocha --reporter spec",
    "patch-release": "npm version patch && npm publish && git add . && git commit -m \"auto-commit\" && git push --follow-tags"
  },
  "dependencies": [
  },
  "globalDependencies": [
    "[email protected]",
    "ionic",
    "potato"
  ],
  "author": "author",
  "license": "MIT",
  "devDependencies": {
    "chai": "^4.2.0",
    "mocha": "^5.2.0"
  },
  "bin": {
    "app": "app.js"
  }
}

Die Autoren von node geben möglicherweise nicht zu, dass package.json eine Projektdatei ist. Aber es ist.

TamusJRoyce
quelle