我如何检测我的node .JS文件是否被调用使用SH:node path-to file或JS:require('path-to file')?
这是Node.JS等价于我之前在Perl中的问题:我怎么能运行我的Perl脚本,如果它没有加载require?
我如何检测我的node .JS文件是否被调用使用SH:node path-to file或JS:require('path-to file')?
这是Node.JS等价于我之前在Perl中的问题:我怎么能运行我的Perl脚本,如果它没有加载require?
当前回答
还有另一种稍短的方法(没有在提到的文档中列出)。
var runningAsScript = !module.parent;
我在这篇博客文章中概述了更多关于这些工作原理的细节。
其他回答
if (require.main === module) {
console.log('called directly');
} else {
console.log('required as a module');
}
请在这里查看相关文档:https://nodejs.org/docs/latest/api/modules.html#modules_accessing_the_main_module
还有另一种稍短的方法(没有在提到的文档中列出)。
var runningAsScript = !module.parent;
我在这篇博客文章中概述了更多关于这些工作原理的细节。
首先,让我们更好地定义问题。我的假设是,您真正要寻找的是您的脚本是否拥有进程。Argv(即你的脚本是否负责处理process.argv)。记住这个假设,下面的代码和测试是准确的。
模块。Parent工作得非常出色,但由于很好的原因(一个模块可能有多个父模块,在这种情况下,模块。父类只代表第一个父类),所以使用下面的future-proof条件来覆盖所有情况:
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");
}
它在以下所有情况下的所有脚本中都正确工作,并且永远不会抛出任何错误†:
Requiring the script (e.x. require('./main.js')) Directly invoking the script (e.x. nodejs cli.js) Preloading another script (e.x. nodejs -r main.js cli.js) Piping into node CLI (e.x. cat cli.js | nodejs) Piping with preloading (e.x. cat cli.js | nodejs -r main.js) In workers (e.x. new Worker('./worker.js')) In evaled workers (e.x. new Worker('if (<test for CLI>) ...', {eval: true})) Inside ES6 modules (e.x. nodejs --experimental-modules cli-es6.js) Modules with preload (e.x. nodejs --experimental-modules -r main-es6.js cli-es6.js) Piped ES6 modules (e.x. cat cli-es6.js | nodejs --experimental-modules) Pipe+preload module (e.x. cat cli-es6.js | nodejs --experimental-modules -r main-es6.js) In the browser (in which case, CLI is false because there is no process.argv) In mixed browser+server environments (e.x. ElectronJS, in which case both inline scripts and all modules loaded via <script> tags are considered CLI)
唯一不工作的情况是当你预加载顶级脚本(例如nodejs -r cli.js cli.js)。这个问题不能通过管道(例如cat cli.js | nodejs -r cli.js)来解决,因为这会执行两次脚本(一次作为必需的模块,一次作为顶级模块)。我不相信有任何可能的解决办法,因为没有办法知道什么主脚本将从一个预加载的脚本。
†理论上,错误可能会从对象的getter内部抛出(例如,如果有人疯狂地执行object . defineproperty (globalThis, "process", {get(){throw 0}});),然而,对于任何环境中代码片段中使用的属性,在默认情况下这永远不会发生。
对于那些使用ES模块(和Node 10.12+)的用户,你可以使用import.meta.url:
import path from 'path';
import { fileURLToPath } from 'url'
const nodePath = path.resolve(process.argv[1]);
const modulePath = path.resolve(fileURLToPath(import.meta.url))
const isRunningDirectlyViaCLI = nodePath === modulePath
比如require。主要模块。parent和__dirname/__filename在ESM中不可用。
注意:如果使用ESLint,它可能会阻塞在这个语法上,在这种情况下,你需要更新到ESLint ^7.2.0,并把你的ecmaVersion调到11(2020)。
更多信息:进程。argv, import.meta.url
我对解释中使用的术语有点困惑。所以我做了几个快速检查。
我发现它们产生了相同的结果:
var isCLI = !module.parent;
var isCLI = require.main === module;
对于其他困惑的人(并直接回答这个问题):
var isCLI = require.main === module;
var wasRequired = !isCLI;