NodeJS wymaga globalnego modułu / pakietu

159

Próbuję zainstalować globalnie, a następnie używam foreveri forever-monitortak:

npm install -g forever forever-monitor

Widzę zwykłe dane wyjściowe, a także operacje, które kopiują pliki do ścieżki globalnej, ale jeśli spróbuję require("forever");, pojawia się błąd informujący, że moduł nie został znaleziony.

Używam najnowszej wersji zarówno węzła, jak i npm i już wiem o zmianie, którą wprowadził npm w instalacji globalnej vs lokalnej, ale naprawdę nie chcę instalować lokalnie na każdym projekcie i pracuję na platformie, która to robi nie obsługuje, linkwięc npm linkpo instalacji globalnej nie jest dla mnie możliwe.

Moje pytanie brzmi: dlaczego nie mogę wymagać pakietu zainstalowanego globalnie? Czy to funkcja czy błąd? A może robię coś źle?

PS: Żeby było jasne: nie chcę instalować lokalnie.

alexandernst
źródło

Odpowiedzi:

215

W Node.js, require nie zagląda do folderu, w którym są zainstalowane moduły globalne.

Możesz to naprawić, ustawiając zmienną środowiskową NODE_PATH. W Linuksie będzie to:

export NODE_PATH=/usr/lib/node_modules

Uwaga: zależy to od tego, gdzie faktycznie są zainstalowane moduły globalne.

Zobacz: Ładowanie z folderów globalnych .

Daniel Uzunu
źródło
24
Na moim komputerze z Ubuntu 13.10 globalna ścieżka do modułów jest inna niż tutaj pokazana. export NODE_PATH=/usr/local/lib/node_modulesZamiast tego musiałem użyć .
Drew Noakes,
11
Jeśli korzystasz z systemu Windows 7/8 i nie nadpisałeś żadnych domyślnych ustawień instalacji Node, ustawienie NODE_PATHzmiennej środowiskowej na C:\Users\{USERNAME}\AppData\Roaming\npm\node_modulesprawdopodobnie zadziała.
Wes Johnson,
5
@WesJohnson Just %AppData%\npm\node_modulesbędzie działać w systemie Windows 10.
theblang
6
Jeśli ustawię, NODE_PATHczy mogę jednocześnie używać modułów globalnych i lokalnych?
Paulo Oliveira
6
Alternatywnie zamiast ścieżki statycznej, np. Jeśli używasz NVM:NODE_PATH=$(npm root -g)
holmberd
96

Po zainstalowaniu pakietu globalnie musisz połączyć projekt lokalny z pakietem globalnym

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

Zobacz tutaj

user568109
źródło
2
Pracuję na platformie, która nie obsługuje linków (jak stwierdza moje pytanie) blog.nodejs.org/2011/04/06/npm-1-0-link
alexandernst
1
jakiej platformy używasz?
user568109
1
Naprawdę nie chcę mieszać w linkach (ani w ogóle z linkami symbolicznymi). Chcę tylko zainstalować pakiety globalnie i potrzebuję ich. Wiem, że NPM został przeprojektowany, aby tego uniknąć, ale jak trudne może być osiągnięcie czegoś takiego?
alexandernst
13
A jeśli nie mam projektu? Powiedz ~/some-stand-alone-random-nodejs-test.js. Nie chcę zmieniać folderu domowego w katalog projektu. Nie chcę tworzyć nowych folderów dla każdego małego eksperymentu.
AnnanFay,
1
Działał idealnie w systemie Windows 8.1. Z wiersza poleceń węzła cd do lokalnego folderu node_modules moich projektów, a następnie zostanie wykonany. npm link <module>Następnie zobaczysz skrót (link) utworzony w folderze node_module twoich projektów, odnoszący się do modułu globalnego węzła.
dynamiclynk
26

Przepraszamy za nekromancję, ale jestem w stanie określić zakodowane ścieżki do modułów zainstalowanych globalnie:

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

To nie jest idealne, ale biorąc pod uwagę, że Unity3d próbuje „skompilować” cały javascript, który jest zawarty w katalogu projektu, naprawdę nie mogę zainstalować żadnych pakietów.

Thomas Ingham
źródło
4
Unity3D nie obsługuje JavaScript. Obsługuje składnię podobną do JS dla swojego interpretera / kompilatora Boo (Boo jest językiem podobnym do Pythona dla .NET), który jest zwodniczo reklamowany jako „JavaScript” . Bardziej dokładną nazwą języka obsługiwanego przez Unity jest UnityScript . Ponieważ nie jest nawet zbliżony do tego samego języka, żaden z JS napisanych dla sieci lub dla Node.js nie będzie działał w Unity. Dużo więcej informacji na temat różnic na oficjalnym wiki Unity: wiki.unity3d.com/index.php/UnityScript_versus_JavaScript
D. Thompson
19

Wiem, że to stare pytanie, ale natknąłem się na to, próbując sprawdzić niektóre wersje za semverpomocą preinstallskryptu w programie package.json. Ponieważ wiedziałem, że nie mogę polegać na żadnych zainstalowanych modułach lokalnych, użyłem tego, aby wymagać semverz node_modulesfolderu globalnego (w npmzależności od tego wiem, że tam jest):

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

Podoba mi się to podejście, ponieważ nie wymaga instalacji żadnych specjalnych modułów w celu użycia.

Nie poszedłem z NODE_PATHrozwiązaniem, które sugerowali inni, ponieważ chciałem, aby to działało na czyimś komputerze, bez konieczności dodatkowej konfiguracji / ustawień przed uruchomieniem npm installdla mojego projektu.

Sposób, w jaki jest to zakodowane, gwarantuje znalezienie tylko modułów najwyższego poziomu (zainstalowanych przy użyciu npm install -g ...) lub modułów wymaganych przez npm(wymienione dependenciestutaj: https://github.com/npm/npm/blob/master/package.json ). Jeśli używasz nowszej wersji NPM, może ona znaleźć zależności innych pakietów zainstalowanych globalnie, ponieważ teraz istnieje bardziej płaska struktura node_modulesfolderów.

Mam nadzieję, że to komuś się przyda.

Joe Skeen
źródło
19

Zgodnie z dokumentacją Node.js będzie domyślnie wyszukiwać w następujących lokalizacjach:

  1. Ścieżka określona w NODE_PATHzmiennej środowiskowej .

    Uwaga: NODE_PATHzmienna środowiskowa jest ustawiona na rozdzielaną dwukropkami listę ścieżek bezwzględnych.

  2. Bieżący node_modulesfolder. (lokalny)

  3. $HOME/.node_modules (światowy)

    Uwaga: $HOMEto katalog domowy użytkownika.

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

    Uwaga: $PREFIXjest skonfigurowany node.js użytkownika node_prefix.

    Aby sprawdzić aktualną wartość node_prefix, uruchom:

    node -p process.config.variables.node_prefix

    Uwaga: przedrostek odpowiada --prefixparametrowi podczas kompilacji i jest względem niego process.execPath. Nie mylić z wartością z npm config get prefixpolecenia. źródło

Jeśli danego modułu nie można znaleźć, oznacza to, że nie ma go w żadnej z powyższych lokalizacji.

Lokalizację globalnego folderu głównego, w którym instalowane są moduły, można wydrukować za pomocą: npm root -g(domyślnie ścieżka jest obliczana w czasie wykonywania, chyba że zostanie zastąpiona w npmrcpliku ).

Rozwiązanie

Możesz wypróbować następujące obejścia:

  • Określ globalną lokalizację modułu w NODE_PATHzmiennej środowiskowej. Na przykład

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

    Aby przetestować i wydrukować wartość NODE_PATH, uruchom:

    echo 'console.log(process.env.NODE_PATH); require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node 
  • Aby uzyskać trwalsze rozwiązanie, połącz $HOME/.node_modulesglobalny folder użytkownika, aby wskazywał folder główny, uruchamiając to polecenie:

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

    Następnie ponownie przetestuj za pomocą: echo 'require("forever")' | nodepolecenie.

  • Tymczasowo zmień bieżący folder na globalny, w którym rozszerzenie zostało zainstalowane, przed wywołaniem skryptu. Na przykład

    npm install -g forever
    cd "$(npm root -g)"
    echo 'require("forever")' | node
    cd -
  • Skonfiguruj globalne miejsce docelowe instalacji w npmpliku userconfig (zobacz :)npm help 5 npmrc lub za pomocą userconfigparam ( --prefix).

    Aby wyświetlić bieżący config, uruchom: npm config list.

    Aby edytować bieżący config, uruchom: npm config edit.

  • Podczas wywoływania określ pełną ścieżkę lokalizacji modułów węzłarequire() . Na przykład

    require("/path/to/sub/module")
  • Zainstaluj pakiet w niestandardowej lokalizacji, np

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

    Jednak instalacja ulegnie awarii ~/.node_modules/lib/node_modules/, więc lokalizacja nadal wymaga dodania.

    Zobacz: lokalny pakiet instalacyjny npm do lokalizacji niestandardowej

  • Utwórz łącze symboliczne w bieżącym folderze z lokalizacji pakietu globalnego. Na przykład

    npm link forever
kenorb
źródło
Wygląda jak 4. Bieżący folder node_modules. (lokalna) ma pierwszeństwo przed 3. $ PREFIX / lib / node (global)
Király István
Lokalne foldery node_modules zawsze mają wyższy priorytet niż foldery globalne!
Király István
14

Możesz użyć pakietu, requiregaby rozwiązać ten problem:

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

da rade.

Jest też inny moduł, global-npmchoć specyficzny tylko dla używania globalnego npm, możesz spojrzeć na krótki kod i zobaczyć, jak działa ta technika.

JP Richardson
źródło
ciekawe, ale metoda NODE_PATH jest chyba bardziej kanoniczna
Alexander Mills
piękno NODE_PATHpolega również na tym, że nie musisz zmieniać żadnego kodu. (moim przypadkiem użycia jest ocenianie wielu projektów studenckich, w których nie chcę uruchamiać npm installkażdego z nich, a także nie chcę, aby dostarczali node_moduleskatalog).
amenthes
Nie, to nie zadziała, ponieważ requiregw pierwszej kolejności nie możesz wymagać , o to chodzi.
thisismydesign
6

W przypadku narzędzi CLI, które zależą od dużych modułów, na przykład puppeteerlubię spawnować npm root -gi używać go do wymagania modułu globalnego.

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
źródło
3

Możesz umieścić tę linię w swoim .profilepliku:

export NODE_PATH = "$ (prefiks pobierania konfiguracji npm) / lib / node_modules"

To sprawi node wykorzystanie ścieżki globalnej.

Luis Paulo
źródło
1
Nie. To jest ogólny sposób uzyskiwania globalnego node_modules. To stara odpowiedź, ale pamiętam, że dostałem ją gdzieś w dokumentacji. W każdym razie na moim komputerze (w 2020 roku) jest globalny node_moduleskatalog npm usr/lib/node_modules. W każdym razie ufam, npm config get prefixponieważ jest używany globalnie przez npm za każdym razem, gdy instalowany jest pakiet globalny, więc powinien mieć rację.
Luis Paulo
1
Tak czy inaczej (nie powiedziałem tego w mojej początkowej odpowiedzi, ponieważ nie miałem dużego doświadczenia w Node.JS), używanie globalnie zainstalowanych pakietów w programie jest przypadkiem użycia krawędzi i rzadko powinno być robione, ponieważ w projekcie utworzy problemy za każdym razem, gdy projekt jest zatwierdzony do VCS i sklonowany w innym środowisku z powodu tej konkretnej zależności nie znajdującej się w package.jsonpliku ani w yarn.lock/ package-lock.json.
Luis Paulo
1
O! Teraz rozumiem. Myślę, że mylisz NODE_PATH z PATH. PATH to miejsce, w którym powłoka będzie szukać plików wykonywalnych. NODE_PATH to miejsce, w którym węzeł będzie szukał pakietów. Rozpocznie się od sprawdzenia bieżącego katalogu w poszukiwaniu node_modulesfolderu, następnie katalogu nadrzędnego, potem nadrzędnego ... aż znajdzie node_modulesfolder zawierający ten moduł. Jeśli jednak zainstalujesz pakiet globalnie, nie będzie on znajdował się w żadnym node_modulesfolderze powyżej bieżącego katalogu skryptu, więc używasz NODE_PATH jako rozwiązania zastępczego, w którym węzeł będzie szukał pakietów.
Luis Paulo
1
ahahahah @Luis Paulo, masz całkowitą rację !! Przykro mi! Spróbuję usunąć niektóre z moich komentarzy, aby uniknąć nieporozumień, dobrej pracy i dziękuję
Ryan Taylor
@Ryan Taylor Nie należy usuwać komentarzy i pytań po ich rozwiązaniu, ponieważ ktoś inny może mieć te same. Teraz wygląda na to, że miałem monolog w komentarzach! ahahahah
Luis Paulo