NodeJS erfordert ein globales Modul / Paket

158

Ich versuche, global zu installieren und dann zu verwenden foreverund forever-monitorwie folgt:

npm install -g forever forever-monitor

Ich sehe die übliche Ausgabe und auch die Operationen, die die Dateien in den globalen Pfad kopieren, aber wenn ich es versuche, require("forever");erhalte ich eine Fehlermeldung, dass das Modul nicht gefunden wurde.

Ich verwende die neueste Version von Node und Npm und weiß bereits, welche Änderungen Npm bei der globalen oder lokalen Installation vorgenommen hat, aber ich möchte wirklich nicht bei jedem Projekt Localy installieren und arbeite auf einer Plattform, die dies nicht tut Ich unterstütze das nicht link, npm linknachdem eine globale Installation für mich nicht möglich ist.

Meine Frage ist: Warum kann ich kein global installiertes Paket benötigen? Ist das eine Funktion oder ein Fehler? Oder mache ich etwas falsch?

PS: Nur um es kristallklar zu machen: Ich möchte nicht lokal installieren.

alexandernst
quelle
so ist es ~/.config/yarn/globalfür Garn
localhostdotdev

Antworten:

215

In Node.js sucht require nicht in dem Ordner, in dem globale Module installiert sind.

Sie können dies beheben, indem Sie die Umgebungsvariable NODE_PATH festlegen. Unter Linux ist dies:

export NODE_PATH=/usr/lib/node_modules

Hinweis: Dies hängt davon ab, wo Ihre globalen Module tatsächlich installiert sind.

Siehe: Laden aus den globalen Ordnern .

Daniel Uzunu
quelle
24
Auf meinem Ubuntu 13.10-Computer unterscheidet sich der globale Pfad für Module von dem hier gezeigten. Ich musste export NODE_PATH=/usr/local/lib/node_modulesstattdessen verwenden.
Drew Noakes
11
Wenn Sie unter Windows 7/8 arbeiten und keine der Installationsstandards von Node überschrieben haben, funktioniert das Festlegen der NODE_PATHUmgebungsvariablen C:\Users\{USERNAME}\AppData\Roaming\npm\node_moduleswahrscheinlich.
Wes Johnson
5
@WesJohnson Just %AppData%\npm\node_moduleswird unter Windows 10
funktionieren
6
Wenn ich einstelle, NODE_PATHkann ich globale und lokale Module gleichzeitig verwenden?
Paulo Oliveira
6
Alternativ anstelle eines statischen Pfads, dh wenn Sie NVM verwenden:NODE_PATH=$(npm root -g)
holmberd
96

Nachdem Sie das Paket global installiert haben, müssen Sie das lokale Projekt mit dem globalen Paket verknüpfen

npm install express -g
cd ~/mynodeproject/
npm link express  

Siehe hier

user568109
quelle
2
Ich verwende eine Plattform, die keinen Link unterstützt (wie in meiner Frage angegeben). Blog.nodejs.org/2011/04/06/npm-1-0-link
alexandernst
1
Welche Plattform benutzt du?
user568109
1
Ich möchte mich wirklich nicht mit Links (oder überhaupt symbolischen Links) anlegen. Ich möchte nur Pakete global installieren und benötige sie. Ich weiß, dass NPM neu gestaltet wurde, um dies zu vermeiden, aber wie schwer könnte es sein, so etwas zu erreichen?
Alexander am
13
Was ist, wenn ich kein Projekt habe? Sagen Sie ~/some-stand-alone-random-nodejs-test.js. Ich möchte meinen Home-Ordner nicht in ein Projektverzeichnis verwandeln. Ich möchte nicht für jedes kleine Experiment neue Ordner erstellen.
AnnanFay
1
Funktionierte perfekt unter Windows 8.1. Von der Befehlszeilen- CD des Knotens zum lokalen Ordner node_modules meiner Projekte, der dann ausgeführt wird. npm link <module>Anschließend wird eine Verknüpfung (Link) im Ordner node_module Ihres Projekts erstellt, die auf das globale Knotenmodul verweist.
Dynamiclynk
26

Entschuldigung für die Nekromantie, aber ich kann fest codierte Pfade zu global installierten Modulen angeben:

var pg = require("/usr/local/lib/node_modules/pg");

Dies ist nicht perfekt, aber wenn man bedenkt, dass Unity3d versucht, alles im Projektverzeichnis enthaltene Javascript zu "kompilieren", kann ich wirklich keine Pakete installieren.

Thomas Ingham
quelle
4
Unity3D unterstützt kein JavaScript. Es unterstützt eine JS-ähnliche Syntax für seinen Boo-Interpreter / Compiler (Boo ist eine Python-ähnliche Sprache für .NET) , die täuschend als „JavaScript“ vermarktet wird . Der genauere Name für die von Unity unterstützte Sprache ist UnityScript . Da es nicht einmal in der Nähe derselben Sprache liegt, funktioniert in Unity so gut wie kein JS, das für das Web oder für Node.js geschrieben wurde. Viele weitere Informationen zu den Unterschieden im offiziellen Unity-Wiki: wiki.unity3d.com/index.php/UnityScript_versus_JavaScript
Slipp D. Thompson
19

Ich weiß, dass dies eine alte Frage ist, aber ich bin darauf gestoßen, als ich versucht habe, eine Versionsprüfung mit semvereinem preinstallSkript in durchzuführen package.json. Da ich wusste, dass ich mich nicht auf installierte lokale Module verlassen kann, habe ich dies verwendet, um es semveraus dem globalen node_modulesOrdner zu fordern ( npmje nachdem, weiß ich, dass es dort ist):

function requireGlobal(packageName) {
  var childProcess = require('child_process');
  var path = require('path');
  var fs = require('fs');

  var globalNodeModules = childProcess.execSync('npm root -g').toString().trim();
  var packageDir = path.join(globalNodeModules, packageName);
  if (!fs.existsSync(packageDir))
    packageDir = path.join(globalNodeModules, 'npm/node_modules', packageName); //find package required by old npm

  if (!fs.existsSync(packageDir))
    throw new Error('Cannot find global module \'' + packageName + '\'');

  var packageMeta = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json')).toString());
  var main = path.join(packageDir, packageMeta.main);

  return require(main);
}

Ich mag diesen Ansatz, da hierfür keine speziellen Module installiert werden müssen.

Ich habe mich nicht für eine NODE_PATHLösung entschieden, wie sie andere vorgeschlagen haben, da ich wollte, dass diese auf jedem Computer funktioniert, ohne dass vor dem Ausführen zusätzliche Konfigurationen / Einstellungen erforderlich sindnpm install ich für mein Projekt ausgeführt werde.

So wie dies codiert ist, werden garantiert nur Module der obersten Ebene (installiert mit npm install -g ...) oder Module gefunden, die von npm(wie dependencieshier aufgeführt: https://github.com/npm/npm/blob/master/package.json ) benötigt werden. Wenn Sie eine neuere Version von NPM verwenden, werden möglicherweise Abhängigkeiten von anderen global installierten Paketen gefunden, da es eine flachere Struktur für gibtnode_modules jetzt Ordner gibt.

Hoffe das ist nützlich für jemanden.

Joe Skeen
quelle
19

Gemäß der Dokumentation sucht Node.js standardmäßig an folgenden Orten:

  1. In der NODE_PATHUmgebungsvariablen angegebener Pfad .

    Hinweis: Die NODE_PATHUmgebungsvariable wird auf eine durch Doppelpunkte getrennte Liste absoluter Pfade festgelegt.

  2. Aktueller node_modulesOrdner. (lokal)

  3. $HOME/.node_modules (global)

    Hinweis: $HOMEist das Home-Verzeichnis des Benutzers.

  4. $HOME/.node_libraries (global)
  5. $PREFIX/lib/node (global)

    Hinweis: $PREFIXIst Node.js konfiguriert node_prefix.

    node_prefixFühren Sie Folgendes aus , um den aktuellen Wert von zu überprüfen :

    node -p process.config.variables.node_prefix

    Hinweis: Das Präfix entspricht dem --prefixParameter während der Erstellung und ist relativ zu process.execPath. Nicht mit dem Wert des npm config get prefixBefehls zu verwechseln . Quelle

Wenn das angegebene Modul nicht gefunden werden kann, bedeutet dies, dass es an keiner der oben genannten Stellen vorhanden ist.

Der Speicherort des globalen Stammordners, in dem Module installiert sind, kann wie npm root -gfolgt gedruckt werden: (Standardmäßig wird der Pfad zur Laufzeit berechnet, sofern er nicht in der npmrcDatei überschrieben wird. )

Lösung

Sie können die folgenden Problemumgehungen ausprobieren:

  • Geben Sie Ihren globalen Modulspeicherort in der NODE_PATHUmgebungsvariablen an. Z.B

    echo 'require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node

    NODE_PATHFühren Sie Folgendes aus , um den Wert von zu testen und auszudrucken :

    echo 'console.log(process.env.NODE_PATH); require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node 
  • Verknüpfen Sie Ihren $HOME/.node_modulesglobalen Benutzerordner, um auf den Stammordner zu verweisen, indem Sie diesen Befehl ausführen, um eine dauerhaftere Lösung zu erhalten :

    ln -vs "$(npm root -g)" "$HOME"/.node_modules

    Testen Sie es dann erneut über den echo 'require("forever")' | nodeBefehl :.

  • Ändern Sie vorübergehend den aktuellen Ordner in den Ort, an dem die Erweiterung global installiert wurde, bevor Sie das Skript aufrufen. Z.B

    npm install -g forever
    cd "$(npm root -g)"
    echo 'require("forever")' | node
    cd -
  • Konfigurieren Sie das globale Installationsziel in der npmuserconfig-Datei (siehe :) npm help 5 npmrcoder mit userconfigparam ( --prefix).

    Führen Sie Folgendes aus, um die aktuelle Konfiguration anzuzeigen : npm config list.

    Führen Sie Folgendes aus, um die aktuelle Konfiguration zu bearbeiten : npm config edit.

  • Geben Sie beim Aufruf den vollständigen Pfad des Speicherorts des Knotenmoduls anrequire() . Z.B

    require("/path/to/sub/module")
  • Installieren Sie das Paket an einem benutzerdefinierten Speicherort, z

    npm install forever -g --prefix "$HOME"/.node_modules

    Die Installation wird jedoch untergehen ~/.node_modules/lib/node_modules/ , sodass der Speicherort noch hinzugefügt werden muss.

    Siehe: Lokales Installationspaket für npm an einem benutzerdefinierten Speicherort

  • Erstellen Sie einen Symlink im aktuellen Ordner vom Speicherort des globalen Pakets. Z.B

    npm link forever
Kenorb
quelle
Es sieht aus wie 4. Aktueller Ordner node_modules. (lokal) hat Vorrang vor 3. $ PREFIX / lib / node (global)
Király István
Lokale node_modules-Ordner haben immer Vorrang vor globalen Ordnern!
Király István
14

Sie können das Paket verwenden requireg, um dieses Problem zu lösen:

var forever = require('requireg')('forever')

wird den Trick machen.

Außerdem gibt es ein weiteres Modul, global-npmwährend spezifisch nur die globale Verwendung npm, können Sie in dem aussehen kurzen Code und sehen , wie die Technik funktioniert.

JP Richardson
quelle
interessant, aber die NODE_PATH-Methode ist wahrscheinlich kanonischer
Alexander Mills
Das Schöne daran NODE_PATHist auch, dass Sie keinen Code ändern müssen. (Mein Anwendungsfall besteht darin, viele Studentenprojekte zu bewerten, bei denen ich nicht npm installfür jedes einzelne ausführen möchte und auch nicht möchte, dass sie ein node_modulesVerzeichnis bereitstellen. )
Amenthes
Nein, es reicht nicht aus, weil Sie es gar nicht erst benötigen können requireg, das ist der springende Punkt.
Thisismydesign
6

Für CLI-Dienstprogramme, die von großen Modulen abhängen, z. B. möchte puppeteerich ein Spawn erzeugen npm root -gund es verwenden, um das globale Modul zu benötigen.

try {
  const root = require('child_process').execSync('npm root -g').toString().trim()
  var puppeteer = require(root + '/puppeteer')
} catch (err) {
  console.error(`Install puppeteer globally first with: npm install -g puppeteer`)
  process.exit(1)
}
Christophe Marois
quelle
3

Sie können diese Zeile in Ihre .profileDatei einfügen:

export NODE_PATH = "$ (npm config erhält Präfix) / lib / node_modules"

Dadurch wird nodeder globale Pfad verwendet.

Luis Paulo
quelle
1
Nein. Dies ist der generische Weg, um das Globale zu bekommen node_modules. Dies ist eine alte Antwort, aber ich erinnere mich, dass ich sie irgendwo in der Dokumentation erhalten habe. Auf meinem Computer (im Jahr 2020) befindet sich das globale npm- node_modulesVerzeichnis usr/lib/node_modules. Wie auch immer, ich vertraue darauf, npm config get prefixdass es von npm global verwendet wird, wenn ein globales Paket installiert wird, also sollte es richtig sein.
Luis Paulo
1
In beiden Fällen (ich habe dies in meiner ersten Antwort nicht gesagt, weil ich mit Node.JS nicht sehr erfahren war) ist die Verwendung global installierter Pakete in einem Programm ein Randanwendungsfall und sollte selten durchgeführt werden, da sie in einem Projekt erstellt werden Probleme, wenn das Projekt in VCS festgeschrieben und in einer anderen Umgebung geklont wird, da diese spezifische Abhängigkeit nicht in der package.jsonDatei oder in yarn.lock/ enthalten ist package-lock.json.
Luis Paulo
1
Oh! Ich verstehe jetzt. Ich glaube, Sie verwechseln den NODE_PATH mit PATH. In PATH sucht eine Shell nach ausführbaren Dateien. In NODE_PATH sucht der Knoten nach Paketen. Zunächst wird das aktuelle Verzeichnis nach einem node_modulesOrdner durchsucht, dann übergeordnet, dann übergeordnet, ... bis ein node_modulesOrdner gefunden wird, der dieses Modul enthält. Wenn Sie ein Paket jedoch global installieren, befindet es sich nicht in einem node_modulesOrdner über dem aktuellen Verzeichnis des Skripts, sodass Sie NODE_PATH als Fallback verwenden, in dem der Knoten nach Paketen sucht.
Luis Paulo
1
ahahahah @Luis Paulo du hast vollkommen recht !! Es tut mir Leid! Ich werde versuchen, einige meiner Kommentare zu löschen, um Verwirrung, gute Arbeit und Danke zu vermeiden
Ryan Taylor
@ Ryan Taylor Sie sollten Kommentare und Fragen nicht löschen, sobald sie gelöst sind, da jemand anderes die gleichen haben könnte. Jetzt sieht es so aus, als hätte ich einen Monolog in den Kommentaren! ahahahah
Luis Paulo