NodeJS 需要一个全局模块/包
Posted
技术标签:
【中文标题】NodeJS 需要一个全局模块/包【英文标题】:NodeJS require a global module/package 【发布时间】:2013-03-16 04:58:00 【问题描述】:我正在尝试全局安装,然后像这样使用forever
和forever-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 <module>
然后您将看到在项目的 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/<username>/.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.json
的 preinstall
脚本中使用 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 需要一个全局模块/包的主要内容,如果未能解决你的问题,请参考以下文章