NodeJS 需要一个全局模块/包

Posted

技术标签:

【中文标题】NodeJS 需要一个全局模块/包【英文标题】:NodeJS require a global module/package 【发布时间】:2013-03-16 04:58:00 【问题描述】:

我正在尝试全局安装,然后像这样使用foreverforever-monitor

npm install -g forever forever-monitor

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

我正在使用 node 和 npm 的最新版本,并且我已经知道 npm 在全局安装和本地安装中所做的更改,但是我真的不想在每个项目上都安装本地化我正在使用一个不支持link 的平台,所以在全局安装后npm link 对我来说是不可能的。

我的问题是:为什么我不能要求全局安装包?这是一个功能还是一个错误?还是我做错了什么?

PS:只是为了说清楚:我不想在本地安装。

【问题讨论】:

我把它留在这里github.com/yarnpkg/yarn/issues/2049github.com/yarnpkg/yarn/issues/2049#issuecomment-337870443 How do I import global modules in Node? I get "Error: Cannot find module <module>"?的可能重复 所以它是 ~/.config/yarn/global 用于纱线 【参考方案1】:

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

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

见here

【讨论】:

我在不支持链接的平台上运行(如我的问题所述)blog.nodejs.org/2011/04/06/npm-1-0-link 您使用的是哪个平台? 我真的不想弄乱链接(也不想弄乱符号链接)。我只想在全球范围内安装软件包并需要它们。我知道 NPM 是为了避免这种情况而重新设计的,但要实现这样的目标有多难? 如果我没有项目怎么办?说~/some-stand-alone-random-nodejs-test.js。我不想将我的主文件夹变成项目目录。我不想为每个小实验都创建新文件夹。 在 Windows 8.1 上完美运行。从节点命令行 cd 到我项目的本地 node_modules 文件夹,然后执行 npm link &lt;module&gt; 然后您将看到在项目的 node_module 文件夹中创建的快捷方式(链接)引用全局节点模块。【参考方案2】:

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

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

export NODE_PATH=/usr/lib/node_modules

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

请参阅:Loading from the global folders。

【讨论】:

在我的 Ubuntu 13.10 机器上,模块的全局路径与您在此处显示的不同。我不得不改用export NODE_PATH=/usr/local/lib/node_modules 如果您在 Windows 7 / 8 上并且没有覆盖任何 Node 的安装默认值,将 NODE_PATH 环境变量设置为 C:\Users\USERNAME\AppData\Roaming\npm\node_modules 可能会起作用。 @WesJohnson Just %AppData%\npm\node_modules 将在 Windows 10 上运行。 如果我设置NODE_PATH 可以同时使用全局和本地模块吗? 替代静态路径,即如果您使用 NVM:NODE_PATH=$(npm root -g)【参考方案3】:

为死灵致歉,但我可以指定全局安装模块的硬编码路径:

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

这并不完美,但考虑到 Unity3d 尝试“编译”项目目录中包含的所有 javascript,我真的无法安装任何包。

【讨论】:

Unity3D 不支持 JavaScript。它的 Boo 解释器/编译器支持类似 JS 的语法 (Boo 是一种用于 .NET 的类似 Python 的语言) 被伪装成“JavaScript”。 Unity 支持的语言更准确的名称是 UnityScript。因为它甚至不接近同一种语言,所以为 Web 或 Node.js 编写的 JS 几乎都不能在 Unity 中运行。有关 Unity 官方 wiki 上的差异的更多信息:wiki.unity3d.com/index.php/UnityScript_versus_JavaScript 或自定义全局路径var pg = require('/home/&lt;username&gt;/.npm-global/lib/node_modules/pg') 永远不要为死灵术道歉。这是a badge 大声哭泣。 ;^)【参考方案4】:

你可以使用包requireg来解决这个问题:

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

会成功的。

另外,还有另一个模块 global-npm,虽然专门用于使用全局 npm,但您可以查看 short code 并了解该技术的工作原理。

【讨论】:

有趣,但 NODE_PATH 方法可能更规范 NODE_PATH 的美妙之处还在于,您无需更改任何代码。 (我的用例是对很多学生项目进行评分,我不想为每个项目运行npm install,也不希望他们提供node_modules 目录)。 不,它不会起作用,因为你不能首先要求requireg,这就是重点。 我遇到了 shellJs + typescript + ncc + docker 工作正常的问题。这个答案引导我走上正确的道路,最终使用全局安装的 shelljs 和 requireq 让它工作。 let shell = require("requireg")("shelljs");【参考方案5】:

我知道这是一个老问题,但是当我尝试在 package.jsonpreinstall 脚本中使用 semver 进行版本检查时遇到了这个问题。因为我知道我不能依赖安装的任何本地模块,所以我用它来要求全局 node_modules 文件夹中的 semver(因为 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 文件夹的结构更加扁平。

希望这对某人有用。

【讨论】:

很棒的功能!谢谢!【参考方案6】:

根据documentation,Node.js 默认会在以下位置进行搜索:

    NODE_PATH 环境变量中指定的路径

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

    当前node_modules 文件夹。(本地)

    $HOME/.node_modules(全球)

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

    $HOME/.node_libraries(全球)

    $PREFIX/lib/node(全球)

    注意:$PREFIX是Node.js配置的node_prefix

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

    node -p process.config.variables.node_prefix
    

    注意:前缀对应于构建过程中的--prefix参数,它是相对于process.execPath的。不要与npm config get prefix 命令中的值混淆。source

如果找不到给定的模块,则表示它不在上述位置之一。

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

解决方案

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

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 -

npm userconfig file(参见:npm help 5 npmrc)或userconfig参数(--prefix)中配置全局安装目标。

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

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

调用require()时指定node modules location的完整路径。例如

require("/path/to/sub/module")

将包安装到自定义位置,例如

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

但是,安装会在~/.node_modules/lib/node_modules/下进行,所以还是需要添加位置。

见:npm local install package to custom location

Create a symlink 在全局包所在位置的当前文件夹中。例如

npm link forever

【讨论】:

看起来像 4. 当前 node_modules 文件夹。 (local) 优先于 3. $PREFIX/lib/node (global) 本地 node_modules 文件夹总是优先于全局文件夹!【参考方案7】:

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

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

这将使node 使用全局路径。

【讨论】:

没有。这是获取全局node_modules 的通用方式。这是一个旧答案,但我记得我是从文档中的某个地方得到的。无论如何,在我的计算机中(2020 年),全局 npm node_modules 目录是 usr/lib/node_modules。无论如何,我相信npm config get prefix,因为无论何时安装全局包,npm 都会全局使用它,所以它应该是正确的。 无论哪种方式(我在最初的回答中没有这么说,因为我在 Node.JS 方面不是很有经验),在程序中使用全局安装的包是一个边缘用例,应该很少使用这样做是因为在项目中,每当项目提交到 VCS 并在另一个环境中克隆时,由于该特定依赖项不在 package.json 文件或 yarn.lock/package-lock.json 中,它会产生问题。 哦!我现在知道了。我相信您将 NODE_PATH 与 PATH 混淆了。 PATH 是 shell 查找可执行文件的地方。 NODE_PATH 是节点查找包的地方。它将首先查看node_modules 文件夹的当前目录,然后是父目录,然后是父目录,...直到找到包含该模块的node_modules 文件夹。但是,如果您全局安装一个包,它不会位于脚本当前目录上方的任何 node_modules 文件夹中,因此您可以使用 NODE_PATH 作为节点查找包的备用路径。 ahahahah @Luis Paulo 你是完全正确的!对不起!我会尝试删除我的一些 cmets 以防止混淆,干得好,谢谢 @Ryan Taylor 你不应该删除 cmets 和问题,因为其他人可能有相同的问题。现在看来,我在 cmets 中有一段独白!哈哈哈【参考方案8】:

对于依赖于大​​模块的 CLI 实用程序,例如 puppeteer,我喜欢生成一个 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)

【讨论】:

【参考方案9】:

我尝试遵循其他答案,但对我有用的是

      node_path = "C:\\Users\\usename\\AppData\\Roaming\\npm\\node_modules"
      const *modulename* = require(node_path + "\\" +'*modulename*');

【讨论】:

以上是关于NodeJS 需要一个全局模块/包的主要内容,如果未能解决你的问题,请参考以下文章

node自定义安装更改npm全局模块默认安装路径

如何从 nodejs 模块中删除全局上下文?

NodeJs笔记

nodejs npm install全局安装和本地安装的区别

找不到模块“newman”需要堆栈:

Nodejs学习笔记----- 路由和全局变量