NodeJS richiede un modulo / pacchetto globale


160

Sto cercando di installare a livello globale e quindi utilizzare forevere in forever-monitorquesto modo:

npm install -g forever forever-monitor

Vedo il solito output e anche le operazioni che copiano i file nel percorso globale, ma poi se provo a require("forever");ricevere un errore che dice che il modulo non è stato trovato.

Sto usando l'ultima versione di entrambi i nodi e npm e conosco già il cambiamento che npm ha fatto nell'installazione globale vs locale, ma non voglio davvero installare localmente su ogni progetto e sto lavorando su una piattaforma che non Supporta linkquindi npm linkdopo che un'installazione globale non è possibile per me.

La mia domanda è: perché non posso richiedere un pacchetto installato a livello globale? È una caratteristica o un bug? O sto facendo qualcosa di sbagliato?

PS: Giusto per chiarire: non voglio installare localmente.




quindi è ~/.config/yarn/globalper il filo
localhostdotdev

Risposte:


216

In Node.js, request non appare nella cartella in cui sono installati i moduli globali.

È possibile risolvere questo problema impostando la variabile di ambiente NODE_PATH. In Linux questo sarà:

export NODE_PATH=/usr/lib/node_modules

Nota: dipende da dove sono effettivamente installati i moduli globali.

Vedi: Caricamento dalle cartelle globali .


24
Sulla mia macchina Ubuntu 13.10, il percorso globale per i moduli è diverso da quello mostrato qui. Ho dovuto usare export NODE_PATH=/usr/local/lib/node_modulesinvece.
Ha disegnato Noakes il

11
Se sei su Windows 7/8 e non hai ignorato alcun valore predefinito di installazione di Node, probabilmente l'impostazione della NODE_PATHvariabile di ambiente C:\Users\{USERNAME}\AppData\Roaming\npm\node_modulesfunzionerà.
Wes Johnson,

5
@WesJohnson Funzionerà solo %AppData%\npm\node_modulessu Windows 10.
theblang

6
Se imposto, NODE_PATHposso utilizzare i moduli globali e locali contemporaneamente?
Paulo Oliveira,

6
In alternativa invece di un percorso statico, ovvero se si utilizza NVM:NODE_PATH=$(npm root -g)
holmberd,

98

Dopo aver installato il pacchetto a livello globale, è necessario collegare il progetto locale al pacchetto globale

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

Vedi qui


2
Sono in esecuzione su una piattaforma che non supporta il collegamento (come afferma la mia domanda) blog.nodejs.org/2011/04/06/npm-1-0-link
alexandernst

1
quale piattaforma stai usando?
user568109

1
Non voglio davvero scherzare con i collegamenti (né i collegamenti simbolici). Voglio solo installare i pacchetti a livello globale e richiederli. So che NPM è stato riprogettato per evitarlo, ma quanto potrebbe essere difficile ottenere qualcosa del genere?
alexandernst,

13
E se non avessi un progetto? Say ~/some-stand-alone-random-nodejs-test.js. Non voglio trasformare la mia cartella home in una directory di progetto. Non voglio creare nuove cartelle per ogni piccolo esperimento.
AnnanFay,

1
Ha funzionato perfettamente su Windows 8.1. Dalla riga di comando del nodo cd alla cartella node_modules locale dei miei progetti quindi eseguita npm link <module>Quindi vedrai un collegamento (collegamento) creato nella cartella node_module dei tuoi progetti che fa riferimento al modulo nodo globale.
dynamiclynk,

26

Mi scuso per la negromanzia ma sono in grado di specificare percorsi codificati per i moduli installati a livello globale:

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

Questo non è perfetto, ma considerando che Unity3d tenta di "compilare" tutti i javascript inclusi nella directory del progetto, non riesco davvero ad installare alcun pacchetto.


4
Unity3D non supporta JavaScript. Supporta una sintassi simile a JS per il suo interprete / compilatore Boo (Boo è un linguaggio simile a Python per .NET) che viene ingannevolmente commercializzato come "JavaScript" . Il nome più accurato per la lingua supportata da Unity è UnityScript . Poiché non è nemmeno vicino alla stessa lingua, accanto a nessuno dei JS scritti per il Web o per Node.js funzionerà in Unity. Molte più informazioni sulle differenze nella wiki ufficiale di Unity: wiki.unity3d.com/index.php/UnityScript_versus_JavaScript
Slipp D. Thompson

19

So che questa è una vecchia domanda, ma mi sono imbattuto in questo quando ho provato a fare un controllo della versione utilizzando semveruno preinstallscript in package.json. Dato che sapevo di non poter dipendere da alcun modulo locale installato, l'ho usato per richiedere semverdalla node_modulescartella globale (poiché npmdipende da esso so che è lì):

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

Mi piace questo approccio perché non richiede l'installazione di alcun modulo speciale per poterlo utilizzare.

Non ho optato per una NODE_PATHsoluzione come altri hanno suggerito poiché volevo farlo funzionare sulla macchina di chiunque, senza dover richiedere ulteriori configurazioni / impostazioni prima di eseguire npm installper il mio progetto.

Il modo in cui questo è codificato, è garantito solo per trovare i moduli di livello superiore (installati utilizzando npm install -g ...) o i moduli richiesti da npm(elencati come dependenciesqui: https://github.com/npm/npm/blob/master/package.json ). Se si utilizza una versione più recente di NPM, è possibile che vengano rilevate dipendenze di altri pacchetti installati a livello globale poiché esiste una struttura più piatta per le node_modulescartelle.

Spero che questo sia utile a qualcuno.


19

Come da documentazione , Node.js cercherà nelle seguenti posizioni per impostazione predefinita:

  1. Percorso specificato nella NODE_PATHvariabile di ambiente .

    Nota: NODE_PATHla variabile di ambiente è impostata su un elenco delimitato da due punti di percorsi assoluti.

  2. node_modulesCartella corrente (Locale)

  3. $HOME/.node_modules (globale)

    Nota: $HOMEè la home directory dell'utente.

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

    Nota: $PREFIXè Node.js di configurazione node_prefix.

    Per verificare il valore corrente di node_prefix, eseguire:

    node -p process.config.variables.node_prefix

    Nota: il prefisso corrisponde a --prefixparam durante la compilazione ed è relativo a process.execPath. Da non confondere con il valore del npm config get prefixcomando. fonte

Se il modulo dato non può essere trovato, significa che non è presente in una delle posizioni sopra.

La posizione della cartella principale globale in cui sono installati i moduli può essere stampata tramite: npm root -g(per impostazione predefinita il percorso viene calcolato in fase di esecuzione a meno che non venga sovrascritto nel npmrcfile ).

Soluzione

Puoi provare le soluzioni alternative seguenti:

  • Specificare la posizione del modulo globale nella NODE_PATHvariabile di ambiente. Per esempio

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

    Per testare e stampare il valore di NODE_PATH, eseguire:

    echo 'console.log(process.env.NODE_PATH); require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node 
  • Per una soluzione più permanente, collega la tua $HOME/.node_modulescartella utente globale per puntare alla cartella principale, eseguendo questo comando:

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

    Quindi riprovare tramite: echo 'require("forever")' | nodecomando.

  • Modificare temporaneamente la cartella corrente in cui l'estensione è stata installata a livello globale, prima di richiamare lo script. Per esempio

    npm install -g forever
    cd "$(npm root -g)"
    echo 'require("forever")' | node
    cd -
  • Configura la destinazione di installazione globale nel npmfile userconfig (vedi :)npm help 5 npmrc o da userconfigparam ( --prefix).

    Per visualizzare la configurazione corrente, eseguire: npm config list.

    Per modificare la configurazione corrente, eseguire: npm config edit.

  • Specificare il percorso completo della posizione dei moduli nodo durante la chiamata require(). Per esempio

    require("/path/to/sub/module")
  • Installa il pacchetto in un percorso personalizzato, ad es

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

    Tuttavia, l'installazione andrà sotto ~/.node_modules/lib/node_modules/, quindi la posizione deve ancora essere aggiunta.

    Vedi: npm pacchetto di installazione locale in posizione personalizzata

  • Creare un collegamento simbolico nella cartella corrente dalla posizione del pacchetto globale. Per esempio

    npm link forever

Sembra che 4. Cartella node_modules corrente. (locale) ha la priorità su 3. $ PREFIX / lib / node (globale)
Király István

Le cartelle locali node_modules hanno sempre la priorità sulle cartelle globali!
Király István,

14

È possibile utilizzare il pacchetto requiregper risolvere questo problema:

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

farà il trucco.

Inoltre, c'è un altro modulo, global-npmmentre specifico per l'utilizzo del globale npm, puoi guardare il codice funzione e vedere come funziona la tecnica.


interessante, ma il metodo NODE_PATH è probabilmente più canonico
Alexander Mills

il bello NODE_PATHè anche che non è necessario modificare alcun codice. (il mio caso d'uso sta valutando molti progetti studenteschi, in cui non voglio correre npm installper ognuno, e inoltre non voglio che forniscano node_modulesdirectory).
amenthes,

No, non farà il trucco perché non è possibile richiedere requiregin primo luogo, questo è il punto.
thisismydesign

6

Per le utility della CLI che dipendono da grandi moduli, ad esempio puppeteer, mi piace spawnare npm root -ge usarlo per richiedere il modulo globale.

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

3

Puoi inserire questa riga nel tuo .profilefile:

export NODE_PATH = "$ (npm config get prefix) / lib / node_modules"

Questo farà nodeuso del percorso globale.


1
No. Questo è il modo generico di ottenere il globale node_modules. Questa è una vecchia risposta, ma ricordo di averla ricevuta da qualche parte nella documentazione. Ad ogni modo, nel mio computer (nel 2020) la node_modulesdirectory npm globale è usr/lib/node_modules. Ad ogni modo, mi fido npm config get prefixperché viene utilizzato a livello globale da npm ogni volta che viene installato un pacchetto globale, quindi dovrebbe essere giusto.
Luis Paulo,

1
In entrambi i casi (non ho detto questo nella mia risposta iniziale perché non avevo molta esperienza in Node.JS), l'uso di pacchetti installati globalmente in un programma è un caso di utilizzo marginale e dovrebbe essere fatto raramente perché in un progetto creerà problemi ogni volta che il progetto è impegnato in VCS e clonato in un altro ambiente a causa della dipendenza specifica che non si trova nel package.jsonfile o in yarn.lock/ package-lock.json.
Luis Paulo,

1
Oh! Ora capisco. Credo che stai scambiando NODE_PATH con PATH. PERCORSO è dove una shell cercherà eseguibili. NODE_PATH è dove il nodo cercherà i pacchetti. Inizierà guardando la directory corrente per una node_modulescartella, quindi è padre, quindi è padre, ... fino a quando non trova una node_modulescartella che contiene quel modulo. Tuttavia, se si installa un pacchetto a livello globale, non si troverà all'interno di alcuna node_modulescartella sopra la directory corrente dello script, quindi si utilizza NODE_PATH come fallback in cui il nodo cercherà i pacchetti.
Luis Paulo,

1
ahahahah @Luis Paulo hai perfettamente ragione !! Mi dispiace! Cercherò di eliminare alcuni dei miei commenti per evitare confusione, bel lavoro e grazie
Ryan Taylor,

@Ryan Taylor Non dovresti eliminare commenti e domande una volta risolti perché qualcun altro potrebbe avere gli stessi. Ora sembra proprio che avessi un monologo nei commenti! ahahahah
Luis Paulo,
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.