我需要一个通过 npm 安装的模块。我想访问从属于该模块的 .js 文件(因此我可以在其中子类化一个 Constructor 方法)。我不能(好吧,不想)修改模块的代码,所以没有地方提取它的 __dirname。
我知道以下问题,但它是关于获取一个具有代码控制权的模块的路径(因此,__dirname 是解决方案): 在 Node.js 中,我如何告诉 `this` 模块的路径?
~~~
更好的是获取模块的加载模块信息
我需要一个通过 npm 安装的模块。我想访问从属于该模块的 .js 文件(因此我可以在其中子类化一个 Constructor 方法)。我不能(好吧,不想)修改模块的代码,所以没有地方提取它的 __dirname。
我知道以下问题,但它是关于获取一个具有代码控制权的模块的路径(因此,__dirname 是解决方案): 在 Node.js 中,我如何告诉 `this` 模块的路径?
~~~
更好的是获取模块的加载模块信息
如果我正确理解您的问题,您应该使用require.resolve():
使用内部 require() 机制来查找模块的位置,而不是加载模块,只返回解析的文件名。
例子:var pathToModule = require.resolve('module');
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"));
仅供参考,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文件并解决了我的问题。
Jason 的答案是最好的答案,直到 Node.js ESM 和该exports
领域问世。
现在 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
字段包含什么。
我希望我正确理解您的需求:获取某个模块的入口点文件。假设您想获取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
根据@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
etvoilà,它出现在我项目的父文件夹中,即在我的项目根文件夹之外:
$pwd
/Users/admin/Projects/Node/myProject
$ ls ../../node_modules/myModule/
所以你无法避免rm -rf ../../node_modules/myModule/
和新鲜npm install
。
我可以争辩说,没有人指示npm
扫描我的计算机以在我应该运行的项目根文件夹或默认模块搜索路径之外的其他地方搜索模块。
这可能是您正在寻找的,请检查:
需要.main.filename