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


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ą .


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

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 :-)


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')
}

2
bzdury, mój process.mainModulejestundefined
datdinhquoc

1
GHOSHHHH, muszę to sprawdzić w moim pliku
.mjs
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.