Node.JS: Detect if called through require or direc

2019-01-20 21:38发布

问题:

How can I detect whether my Node.JS file was called using SH:node path-to-file or JS:require('path-to-file')?

This is the Node.JS equivalent to my previous question in Perl: How can I run my Perl script only if it wasn't loaded with require?

回答1:

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

See documentation for this here: https://nodejs.org/docs/latest/api/all.html#modules_accessing_the_main_module



回答2:

There is another, slightly shorter way (not outlined in the mentioned docs).

var runningAsScript = !module.parent;

I outlined more details about how this all works under the hood in this blog post.



回答3:

I was a little confused by the terminology used in the explanation(s). So I had to do a couple quick tests.

I found that these produce the same results:

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

And for the other confused people (and to answer the question directly):

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


回答4:

Just like in Python, I always find myself trying to remember how to write this goddamn code snippet. So I decided to create a simple module for it. It took me a bit to develop since accessing caller's module information isn't straighforward, but it was fun to see how it could be done.

So the idea is to call a module and ask it if the caller module is the main one. We have to figure out the module of the caller function. My first approach was a variation of the accepted answer:

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

But that is not guaranteed to work. module.parent points to the module which loaded us into memory, not the one calling us. If it was the caller module which loaded this helper module into memory, that's fine. But if it wasn't, we're helpless. So we need to try something else. My solution was to generate a stack trace and get the caller's module name from there:

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

Now we can do:

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

Or more readable:

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

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

Impossible to forget :-)



回答5:

Try this if you are using ES6 modules:

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