如何加载节点模块,就好像当前模块位于其他地方一样?

How do I load a node module as if the current module were located somewhere else?

我在某个模块中有一些 nodejs 代码 运行。从这个模块,我想加载一个位于文件系统中完全不同位置的模块——例如,给定路径 "/another/dir" 和模块名称 "foo",我希望 Node 执行好像 /another/dir 中的模块 运行 调用了 require("foo"),而不是我自己的模块。

  My code is running here
/some/folder/node_modules/mine/my_module.js

  I have the path "/another/dir/", the string "foo",
    and want to load this module
/another/dir/node_modules/foo/index.js

换句话说,module documentation指的是进程"require(X) from module at path Y",我想为Y指定我自己的值

这能实现吗?如果是这样,如何?如果不是,为什么不呢?

最简单的,就是将路径解析为绝对路径,即使不是所有情况,这也是大多数情况下的推荐方法。

var path = require('path');

var basedir = '/another/dir';
var filename = 'foo'; // renamed from dirname

var filepath = path.join(basedir, 'node_modules', filename);
var imports = require(filepath);

如果您确实需要让 require 像在不同的目录中一样工作, 您可以将基本目录推送到 module.paths

module.paths.unshift('/another/dir/node_modules');

var imports = require('foo');

module.paths.shift();

module.paths 也可以通过环境变量 NODE_PATH 在外部进行修改,尽管这是最不推荐的方法 但是 这确实适用于全局所有模块。

实现起来很简单,给模块对象加上绝对路径就可以了

在您当前的脚本中/some/folder/node_modules/mine/my_module.js添加这个

module.paths.push('/another/dir/node_modules'); 
                   //this must be absolute, like /Users/John/another/dir/node_modules

var foo = require('foo');

对于演示,在终端中打开节点,然后键入 module.paths,它将显示节点将搜索 require 的所有路径,您只需添加您的路径

"require(X) from module at path Y"

意味着从位于路径 Y 的文件中调用 require(X)。因此您实际上无法更改 Y。


尽管上述解决方案有效(修改 module.paths 并需要绝对路径),但您必须将这些片段添加到项目中需要外部模块的每个文件中。

更何况,官方不支持修改module.paths。所以它不能保证在节点的未来更新中工作


介绍 NODE_PATH

NODE_PATH 是一个环境变量,设置为以冒号分隔的绝对路径列表。

在这些绝对路径中,Node.js 将在所有其他方法都失败时搜索与您的 require 语句匹配的模块(索引 node_modules 最多文件系统根目录但仍未找到匹配项)

官方支持,但不推荐,因为它违反惯例(您的同事可能不知道 NODE_PATH 用法,因为没有描述性说明在您的项目本身中说明这一点的方式)

备注:

  • 在 Windows 上,NODE_PATH 由分号分隔,而不是 冒号。
  • Node 不会在这些路径中寻找 node_modules 它的默认行为,所以你的路径应该正是你 包含需要的模块。例如:“/another/dir/node_modules”


详细信息可以参考NodeJs官方文档:
https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders

对于那些不知道什么是环境变量以及如何设置它们的人,我有一个 windows 屏幕截图可以帮助您入门

一个 symlink 与 npm link

为了避免问题或修改源代码,我会使用 npm link,从你的示例中:

第一个:

cd /another/dir/node_modules/foo  # go into the package directory
npm link                          # creates global link

这将为 foo 模块创建全局 link,在 Linux 上,您需要 root 权限才能执行此操作。

然后:

cd /some/folder/ # go into some other package directory.
npm link foo     # link-install the package

/some/folder/package.json 应该包含 foo 作为 dep,不是强制性的,没有它你会收到 npm ls:

extraneous 警告
"dependencies": {
    [...]
    "foo": "*"
  }

与本地NODE_PATH

无符号link

你不喜欢 symlinks 吗?您仍然可以使用 NODE_PATH 但在本地而不是按照@rocketspacer 的建议设置全局变量,因为正如他正确指出的那样,不建议在全局使用它。

注意:无论如何我会使用用户变量 系统范围的变量,一个同事可以在同一台机器上使用不同的用户名登录,并且仍然得到修改后的 NODE_PATH.

但是要在 调用 Linux 时在本地执行此操作,您只需调用:

NODE_PATH=$NODE_PATH:/another/dir/node_modules npm start

它将使用 NODE_PATH 用于该调用。

Windows:

上的相同一次调用
@ECHO OFF

SET BASE_NODE_PATH=%NODE_PATH%
SET NODE_PATH=%BASE_NODE_PATH%;C:\another\dir\node_modules\
node index.js
SET NODE_PATH=%BASE_NODE_PATH%

还有...

您也可以使用本地代理,例如:

"dependencies": {
  "foo": "file:/another/dir/node_modules/foo"
}

但需要一个 npm install 并且它会在当前包 node_modules 文件夹中复制 foo 的内容。

简而言之,您可以将自己的文件夹称为模块:

为此我们需要:global 和 app-module-path 模块

此处 "App-module-path" 是模块,它使您可以将其他目录添加到 Node.js 模块搜索路径 "global" 是,您附加到此对象的任何内容都将可用在您的应用中无处不在。

现在看看这个片段:

global.appBasePath = __dirname;

require('app-module-path').addPath(appBasePath);

__dirname是node.You的当前运行目录可以在这里给自己的路径搜索模块的路径。