Wykryj, czy wywołanie wymaga lub bezpośrednio z wiersza poleceń

Odpowiedzi:

471
if (require.main === module) {
    console.log('called directly');
} else {
    console.log('required as a module');
}

Zobacz dokumentację tego tutaj: https://nodejs.org/docs/latest/api/modules.html#modules_accessing_the_main_module

nicolaskruchten
źródło
3
Czy jest jakiś sposób na obejście tego? Mam kod (nad którym nie mam kontroli), który to robi, ale muszę go wymagać (), aby działał tak, jakby był wywoływany bezpośrednio. Zasadniczo muszę oszukać coś, co wykorzystuje ten test, do myślenia, że ​​to się nazywa bezpośrednio.
Kevin,
2
@Kevin Nie wiem, jak to zrobić require(), ale możesz to zrobić, importując plik, a następnie uruchamiając evalgo, lub uruchamiającrequire('child_process').exec('node the_file.js')
MalcolmOcean
Korzystając z modułów ES z Node.js, możesz użyć es-mainpakietu, aby sprawdzić, czy moduł został uruchomiony bezpośrednio.
Tim Schaub
91

Istnieje inna, nieco krótsza droga (nie wymieniona we wspomnianych dokumentach).

var runningAsScript = !module.parent;

W tym wpisie na blogu przedstawiłem więcej szczegółów na temat tego, jak to wszystko działa pod maską .

Thorsten Lorenz
źródło
+1, podoba mi się to bardziej, ale waham się przed zmianą zaakceptowanych odpowiedzi. :)
Bryan Field
8
Jak wskazałem, oficjalnym sposobem, który jest udokumentowany, jest ten opisany przez @nicolaskruchten. To tylko alternatywa, nie trzeba zmieniać przyjętej odpowiedzi. Oba działają.
Thorsten Lorenz,
10
Musiałem użyć tego raczej niż udokumentowanego - udokumentowany sposób działa np. node script.jsale nie cat script.js | node. Ten sposób działa dla obu.
Tim Malone
9

Byłem trochę zdezorientowany terminologią użytą w wyjaśnieniach. Musiałem więc zrobić kilka szybkich testów.

Odkryłem, że dają one takie same wyniki:

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

A dla innych zdezorientowanych ludzi (i bezpośredniej odpowiedzi na pytanie):

var isCLI = require.main === module;
var wasRequired = !isCLI;
kok
źródło
5

Tak jak w Pythonie, zawsze próbuję sobie przypomnieć, jak napisać ten cholerny fragment kodu. Postanowiłem więc stworzyć dla niego prosty moduł. Zajęło mi to trochę czasu, ponieważ dostęp do informacji o module dzwoniącym nie jest łatwy, ale fajnie było zobaczyć, jak można to zrobić.

Pomysł polega więc na wywołaniu modułu i zapytaniu go, czy moduł wywołujący jest główny. Musimy ustalić moduł funkcji dzwoniącego. Moje pierwsze podejście było odmianą przyjętej odpowiedzi:

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

Ale to nie gwarantuje, że zadziała. module.parentwskazuje moduł, który załadował nas do pamięci, a nie ten, który nas woła. Jeśli to moduł wywołujący załadował ten moduł pomocnika do pamięci, nie ma sprawy. Ale jeśli nie, jesteśmy bezradni. Musimy więc spróbować czegoś innego. Moim rozwiązaniem było wygenerowanie śladu stosu i pobranie stąd nazwy modułu dzwoniącego:

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;
};

Teraz możemy zrobić:

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

Lub bardziej czytelny:

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

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

Niemożliwe do zapomnienia :-)

Lucio Paiva
źródło
2
Bardzo fajny. Uwielbiam to, gdy wspólne fragmenty kodu są skracane do jednej nazwy. Mała korekta:return require.main /*this is undefined if we started node interactively*/ && require.main.filename === callerModuleName;
masterxilo
4

Wypróbuj to, jeśli używasz modułów ES6:

if (process.mainModule.filename === __filename) {
  console.log('running as main module')
}
Kebot
źródło
2
bzdury, mój process.mainModulejestundefined
datdinhquoc
1
GHOSHHHH, muszę to sprawdzić w moim pliku
.mjs