require経由で呼び出されたか、コマンドラインで直接呼び出されたかを検出します


298

Node.JSファイルがSH:node path-to-fileまたはJS を使用して呼び出されたかどうかをどのように検出できますか?require('path-to-file')

これは、Perlでの前の質問と同等のNode.JSです。requireでロードされなかった場合にのみ、Perlスクリプトを実行するにはどうすればよいですか?


回答:


471
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


3
これを回避する方法はありますか?これを行うコード(私は制御できません)がありますが、require()して、直接呼び出されたかのように動作させる必要があります。基本的に、私はそのテストを使用して何かが直接呼び出されたと考えるように騙す必要があります。
ケビン

2
私はこのことについて知らない@Kevin require()が、あなたはおそらく実行し、ファイルをインポートするのいずれかでそれを行うことができeval、その上、または実行してrequire('child_process').exec('node the_file.js')
MalcolmOcean

Node.jsでESモジュールを使用する場合、es-mainパッケージを使用して、モジュールが直接実行されたかどうかを確認できます。
Tim Schaub

91

別のわずかに短い方法があります(前述のドキュメントでは概説されていません)。

var runningAsScript = !module.parent;

このすべてが内部でどのように機能するかについては、このブログ投稿で詳しく説明しました。


+1、私はこれが好きですが、受け入れられた回答を切り替える前にためらいます。:)
ブライアンフィールド

8
私が指摘したように、文書化されている公式の方法は、@ nicolaskruchtenで概説されている方法です。これは単なる代替手段であり、受け入れられた回答を切り替える必要はありません。どちらも機能します。
Thorsten Lorenz

10
文書化された方法ではなく、これを使用する必要がありました。node script.jsしかし、ではありませんcat script.js | node。この方法は両方で機能します。
Tim Malone

9

説明で使用されている用語に少し混乱しました。だから私はいくつかの簡単なテストをしなければなりませんでした。

これらは同じ結果をもたらすことがわかりました:

var isCLI = !module.parent;
var isCLI = require.main === module;

そして、他の混乱した人々のために(そして質問に直接答えるために):

var isCLI = require.main === module;
var wasRequired = !isCLI;

5

Pythonと同じように、私はいつもこのくだらないコードスニペットの書き方を思い出そうとしています。それで、私はそのための単純なモジュールを作成することにしました。呼び出し元のモジュール情報にアクセスするのは簡単ではないため、開発に少し時間がかかりましたが、それがどのように行われるかを確認するのは楽しかったです。

したがって、アイデアはモジュールを呼び出し、呼び出し元のモジュールがメインモジュールであるかどうかを尋ねることです。呼び出し元関数のモジュールを理解する必要があります。私の最初のアプローチは、受け入れられた答えのバリエーションでした:

module.exports = function () {
    return require.main === module.parent;
};

しかし、それが機能するとは限りません。私たちをメモリにロード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;
};

今私たちはできる:

if (require("./is-main-module")()) {  // notice the `()` at the end
    // do something
} else {
    // do something else
}

またはもっと読みやすい:

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

if (isMainModule()) {
    // do something
} else {
    // do something else
}

忘れられない :-)


2
とてもかっこいい。一般的なコードスニペットが1つの名前に省略されているときは、とても気に入っています。微調整:return require.main /*this is undefined if we started node interactively*/ && require.main.filename === callerModuleName;
masterxilo 2018

4

ES6モジュールを使用している場合は、これを試してください。

if (process.mainModule.filename === __filename) {
  console.log('running as main module')
}

2
がらくた、私process.mainModuleundefined
datdinhquoc 2018年

1
GHOSHHHH、私はこれを.mjsファイルでチェックする必要があります
datdinhquoc 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.