我需要通过npm安装的模块。我想访问一个从属于该模块的.js文件(因此我可以在其中继承一个Constructor方法)。我不能(当然,不想)修改模块的代码,因此没有地方提取其__dirname。
我知道以下问题,但这是关于获取一个可以对其进行代码控制的模块的路径(因此,解决方案是__dirname): 在Node.js中,我如何分辨`this`模块的路径?
~~~
更好的办法是获取模块的已加载模块信息
我需要通过npm安装的模块。我想访问一个从属于该模块的.js文件(因此我可以在其中继承一个Constructor方法)。我不能(当然,不想)修改模块的代码,因此没有地方提取其__dirname。
我知道以下问题,但这是关于获取一个可以对其进行代码控制的模块的路径(因此,解决方案是__dirname): 在Node.js中,我如何分辨`this`模块的路径?
~~~
更好的办法是获取模块的已加载模块信息
Answers:
如果我正确理解您的问题,则应使用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"));
package.json
文件非常聪明的答案。您不应该使用path.join('moduleName', 'package.json')
Windows兼容吗?
require.resolve
与平台无关,就像require
不需要使用它一样path.join
const path = require('path');
使用前不要忘记添加path.dirname
。
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
。不确定是否与它有任何关系...
type: module
,显然package.json
必须在该exports
字段中显式公开它。我认为Node的新ESM功能不会require
像往常一样阻止解析路径,但显然可以。
仅供参考,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文件并解决了我的问题。
我希望我能正确理解您的需求:获取某个模块的入口点文件。假设您要获取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
等等,结果是它在我项目的父文件夹中,即在我的项目根文件夹之外:
$pwd
/Users/admin/Projects/Node/myProject
$ ls ../../node_modules/myModule/
所以你不能避免rm -rf ../../node_modules/myModule/
和新鲜npm install
。
我可以争辩说,没有人指示npm
扫描我的计算机以查找应该在其运行的项目根文件夹或默认模块搜索路径之外的其他模块。
在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
字段包含什么。