Узел.JS: обнаружение, если вызывается через require или непосредственно с помощью командной строки


Как я могу определить, является ли мой узел.JS файл был вызван с помощью SH:node path-to-file или JS:require('path-to-file')?

это узел.JS эквивалентен моему предыдущему вопросу в Perl: как я могу запустить свой скрипт Perl, только если он не был загружен require?

4 222

4 ответа:

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

смотрите документацию для этого здесь: https://nodejs.org/docs/latest/api/all.html#modules_accessing_the_main_module

есть еще один, немного более короткий путь (не описанный в упомянутых документах).

var runningAsScript = !module.parent;

Я изложил более детально о том, как это все работает под капотом в этот блог.

Я был немного смущен терминологией, используемой в объяснении (Ях). Так что мне пришлось сделать пару быстрых тестов.

я обнаружил, что они дают те же результаты:

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

а для других растерянных людей (и чтобы ответить на вопрос напрямую):

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

как и в 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
}

невозможно забыть :-)