Node.JS:检测是否通过require调用或直接通过命令行调用

Bry*_*eld 281 require node.js

如何检测我的Node.JS文件是否使用SH:node path-to-file或JS 调用require('path-to-file')

这是Node.JS等同于我在Perl中的上一个问题:如果它没有加载require,我怎么能运行我的Perl脚本?

nic*_*ten 429

if (require.main === module) {
    console.log('called directly');
} else {
    console.log('required as a module');
}
Run Code Online (Sandbox Code Playgroud)

请参阅此处的文档:https://nodejs.org/docs/latest/api/modules.html#modules_accessing_the_main_module

  • 有没有办法解决这个问题?我有代码(我无法控制)执行此操作,但我需要()它并使其行为就像直接调用它一样.基本上,我需要愚弄使用该测试的东西,以为它被直接调用. (3认同)
  • 在 Node.js 中使用 ES 模块时,可以使用 [`es-main`](https://www.npmjs.com/package/es-main) 包来检查模块是否直接运行。 (3认同)
  • @Kevin我不知道用`require()`来做这个,但是你可以用导入文件然后运行`eval`或者运行`require('child_process')来执行它.exec('节点the_file.js')` (2认同)

Tho*_*enz 84

还有另一种略短的方法(在上述文档中没有概述).

var runningAsScript = !module.parent;

我在这篇博客文章中概述了有关这一切是如何工作的更多细节.

  • 我不得不使用这个而不是记录的方式 - 记录的方式适用于例如.`node script.js`但不是`cat script.js | node`.这种方式适用于两者. (9认同)
  • 正如我所指出的,记录的官方方式是@nicolaskruchten概述.这只是一种替代方案,无需切换接受的答案.两者都有效. (8认同)
  • 请注意,`module.parent` 已被弃用([自 v14.6.0, v12.19.0](https://nodejs.org/api/modules.html#moduleparent)),因此您应该避免使用它。 (3认同)

Luc*_*iva 8

我总是发现自己在回想如何编写这个该死的代码片段,所以我决定为它创建一个简单的模块。因为访问调用者的模块信息并不简单,所以我花了一点时间让它工作,但是看看它是如何完成的很有趣。

所以这个想法是调用一个模块并询问它是否调用者模块是主要的。我们必须弄清楚调用者函数的模块。我的第一种方法是接受答案的变体:

module.exports = function () {
    return require.main === module.parent;
};
Run Code Online (Sandbox Code Playgroud)

但这并不能保证有效。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;
};
Run Code Online (Sandbox Code Playgroud)

将其另存为is-main-module.js,现在您可以执行以下操作:

const isMainModule = require("./is-main-module");

if (isMainModule()) {
    console.info("called directly");
} else {
    console.info("required as a module");
}
Run Code Online (Sandbox Code Playgroud)

哪个更容易记住。

  • 很酷。我喜欢将常见的代码片段缩写为一个名称。小调整:`return require.main /*如果我们以交互方式启动节点,这是未定义的*/ && require.main.filename === callerModuleName;` (2认同)

小智 8

如果你使用 ES6 模块,试试这个:

if (process.mainModule.filename === __filename) {
  console.log('running as main module')
}
Run Code Online (Sandbox Code Playgroud)

  • 废话,我的`process.mainModule` 是`undefined` (5认同)

bob*_*bob 6

我对解释中使用的术语感到有些困惑。所以我不得不做一些快速测试。

我发现它们产生相同的结果:

var isCLI = !module.parent;
var isCLI = require.main === module;
Run Code Online (Sandbox Code Playgroud)

对于其他困惑的人(并直接回答问题):

var isCLI = require.main === module;
var wasRequired = !isCLI;
Run Code Online (Sandbox Code Playgroud)


小智 5

对于使用 ES 模块(和 Node 10.12+)的用户,您可以使用import.meta.url

import { fileURLToPath } from 'url'

const isRunningDirectlyViaCLI = process.argv[1] === fileURLToPath(import.meta.url)
Run Code Online (Sandbox Code Playgroud)

诸如require.main,module.parent__dirname/之类的东西__filename 在 ESM 中不可用

注意:如果使用 ESLint,它可能会阻塞在这种语法上,在这种情况下,您需要更新到 ESLint^7.2.0并将您的ecmaVersion上调到11( 2020)。

更多信息:process.argvimport.meta.url