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.