在node.JS中,我如何获取通过require加载的模块的路径?


94

我需要通过npm安装的模块。我想访问一个从属于该模块的.js文件(因此我可以在其中继承一个Constructor方法)。我不能(当然,不想)修改模块的代码,因此没有地方提取其__dirname。

我知道以下问题,但这是关于获取一个可以对其进行代码控制的模块的路径(因此,解决方案是__dirname): 在Node.js中,我如何分辨`this`模块的路径?

~~~

更好的办法是获取模块的已加载模块信息


在哪里可以使用require('modulename')加载模块而不会出现任何错误?
Futur

你能更好地解释吗?一些代码?
加布里埃尔·拉玛斯

Answers:


130

如果我正确理解您的问题,则应使用require.resolve()

使用内部的require()机制查找模块的位置,而不是加载模块,只需返回解析的文件名即可。

例: var pathToModule = require.resolve('module');


13
此答案不适用于所有节点模块。看我的答案。
杰森

61

require.resolve()是部分答案。可接受的答案可能适用于许多节点模块,但不适用于所有节点模块。

require.resolve("moduleName")没有为您提供安装模块的目录;它为您提供了main在模块的属性中定义的文件的位置package.json

那可能是moduleName/index.js或者可能是moduleName/lib/moduleName.js。在后一种情况下,path.dirname(require.resolve("moduleName"))将返回您可能不需要或期望的目录:node_modules/moduleName/lib

获取特定模块完整路径的正确方法是解析文件名:

let readmePath = require.resolve("moduleName/README.md");

如果您只想要模块的目录(也许您将要进行很多path.join()调用),请解析package.json-必须始终位于项目的根目录中-并传递给path.dirname()

let packagePath = path.dirname(require.resolve("moduleName/package.json"));

1
通过检测package.json文件非常聪明的答案。您不应该使用path.join('moduleName', 'package.json')Windows兼容吗?
若奥·皮门特尔·费雷拉

2
@JoãoPimentelFerreirarequire.resolve与平台无关,就像require不需要使用它一样path.join
Gopikrishna S

1
const path = require('path');使用前不要忘记添加path.dirname
GOTO

我希望这个答案是完全正确的!我可以成功解决类似的问题require.resolve('@scope/module'),而却给我类似的问题/path/to/@scope/module/dist/index.js,但是,如果我尝试运行,require.resolve('@scope/module/package.json')则会抛出MODULE_NOT_FOUND错误。我在Node 14.4.0中,我要解析的模块"type": "module"在package.json中包含一个exports不包含的字段package.json。不确定是否与它有任何关系...
trusktr

我发现了问题:当模块具有时type: module,显然package.json必须在该exports字段中显式公开它。我认为Node的新ESM功能不会require像往常一样阻止解析路径,但显然可以。
trusktr

3

仅供参考,require.resolve根据CommonJS返回模块标识符。在node.js中,这是文件名。在webpack中,这是一个数字。

webpack的情况下,这是我的解决方案,以找出模块路径:

const pathToModule = require.resolve('module/to/require');
console.log('pathToModule is', pathToModule); // a number, eg. 8
console.log('__webpack_modules__[pathToModule] is', __webpack_modules__[pathToModule]);

然后从__webpack_modules__[pathToModule]我得到这样的信息:

(function(module, exports, __webpack_require__) {

    eval("module.exports = (__webpack_require__(6))(85);\n\n//////////////////\n// 
    WEBPACK FOOTER\n// delegated ./node_modules/echarts/lib/echarts.js from dll-reference vendor_da75d351571a5de37e2e\n// module id = 8\n// module chunks = 0\n\n//# sourceURL=webpack:///delegated_./node_modules/echarts/lib/echarts.js_from_dll-reference_vendor_da75d351571a5de37e2e?");

    /***/
})

原来,我需要以前的dll构建文件中的旧脚本(以加快构建速度),以便我更新的模块文件无法按预期工作。最后,我重建了我的dll文件并解决了我的问题。

参考:使用require.resolve得到解决文件路径(节点)


2

我希望我能正确理解您的需求:获取某个模块的入口点文件。假设您要获取jugglingdb模块的入口点:

node
> require('module')._resolveFilename('jugglingdb')
'/usr/local/lib/node_modules/jugglingdb/index.js'

如您所见,这不是获取有关模块信息的“官方”方式,因此此功能的行为可能因版本而异。我在节点源中找到了它:https : //github.com/joyent/node/blob/master/lib/module.js#L280


2

根据@anatoliy解决方案,在MacOS XI上发现了查找路径

require('module')._resolveLookupPaths('myModule')

所以我得到了解析的查找路径

[ 'myModule',
  [ '/Users/admin/.node_modules',
    '/Users/admin/.node_libraries',
    '/usr/local/lib/node' ] ]

require('module')._resolveFilename('myModule')

无论如何,它都不会解析我一直在寻找的模块,事实上,疯狂的事情是_load无法解析该模块:

> require('module')._load('myModule')
Error: Cannot find module 'myModule'
    at Function.Module._resolveFilename (module.js:440:15)
    at Function.Module._load (module.js:388:25)
    at repl:1:19
    at sigintHandlersWrap (vm.js:32:31)
    at sigintHandlersWrap (vm.js:96:12)
    at ContextifyScript.Script.runInContext (vm.js:31:12)
    at REPLServer.defaultEval (repl.js:308:29)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:489:10)

require遗嘱:

> require('myModule')

但是我没有这个模块

myProject/node_modules/
myProject/node_modules/@scope/
/usr/local/lib/node_modules/
/usr/local/lib/node_modules/@scope
/usr/local/lib/node_modules/npm/node_modules/
/usr/local/lib/node_modules/npm/node_modules/@scope
$HOME/.npm/
$HOME/.npm/@scope/

那么这个模块在哪里?

首先,我不得不做$ sudo /usr/libexec/locate.updatedb 一些咖啡我做,然后进行locate myModule或更好locate myModule/someFile.js

等等,结果是它在我项目的父文件夹中,即在我的项目根文件夹之外:

$pwd
/Users/admin/Projects/Node/myProject
$ ls ../../node_modules/myModule/

所以你不能避免rm -rf ../../node_modules/myModule/和新鲜npm install

我可以争辩说,没有人指示npm扫描我的计算机以查找应该在其运行的项目根文件夹或默认模块搜索路径之外的其他模块。


1

这可能是您要查找的内容,请检查:

require.main.filename


1

在Node.js ESM和该exports领域问世之前,Jason的答案是最好的答案。

现在,Node支持带有exports默认字段的软件包,除非该软件包的作者明确决定公开这些文件package.json否则默认情况下它将阻止诸如文件之类的文件被解析,对于未显式公开的软件包,Jason的回答将失败package.json

有一个名为的软件包resolve-package-path可以解决问题。

使用方法如下:

const resolvePkg = require('resolve-package-path')

console.log(resolvePkg('@some/package'))

这将输出类似

/path/to/@some/package/package.json

无论包装的exports字段包含什么。


我怀疑一旦作者有意识地导出了模块内容的一部分,您就处于更加不稳定的境地,因为现在作者已经正式定义了他们的公共接口。我认为,这将导致对未明确导出的内容进行更积极的重构,不是吗?
杰森

@Jason对于源文件来说是正确的,但是package.json文件并没有消失。我看不出有任何理由应将其隐藏起来。
trusktr
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.