Détecter si appelé via require ou directement par ligne de commande

Réponses:

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

Voir la documentation à ce sujet ici: https://nodejs.org/docs/latest/api/modules.html#modules_accessing_the_main_module

nicolaskruchten
la source
3
Y a-t-il un moyen de contourner cela? J'ai du code (sur lequel je n'ai pas de contrôle) qui fait cela, mais je dois l'exiger () et le faire agir comme s'il était appelé directement. Fondamentalement, je dois tromper quelque chose qui utilise ce test en pensant qu'il a été appelé directement.
Kevin
2
@Kevin Je ne sais pas comment faire cela require(), mais vous pouvez peut-être le faire soit en important le fichier puis en l'exécutant eval, soit en exécutantrequire('child_process').exec('node the_file.js')
MalcolmOcean
Lorsque vous utilisez des modules ES avec Node.js, vous pouvez utiliser le es-mainpackage pour vérifier si un module a été exécuté directement.
Tim Schaub
91

Il existe une autre méthode, légèrement plus courte (non décrite dans les documents mentionnés).

var runningAsScript = !module.parent;

J'ai décrit plus en détail comment tout cela fonctionne sous le capot dans cet article de blog .

Thorsten Lorenz
la source
+1, j'aime mieux cela, mais j'hésiterai avant de changer de réponse acceptée. :)
Bryan Field
8
Comme je l'ai indiqué, la manière officielle qui est documentée est celle décrite par @nicolaskruchten. Ceci est juste une alternative, pas besoin de changer de réponse acceptée. Les deux fonctionnent.
Thorsten Lorenz
10
J'ai dû utiliser cela plutôt que la méthode documentée - la méthode documentée fonctionne par exemple. node script.jsmais pas cat script.js | node. Cette méthode fonctionne pour les deux.
Tim Malone
9

J'étais un peu confus par la terminologie utilisée dans les explications. J'ai donc dû faire quelques tests rapides.

J'ai trouvé que ceux-ci produisent les mêmes résultats:

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

Et pour les autres confus (et pour répondre directement à la question):

var isCLI = require.main === module;
var wasRequired = !isCLI;
bob
la source
5

Tout comme en Python, je me retrouve toujours à essayer de me rappeler comment écrire ce putain d'extrait de code. J'ai donc décidé de créer un module simple pour cela. Cela m'a pris un peu de temps à développer, car l'accès aux informations du module de l'appelant n'est pas simple, mais c'était amusant de voir comment cela pourrait être fait.

L'idée est donc d'appeler un module et de lui demander si le module appelant est le principal. Nous devons comprendre le module de la fonction appelant. Ma première approche a été une variation de la réponse acceptée:

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

Mais cela n'est pas garanti de fonctionner. module.parentpointe vers le module qui nous a chargés en mémoire, pas celui qui nous appelle. Si c'est le module appelant qui a chargé ce module d'assistance en mémoire, c'est bien. Mais si ce n'était pas le cas, nous sommes impuissants. Nous devons donc essayer autre chose. Ma solution était de générer une trace de pile et d'obtenir le nom du module de l'appelant à partir de là:

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

Maintenant, nous pouvons faire:

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

Ou plus lisible:

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

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

Inoubliable :-)

Lucio Paiva
la source
2
Très cool. J'adore quand les extraits de code communs sont abrégés en un seul nom. Petit ajustement:return require.main /*this is undefined if we started node interactively*/ && require.main.filename === callerModuleName;
masterxilo
4

Essayez ceci si vous utilisez des modules ES6:

if (process.mainModule.filename === __filename) {
  console.log('running as main module')
}
Kebot
la source
2
merde, mon process.mainModuleestundefined
datdinhquoc
1
GHOSHHHH, j'ai besoin de vérifier cela dans mon fichier
.mjs