NodeJS需要一个全局模块/包


158

我试图在全球范围内安装,然后使用foreverforever-monitor这样的:

npm install -g forever forever-monitor

我看到了通常的输出以及将文件复制到全局路径的操作,但是如果我尝试require("forever");这样做,则会收到一条错误消息,指出未找到该模块。

我正在使用最新版本的node和npm,并且我已经知道npm在全局安装与本地安装中所做的更改,但是我真的不想在每个项目上都安装localy,并且我正在一个不支持本地安装的平台上工作。不支持,link因此npm link对我而言无法全局安装。

我的问题是:为什么我不需要全局安装的软件包?那是功能还是错误?还是我做错了什么?

PS:只是为了让它变得清晰起来:我不想在本地安装。




所以是~/.config/yarn/global为了纱线
localhostdotdev

Answers:


215

在Node.js中,require不会在安装全局模块的文件夹中查找。

您可以通过设置NODE_PATH环境变量来解决此问题。在Linux中,它将是:

export NODE_PATH=/usr/lib/node_modules

注意:这取决于您的全局模块的实际安装位​​置。

请参阅:从全局文件夹加载


24
在我的Ubuntu 13.10计算机上,模块的全局路径与此处显示的不同。我不得不使用export NODE_PATH=/usr/local/lib/node_modules
Drew Noakes 2014年

11
如果您使用的是Windows 7/8,并且未覆盖Node的任何安装默认设置,则将NODE_PATH环境变量设置为C:\Users\{USERNAME}\AppData\Roaming\npm\node_modules可能会起作用。
Wes Johnson

5
@WesJohnson只是%AppData%\npm\node_modules将工作在Windows 10
theblang

6
如果设置,是否NODE_PATH可以同时使用全局和本地模块?
Paulo Oliveira

6
替代静态路径,即如果您使用的是NVM,则:NODE_PATH=$(npm root -g)
holmberd

96

全局安装软件包后,必须将本地项目与全局软件包链接

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

这里


2
我正在不支持链接的平台上运行(正如我的问题所述)blog.nodejs.org/2011/04/06/npm-1-0-link
alexandernst

1
您正在使用哪个平台?
user568109 2013年

1
我真的不想弄乱链接(也没有符号链接)。我只想在全球安装软件包并需要它们。我知道NPM经过重新设计可以避免这种情况,但是要实现这样的目标有多困难?
亚历山大

13
如果我没有项目怎么办?说~/some-stand-alone-random-nodejs-test.js。我不想将主文件夹转换为项目目录。我不想为每个小型实验创建新文件夹。
AnnanFay 2014年

1
在Windows 8.1上完美运行。从节点命令行cd到我项目的本地node_modules文件夹,然后执行。npm link <module>然后,您将看到在项目的node_module文件夹中创建的引用全局节点模块的快捷方式(链接)。
dynamiclynk 2014年

26

道歉,但我能够为全局安装的模块指定硬编码的路径:

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

这不是完美的,但是考虑到Unity3d试图“编译”项目目录中包含的所有javascript,我确实无法安装任何软件包。


4
Unity3D不支持JavaScript。它为其Boo解释器/编译器(Boo是.NET的类似Python的语言) 提供了类似JS的语法,这在市场上被称为“ JavaScript”。Unity支持的语言的更准确的名称是UnityScript。因为它甚至不接近同一语言,所以几乎没有为Web或Node.js编写的JS都可以在Unity中使用。关于Unity官方Wiki差异的更多信息:wiki.unity3d.com/index.php/UnityScript_versus_JavaScript
Slipp D. Thompson

19

我知道这是一个老问题,但是在尝试使用semver中的preinstall脚本进行版本检查时遇到了这个问题package.json。因为我知道我不能依赖于已安装的任何本地模块,所以我使用了它来要求semver来自全局node_modules文件夹(npm取决于它,我知道它在那里):

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

我喜欢这种方法,因为它不需要安装任何特殊的模块即可使用。

我没有采用NODE_PATH其他人建议的解决方案,因为我想让它在任何人的机器上都能工作,而在运行npm install我的项目之前无需进行其他配置/设置。

这种编码方式只能保证找到顶级模块(使用安装npm install -g ...)或所需的模块npm(在dependencies此处列出:https : //github.com/npm/npm/blob/master/package.json)。如果您使用的是NPM的较新版本,则它可能会找到其他全局安装的软件包的依赖项,因为node_modules现在文件夹的结构更加扁平。

希望这对某人有用。


19

根据文档,Node.js将默认在以下位置搜索:

  1. NODE_PATH环境变量中指定的路径

    注意:NODE_PATH环境变量设置为以冒号分隔的绝对路径列表。

  2. 当前node_modules文件夹。(本地)

  3. $HOME/.node_modules (全球)

    注意:$HOME是用户的主目录。

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

    注意:$PREFIXNode.js已配置node_prefix

    要检查的当前值node_prefix,请运行:

    node -p process.config.variables.node_prefix

    注意:前缀对应于--prefix构建期间的参数,并且相对于process.execPath。不要与npm config get prefix命令的值混淆。资源

如果找不到给定的模块,则意味着在上述位置之一中不存在该模块。

可以通过以下方式打印安装模块的全局根文件夹的位置:(npm root -g默认情况下,路径在运行时计算,除非在npmrcfile中覆盖了该路径)。

您可以尝试以下解决方法:

  • NODE_PATH环境变量中指定全局模块位置。例如

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

    要测试并打印的值NODE_PATH,请运行:

    echo 'console.log(process.env.NODE_PATH); require("forever")' | NODE_PATH="$(npm root -g):$NODE_PATH" node 
  • 要获得更永久的解决方案,请$HOME/.node_modules通过运行以下命令将全局用户文件夹链接到指向根文件夹:

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

    然后通过以下echo 'require("forever")' | node命令重新测试它:

  • 在调用脚本之前,将当前文件夹临时更改为全局已将扩展安装到的文件夹。例如

    npm install -g forever
    cd "$(npm root -g)"
    echo 'require("forever")' | node
    cd -
  • npmuserconfig文件(请参阅:)中npm help 5 npmrc或通过userconfigparam(--prefix)配置全局安装目标。

    要显示当前配置,请运行:npm config list

    要编辑当前配置,请运行:npm config edit

  • 调用时指定节点模块位置的完整路径require()。例如

    require("/path/to/sub/module")
  • 将软件包安装到自定义位置,例如

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

    但是,安装将在下进行~/.node_modules/lib/node_modules/,因此仍需要添加该位置。

    请参阅:npm本地安装软件包到自定义位置

  • 从全局包的位置在当前文件夹中创建一个符号链接。例如

    npm link forever

看起来像4.当前的node_modules文件夹。在3 $(本地)优先PREFIX / lib目录/节点(全球)
基拉伊伊什特万

本地node_modules文件夹始终优先于全局文件夹!
基拉伊伊什特万

14

您可以使用该程序包requireg解决此问题:

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

会成功的

此外,还有另一个模块,global-npm虽然特定于仅使用global npm,但是您可以查看短代码并了解该技术的工作方式。


有趣,但NODE_PATH方法可能更规范
Alexander Mills

的优点NODE_PATH还在于,您无需更改任何代码。(我的用例是对很多学生项目进行分级,我不想npm install为每个学生项目运行,也不希望他们提供node_modules目录)。
amenthes

不,它不会成功,因为您一开始就不需要requireg,这就是重点。
thisismydesign '19

6

对于依赖大型模块(例如)的CLI实用程序puppeteer,我喜欢生成a npm root -g并将其用于需要全局模块。

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

您可以将以下行放入.profile文件中:

export NODE_PATH =“ $(npm config获取前缀)/ lib / node_modules”

这将node使用全局路径。


1
否。这是获得全球化的通用方式node_modules。这是一个旧答案,但我记得我从文档中的某处得到了它。无论如何,在我的计算机中(2020年),全局npm node_modules目录为usr/lib/node_modules。无论如何,我相信,npm config get prefix因为每当安装了全局软件包时,npm都会全局使用它,因此它应该是正确的。
Luis Paulo

1
无论哪种方式(我在最初的回答中都没有说这一点,因为我对Node.JS不太了解),在程序中使用全局安装的软件包是一种边缘用例,并且很少应这样做,因为它将在项目中创建每当项目提交到VCS并在另一个环境中克隆时,由于package.json文件或yarn.lock/中没有该特定依赖项而导致问题package-lock.json
路易斯·保罗

1
哦! 我现在知道了。我相信您误将NODE_PATH与PATH一起使用。外壳程序将在PATH中查找可执行文件。NODE_PATH是节点将在其中查找软件包的位置。首先从查看当前目录中的node_modules文件夹开始,然后是父文件夹,然后是父文件夹,直到找到node_modules包含该模块的文件夹。但是,如果在全局范围内安装软件包,则该软件包将不会node_modules位于脚本当前目录上方的任何文件夹内,因此您可以将NODE_PATH用作后备节点,节点将在其中查找软件包。
Luis Paulo

1
啊哈哈哈@路易斯·保罗你说的没错!对不起!我将尝试删除我的一些评论,以防止造成混乱,工作愉快并谢谢您
Ryan Taylor

@Ryan Taylor注释和问题得到解决后,您不应删除它们,因为其他人可能也有相同的想法。现在看来我在评论中独白了!啊哈哈哈
路易斯·保罗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.