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

dwh*_*ieb 10 javascript node.js node-modules es6-modules

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

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

Cas*_*mir 29

使用

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

有关详细信息,请参阅MDN 文档import.meta

2021 年 9 月 27 日更新

更好地使用pathToFileURL它在 Unix 与 Windows 上正确处理前/后斜杠(通过Rich Harris

import { pathToFileURL } from 'url'

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


gus*_*laj 10

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

这些脚本将在文件夹中进行符号链接node_modules/.bin。这些可以通过npx或作为在scripts-object in中定义的脚本来调用package.jsonprocess.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 not imported by another file.
}
Run Code Online (Sandbox Code Playgroud)

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


Ber*_*rgi 6

没有 - 但(它仍然是实验性的!)。尽管普遍的意见是这样的检查无论如何都是不好的做法,您应该只为库和可执行文件提供单独的脚本,但有一个想法import.meta.main为此目的提供布尔属性。

  • 这似乎有效:``if (import.meta.url === `file://${process.argv[1]}`) // 模块未导入,而是直接调用``。 (2认同)