从 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
}
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.
}
我本来可以将此作为对已接受答案的评论发布的,但显然我不允许使用新帐户发表评论。
在 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
}
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.
}
我本来可以将此作为对已接受答案的评论发布的,但显然我不允许使用新帐户发表评论。