Виявити, якщо викликано через вимагає або безпосередньо командним рядком


298

Як я можу виявити, чи викликався мій файл Node.JS за допомогою SH: node path-to-fileабо JS require('path-to-file'):?

Це еквівалент Node.JS моєму попередньому запитанню в Perl: Як я можу запустити свій скрипт 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
Чи є спосіб обійти це? У мене є код (над яким я не маю контролю), який це робить, але мені потрібно вимагати () його, і він повинен діяти так, ніби він був викликаний безпосередньо. По суті, мені потрібно обдурити те, що використовує цей тест, щоб думати, що це було названо безпосередньо.
Кевін

2
@Kevin Я не знаю, з чим це робити require(), але ти можеш це зробити, або імпортуючи файл, а потім запустивши evalйого, або запустившиrequire('child_process').exec('node the_file.js')
MalcolmOcean

Використовуючи модулі ES з Node.js, ви можете за допомогою es-mainпакета перевірити, чи модуль запускався безпосередньо.
Тім Шауб

91

Існує ще один, трохи коротший спосіб (не окреслений у згаданих документах).

var runningAsScript = !module.parent;

Я детальніше розповів про те, як це все працює під кришкою в цій публікації блогу .


+1, мені це більше подобається, але я вагаюся перед тим, як переключити прийняті відповіді. :)
Брайан Філд

8
Як я зазначив, офіційним способом, який задокументований, є той, який @nicolaskruchten окреслено. Це лише альтернатива, не потрібно перемикати прийняту відповідь. Обидва працюють.
Торстен Лоренц

10
Мені довелося скористатися цим, а не задокументованим способом - документований спосіб працює, наприклад. node script.jsале ні cat script.js | node. Цей спосіб працює для обох.
Тім Малоун

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
Дуже круто. Мені подобається, коли загальні фрагменти коду скорочуються до одного імені. Невелике регулювання:return require.main /*this is undefined if we started node interactively*/ && require.main.filename === callerModuleName;
masterxilo

4

Спробуйте це, якщо ви використовуєте модулі ES6:

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

2
Лайно, мій process.mainModuleєundefined
datdinhquoc

1
GHOSHHHH, мені потрібно перевірити це у своєму .mjs-файлі
datdinhquoc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.