Node.js 检测是通过require调用还是直接通过命令行调用
如何检测是否使用SH:Node.js 检测是通过require调用还是直接通过命令行调用,node.js,require,Node.js,Require,如何检测是否使用SH:节点路径到文件或JS:require('path-to-file')调用了Node.JS文件 这是Node.JS,相当于我在Perl中的上一个问题: 请参阅此处的文档:还有另一种略短的方法(未在提及的文档中列出) var runningAsScript=!模块。父模块 我在中概述了关于这一切如何在引擎盖下工作的更多细节。我被解释中使用的术语弄糊涂了。所以我必须做一些快速测试 我发现这些方法产生了相同的结果: var isCLI = !module.parent; var i
节点路径到文件
或JS:require('path-to-file')
调用了Node.JS文件
这是Node.JS,相当于我在Perl中的上一个问题:
请参阅此处的文档:还有另一种略短的方法(未在提及的文档中列出)
var runningAsScript=!模块。父模块代码>
我在中概述了关于这一切如何在引擎盖下工作的更多细节。我被解释中使用的术语弄糊涂了。所以我必须做一些快速测试
我发现这些方法产生了相同的结果:
var isCLI = !module.parent;
var isCLI = require.main === module;
对于其他困惑的人(直接回答问题):
我总是试图回忆如何编写这个该死的代码片段,所以我决定为它创建一个简单的模块。我花了一点时间才让它工作起来,因为访问调用方的模块信息并不简单,但看到如何做到这一点很有趣
因此,我们的想法是调用一个模块,并询问它调用方模块是否是主模块。我们必须找出调用函数的模块。我的第一种方法是接受答案的一种变体:
module.exports = function () {
return require.main === module.parent;
};
但这并不能保证奏效<代码>模块。父级
指向将我们加载到内存中的模块,而不是调用我们的模块。如果是调用方模块将这个助手模块加载到内存中,我们就可以了。但如果不是,它就不会起作用。所以我们需要试试别的。我的解决方案是生成堆栈跟踪并从中获取调用方的模块名:
module.exports = function () {
// generate a stack trace
const stack = (new Error()).stack;
// the third line refers to our caller
const stackLine = stack.split("\n")[2];
// extract the module name from that line
const callerModuleName = /\((.*):\d+:\d+\)$/.exec(stackLine)[1];
return require.main.filename === callerModuleName;
};
将其另存为is main module.js
,现在您可以执行以下操作:
const isMainModule = require("./is-main-module");
if (isMainModule()) {
console.info("called directly");
} else {
console.info("required as a module");
}
这更容易记住。如果您使用的是ES6模块,请尝试以下操作:
if (process.mainModule.filename === __filename) {
console.log('running as main module')
}
首先,让我们更好地定义问题。我的假设是,您真正需要的是脚本是否拥有
process.argv
(即脚本是否负责处理process.argv
)。考虑到这个假设,下面的代码和测试是准确的
module.parent
工作得很好,但由于一些原因,它被弃用(一个模块可能有多个父模块,在这种情况下,module.parent
仅代表第一个父模块),因此使用以下经得起未来考验的条件覆盖所有情况:
if (
typeof process === 'object' && process && process.argv
&& (
(
typeof module === 'object' && module
&& (
!module.parent
|| require.main === module
|| (process.mainModule && process.mainModule.filename === __filename)
|| (__filename === "[stdin]" && __dirname === ".")
)
)
|| (
typeof document === "object"
&& (function() {
var scripts = document.getElementsByTagName("script");
try { // in case we are in a special environment without path
var normalize = require("path").normalize;
for (var i=0,len=scripts.length|0; i < len; i=i+1|0)
if (normalize(scripts[i].src.replace(/^file:/i,"")) === __filename)
return true;
} catch(e) {}
})()
)
)
) {
// this module is top-level and invoked directly by the CLI
console.log("Invoked from CLI");
} else {
console.log("Not invoked from CLI");
}
if(
进程类型==='object'&&process&&process.argv
&& (
(
模块类型==='object'&&module
&& (
!module.parent
||require.main==模块
||(process.mainModule&&process.mainModule.filename====\uu文件名)
||(文件名===“[stdin]”&&&&&&uu目录名===”)
)
)
|| (
文档类型==“对象”
&&(功能(){
var scripts=document.getElementsByTagName(“脚本”);
尝试{//以防我们处于没有路径的特殊环境中
var normalize=需要(“路径”)。normalize;
对于(变量i=0,len=scripts.length | 0;i
在以下所有情况下,它在所有脚本中都能正常工作,并且从不抛出任何错误†:
- 需要脚本(e.x.
)require('./main.js')
- 直接调用脚本(e.x.
)nodejs cli.js
- 预加载另一个脚本(e.x.
)nodejs-r main.js cli.js
- 进入节点CLI的管道(e.x.
)cat CLI.js | nodejs
- 带预加载的管道(e.x.
)cat cli.js | nodejs-r main.js
- 在workers中(e.x.
)新Worker('./Worker.js')
- 在
ed Worker中(e.x.eval
)new Worker('if()…',{eval:true})
- ES6模块内部(e.x.
)nodejs——实验模块cli-ES6.js
- 带预加载的模块(e.x.
)nodejs——实验模块-r main-es6.js cli-es6.js
- 管道式ES6模块(e.x.
)cat cli-ES6.js | nodejs——实验模块
- 管道+预加载模块(e.x.
)cat cli-es6.js | nodejs——实验模块-r main-es6.js
- 在浏览器中(在这种情况下,CLI为false,因为没有
)process.argv
- 在混合浏览器+服务器环境中(例如ElectronJS,在这种情况下,内联脚本和通过
标记加载的所有模块都被视为CLI)
nodejs-r cli.js cli.js
)。通过管道(e.x.cat cli.js | nodejs-r cli.js
)无法解决此问题,因为它会执行两次脚本(一次作为必需模块,一次作为顶级)。我不相信有任何可能的修复方法,因为无法从预加载的脚本中知道主脚本是什么
†理论上,错误可能是从对象的getter内部抛出的(例如,如果有人疯狂地执行
object.defineProperty(globalThis,“process”,{get(){throw 0}});
),但是,在任何环境中,对于代码段中使用的属性,在默认情况下都不会发生这种情况。对于使用ES模块(和节点10.12+)的用户,可以使用import.meta.url
:
从“url”导入{fileURLToPath}
const isRunningDirectlyViaCLI=process.argv[1]==fileURLToPath(import.meta.url)
像require.main
、module.parent
和\uuu dirname
/\uu filename
这样的东西
注意:如果使用ESLint,它可能会阻塞此语法,在这种情况下,您需要将ecmaVersion
设置为11
(2020
)
更多
if (process.mainModule.filename === __filename) {
console.log('running as main module')
}
if (
typeof process === 'object' && process && process.argv
&& (
(
typeof module === 'object' && module
&& (
!module.parent
|| require.main === module
|| (process.mainModule && process.mainModule.filename === __filename)
|| (__filename === "[stdin]" && __dirname === ".")
)
)
|| (
typeof document === "object"
&& (function() {
var scripts = document.getElementsByTagName("script");
try { // in case we are in a special environment without path
var normalize = require("path").normalize;
for (var i=0,len=scripts.length|0; i < len; i=i+1|0)
if (normalize(scripts[i].src.replace(/^file:/i,"")) === __filename)
return true;
} catch(e) {}
})()
)
)
) {
// this module is top-level and invoked directly by the CLI
console.log("Invoked from CLI");
} else {
console.log("Not invoked from CLI");
}