NodeJS nécessite un module / package global

160

J'essaie d'installer globalement, puis d'utiliser foreveret forever-monitorcomme ceci:

npm install -g forever forever-monitor

Je vois la sortie habituelle et aussi les opérations qui copient les fichiers dans le chemin global, mais si j'essaye, require("forever");j'obtiens une erreur indiquant que le module n'a pas été trouvé.

J'utilise la dernière version de node et npm et je connais déjà le changement que npm a fait dans l'installation globale vs locale, mais je ne veux vraiment pas installer localement sur chaque projet et je travaille sur une plate-forme qui ne le fait pas 't support linkdonc npm linkaprès une installation globale n'est pas possible pour moi.

Ma question est la suivante: pourquoi je ne peux pas exiger un package installé globalement? Est-ce une fonctionnalité ou un bug? Ou est-ce que je fais quelque chose de mal?

PS: Juste pour être clair: je ne veux pas installer localement.

alexandernst
la source
donc c'est ~/.config/yarn/globalpour la laine
localhostdotdev

Réponses:

216

Dans Node.js, require ne regarde pas dans le dossier où les modules globaux sont installés.

Vous pouvez résoudre ce problème en définissant la variable d'environnement NODE_PATH. Sous Linux, ce sera:

export NODE_PATH=/usr/lib/node_modules

Remarque: cela dépend de l'endroit où vos modules globaux sont réellement installés.

Voir: Chargement à partir des dossiers globaux .

Daniel Uzunu
la source
24
Sur ma machine Ubuntu 13.10, le chemin global des modules est différent de celui que vous montrez ici. J'ai dû utiliser à la export NODE_PATH=/usr/local/lib/node_modulesplace.
Drew Noakes
11
Si vous êtes sous Windows 7/8 et que vous n'avez remplacé aucune des valeurs par défaut d'installation de Node, définir la NODE_PATHvariable d'environnement sur C:\Users\{USERNAME}\AppData\Roaming\npm\node_modulesfonctionnera probablement.
Wes Johnson
5
@WesJohnson Just %AppData%\npm\node_modulesfonctionnera sous Windows 10.
theblang
6
Si je définis, NODE_PATHpuis-je utiliser simultanément des modules globaux et locaux?
Paulo Oliveira
6
Alternativement au lieu d'un chemin statique, c'est-à-dire si vous utilisez NVM:NODE_PATH=$(npm root -g)
holmberd
98

Après avoir installé le package globalement, vous devez lier le projet local avec le package global

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

Voir ici

user568109
la source
2
Je cours sur une plate-forme qui ne prend pas en charge le lien (comme l'indique ma question) blog.nodejs.org/2011/04/06/npm-1-0-link
alexandernst
1
quelle plateforme utilisez-vous?
user568109
1
Je ne veux vraiment pas jouer avec les liens (ni les liens symboliques du tout). Je veux juste installer les packages globalement et en avoir besoin. Je sais que NPM a été repensé pour éviter cela, mais à quel point pourrait-il être difficile de réaliser quelque chose comme ça?
alexandernst
13
Et si je n'ai pas de projet? Dis ~/some-stand-alone-random-nodejs-test.js. Je ne veux pas transformer mon dossier personnel en répertoire de projet. Je ne veux pas créer de nouveaux dossiers pour chaque petite expérience.
AnnanFay
1
Fonctionne parfaitement sur Windows 8.1. De la ligne de commande du nœud cd au dossier local node_modules de mes projets puis exécuté. npm link <module>Ensuite, vous verrez un raccourci (lien) créé dans le dossier node_module de vos projets faisant référence au module de nœud global.
dynamiclynk
26

Toutes mes excuses pour la nécromancie, mais je suis en mesure de spécifier des chemins codés en dur vers les modules installés globalement:

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

Ce n'est pas parfait mais étant donné qu'Unity3d essaie de "compiler" tous les javascript qui sont inclus dans le répertoire du projet, je ne peux vraiment pas installer de packages.

Thomas Ingham
la source
4
Unity3D ne prend pas en charge JavaScript. Il prend en charge une syntaxe de type JS pour son interpréteur / compilateur Boo (Boo est un langage de type Python pour .NET) qui est commercialisé à tort comme «JavaScript» . Le nom le plus précis du langage pris en charge par Unity est UnityScript . Parce que ce n'est même pas proche du même langage, pratiquement aucun des JS écrits pour le Web ou pour Node.js ne fonctionnera dans Unity. Beaucoup plus d'informations sur les différences sur le wiki officiel de Unity: wiki.unity3d.com/index.php/UnityScript_versus_JavaScript
Slipp
19

Je sais que c'est une vieille question, mais je suis tombé dessus en essayant de faire une vérification de version en utilisant semverun preinstallscript dans package.json. Puisque je savais que je ne pouvais pas dépendre des modules locaux installés, je l'ai utilisé pour exiger semverdu node_modulesdossier global (car cela npmdépend de lui, je sais qu'il est 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);
}

J'aime cette approche car elle ne nécessite l'installation d'aucun module spécial pour pouvoir l'utiliser.

Je n'ai pas opté pour une NODE_PATHsolution comme d'autres l'ont suggéré car je voulais que cela fonctionne sur la machine de n'importe qui, sans avoir besoin de configuration / configuration supplémentaire avant de démarrernpm install mon projet.

La façon dont cela est codé, il est garanti de ne trouver que les modules de premier niveau (installés à l'aide de npm install -g ...) ou les modules requis par npm(répertoriés comme dependenciesici: https://github.com/npm/npm/blob/master/package.json ). Si vous utilisez une version plus récente de NPM, il peut trouver des dépendances d'autres packages installés globalement car la structure des node_modulesdossiers est désormais plus plate .

J'espère que cela est utile à quelqu'un.

Joe Skeen
la source
19

Selon la documentation , Node.js recherchera par défaut dans les emplacements suivants:

  1. Chemin spécifié dans la NODE_PATHvariable d'environnement .

    Remarque: NODE_PATHla variable d'environnement est définie sur une liste de chemins absolus séparés par deux-points.

  2. node_modulesDossier actuel . (local)

  3. $HOME/.node_modules (global)

    Remarque: $HOMEest le répertoire personnel de l'utilisateur.

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

    Remarque: $PREFIXest-ce que Node.js est configuré node_prefix.

    Pour vérifier la valeur actuelle de node_prefix, exécutez:

    node -p process.config.variables.node_prefix

    Remarque: le préfixe correspond au --prefixparamètre lors de la construction et il est relatif à process.execPath. Ne pas confondre avec la valeur de la npm config get prefixcommande. la source

Si le module donné est introuvable, cela signifie qu'il n'est pas présent dans l'un des emplacements ci-dessus.

L'emplacement du dossier racine global où les modules sont installés peut être imprimé par: npm root -g(par défaut, le chemin est calculé au moment de l'exécution sauf s'il est remplacé dans le npmrcfichier ).

Solution

Vous pouvez essayer les solutions de contournement suivantes:

  • Spécifiez l'emplacement de votre module global dans NODE_PATHla variable d'environnement. Par exemple

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

    Pour tester et imprimer la valeur de NODE_PATH, exécutez:

    echo 'console.log(process.env.NODE_PATH); require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node 
  • Pour une solution plus permanente, liez votre $HOME/.node_modulesdossier utilisateur global pour qu'il pointe vers le dossier racine, en exécutant cette commande:

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

    Puis re-testez-le via: echo 'require("forever")' | nodecommande.

  • Changez temporairement le dossier actuel dans lequel l'extension a été installée globalement, avant d'appeler le script. Par exemple

    npm install -g forever
    cd "$(npm root -g)"
    echo 'require("forever")' | node
    cd -
  • Configurez la destination d'installation globale dans le npmfichier userconfig (voir :)npm help 5 npmrc ou par userconfigparam ( --prefix).

    Pour afficher la configuration actuelle, exécutez: npm config list.

    Pour modifier la configuration actuelle, exécutez: npm config edit.

  • Spécifiez le chemin complet de l' emplacement des modules de nœud lors de l'appel require(). Par exemple

    require("/path/to/sub/module")
  • Installez le package à un emplacement personnalisé, par exemple

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

    Cependant, l'installation se déroulera en panne ~/.node_modules/lib/node_modules/, l'emplacement doit donc encore être ajouté.

    Voir: package d'installation local npm vers un emplacement personnalisé

  • Créez un lien symbolique dans le dossier actuel à partir de l'emplacement du package global. Par exemple

    npm link forever
Kenorb
la source
Il ressemble à 4. Dossier node_modules actuel. (local) a priorité sur 3. $ PREFIX / lib / node (global)
Király István
Les dossiers locaux node_modules ont toujours la priorité sur les dossiers globaux!
Király István
14

Vous pouvez utiliser le package requiregpour résoudre ce problème:

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

fera l'affaire.

En outre, il existe un autre module, bien global-npmque spécifique à l'utilisation du global npm, vous pouvez regarder le code court et voir comment la technique fonctionne.

JP Richardson
la source
intéressant, mais la méthode NODE_PATH est probablement plus canonique
Alexander Mills
la beauté de NODE_PATHc'est aussi que vous n'avez pas besoin de changer de code. (mon cas d'utilisation est de noter de nombreux projets d'étudiants, où je ne veux pas exécuter npm installpour chacun d'eux, et je ne veux pas non plus qu'ils fournissent un node_modulesrépertoire).
amenthes le
Non, cela ne fera pas l'affaire car vous ne pouvez pas exiger requiregen premier lieu, c'est tout le problème.
thisismydesign
6

Pour les utilitaires CLI qui dépendent de gros modules, comme puppeteer, j'aime créer un npm root -get l'utiliser pour exiger le module global.

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
la source
3

Vous pouvez mettre cette ligne dans votre .profilefichier:

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

Cela nodeutilisera le chemin global.

Luis Paulo
la source
1
Non. C'est la manière générique d'obtenir le global node_modules. C'est une vieille réponse mais je me souviens que je l'ai eu quelque part dans la documentation. Quoi qu'il en soit, sur mon ordinateur (en 2020), le node_modulesrépertoire global npm est usr/lib/node_modules. Quoi qu'il en soit, je fais confiance npm config get prefixcar il est utilisé globalement par npm chaque fois qu'un package global est installé, il devrait donc être correct.
Luis Paulo le
1
Quoi qu'il en soit (je n'ai pas dit cela dans ma réponse initiale car je n'étais pas très expérimenté dans Node.JS), l'utilisation de packages installés globalement dans un programme est un cas d'utilisation de pointe et devrait rarement être fait car dans un projet, il créera problèmes chaque fois que le projet est validé dans VCS et cloné dans un autre environnement en raison de cette dépendance spécifique ne figurant pas dans le package.jsonfichier ou dans yarn.lock/ package-lock.json.
Luis Paulo le
1
Oh! Je comprends maintenant. Je crois que vous confondez NODE_PATH avec PATH. PATH est l'endroit où un shell recherchera des exécutables. NODE_PATH est l'endroit où le nœud recherchera les packages. Il va commencer par regarder le répertoire courant pour un node_modulesdossier, puis c'est parent, puis c'est parent, ... jusqu'à ce qu'il trouve un node_modulesdossier qui contient ce module. Cependant, si vous installez un package globalement, il ne sera dans aucun node_modulesdossier au-dessus du répertoire actuel du script, vous utilisez donc NODE_PATH comme solution de secours où node recherchera les packages.
Luis Paulo
1
ahahahah @ Luis Paulo tu as tout à fait raison !! Je suis désolé! Je vais essayer de supprimer certains de mes commentaires pour éviter toute confusion, bon travail et merci
Ryan Taylor le
@Ryan Taylor Vous ne devriez pas supprimer les commentaires et les questions une fois qu'ils sont résolus, car quelqu'un d'autre pourrait avoir les mêmes. Maintenant, il semble que j'avais un monologue dans les commentaires! ahahahah
Luis Paulo le