从 Node 中的命令行检测 ES 模块是否为 运行

detect whether ES Module is run from command line in Node

在 Node 中使用 CommonJS 模块时,您可以使用 require.main === module.

从命令行检测脚本是否正在 运行

在 Node 中使用 ES 模块(使用 --experimental-modules 标志)时,检测脚本是否从命令行 运行 的等效方法是什么?

有 none - 但是(仍处于实验阶段!)。尽管普遍的意见是这样的检查无论如何都是一种不好的做法,您应该只为库和可执行文件提供单独的脚本,there is an idea to provide a boolean <a href="https://github.com/tc39/proposal-import-meta#importmeta" rel="noreferrer">import.meta</a>.main 属性 为此目的。

module 全局变量将在 CommonJS 中定义,但不会存在于 全部在 ES 模块中。是的,那里有一个不一致的地方,那就是 ES 模块是 没有的东西有module个变量。

您可以通过查看 typeof v 是否为字符串来检查未定义的变量 (不是值!)'undefined'.

变成:

const inCommonJs = typeof module !== 'undefined';

console.log(`inCommonJs = ${inCommonJs}`);

如果我们将确切的代码放入 .cjs.mjs 文件中,我们会得到正确的答案:

$ node foo.mjs
inCommonJs = false
$ cp foo.mjs foo.cjs
$ node foo.cjs
inCommonJs = true

使用

if (import.meta.url === `file://${process.argv[1]}`) {
  // module was not imported but called directly
}

详情见MDN docs on import.meta

2021 年 9 月 27 日更新

可能更稳健,但涉及 extra import (via Rich Harris)

import url from 'url'

if (import.meta.url === url.pathToFileURL(process.argv[1]).href) {
  // module was not imported but called directly
}

我喜欢import.meta.url === `file://${process.argv[1]}` ,但是在Windows里面bashshell里面不行。这是仅检查基本名称的替代方法:

const runningAsScript = import.meta.url.endsWith(path.basename(process.argv[1]));

好像有一个documented way to do this now:

if (require.main === module) {
    console.log('executed directly');
    . . .
}

其他答案接近,但会错过一个非常典型的用例的标记 - package.json 文件中 bin 属性 公开的 cli 脚本。

这些脚本将在 node_modules/.bin 文件夹中进行符号链接。这些可以通过 npx 或作为在 package.json 中的 scripts 对象中定义的脚本调用。 process.argv[1] 在这种情况下将是符号链接,而不是 import.meta.url

引用的实际文件

此外,我们需要将文件路径转换为实际的file://-url,否则在不同平台上将无法正常工作。

import { realpathSync } from "fs";
import { pathToFileURL } from "url";

function wasCalledAsScript() {
    // We use realpathSync to resolve symlinks, as cli scripts will often
    // be executed from symlinks in the `node_modules/.bin`-folder
    const realPath = realpathSync(process.argv[1]);

    // Convert the file-path to a file-url before comparing it
    const realPathAsUrl = pathToFileURL(realPath).href;
  
    return import.meta.url === realPathAsUrl;
}

if (wasCalledAsScript()) {
  // module was executed and imported by another file.
}

我本来可以将此作为对已接受答案的评论发布的,但显然我不允许使用新帐户发表评论。