How to detect if a nodejs module is run as a script
Quick Answer
First option, recommended by the module docs
var runningAsScript = require.main === module;
Second option, a bit shorter
var runningAsScript = !module.parent;
If you want to find out how the second option works, read on.
The NodeJS Module Parameter
Every nodejs module gets a module
variable injected when it is evaluated. So module
is not global, but instead a
parameter that is passed into a self invoking function that the module is wrapped with.
It looks like this:
(function (exports, require, module, __filename, __dirname) {
// module code here
})();
Quoting from the module documentation, the parent of the module is:
The module that required this one.
So it follows that a module will have no parent if it is executed as a script.
A Simple Example
We are going to use replpad to load
some code and inscpect things. You can follow along by cloning this blog git clone
git://github.com/thlorenz/thlorenz.com-blog.git
.
Inside the parent-module/snippets
folder you will find the sample files I use below.
First we create the module that will be the parent foo.js
.
var bar = require('./bar');
The child, that is required by it, bar.js
looks like this:
exports.module = module;
In order to play around with them, lets fire up replpad:
➜ parent-module replpad .
Loading replpad config from: /Users/thlorenz/.config/replpad/config.js
Started watching: snippets/bar.js
Started watching: snippets/foo.js
Started watching: snippets/script.js
Watching [3 files]
replpad v0.5.0
node v0.8.16 | MacBook-Air.local | 4 cpus | darwin platform | v8 v3.11.10.25 | uv v0.8
plugins: vim | matchtoken
If in doubt, enter .help
pad >
Now we can open foo.js
in an editor and save it in order to have replpad evaluate it. At this point we have access to
bar's module since bar exports it.
pad > bar.module
{ id: '[..]/thlorenz.com-blog/parent-module/snippets/bar.js',
exports: { module: [Circular] },
parent:
{ id: '[..]/thlorenz.com-blog/parent-module/snippets/foo.js',
exports: {},
parent: undefined,
filename: '[..]/thlorenz.com-blog/parent-module/snippets/foo.js',
loaded: false,
children: [ [Circular] ],
paths:
[ [ .. ],
/Users/node_modules',
'/node_modules' ] },
filename: '[..]/thlorenz.com-blog/parent-module/snippets/bar.js',
loaded: true,
children: [],
paths:
[ [ .. ],
'/Users/node_modules',
'/node_modules' ] }
pad >
This prints all the module's properties (paths are shortened). As you can see bar's parent is foo, since that is the module that required it. However bar has not required any module itself and therefore has no children.
Note that foo's children are output as [Circular]
which makes sense.
We can also print foo's module information, using the fact that foo's module is actually bar's parent.
pad > bar.module.parent
{ id: '[..]/thlorenz.com-blog/parent-module/snippets/foo.js',
exports: {},
parent: undefined,
filename: '[..]/thlorenz.com-blog/parent-module/snippets/foo.js',
loaded: false,
children:
[ { id: '[..]/thlorenz.com-blog/parent-module/snippets/bar.js',
exports: { module: [Circular] },
parent: [Circular],
filename: '[..]/thlorenz.com-blog/parent-module/snippets/bar.js',
loaded: true,
children: [],
paths:
[ [ .. ],
'/Users/node_modules',
'/node_modules' ] } ],
paths:
[ [ .. ],
'/Users/node_modules',
'/node_modules' ] }
Now we can see, that bar is indeed the only child of foo and that foo itself has no parent.
Another interesting thing to realize is, that bar
itself is actually the same object as the exports of its module:
pad > bar === bar.module.exports
true
Running a module as a script
As a final proof of concept lets run a
script from the command line and make sure that it really has no parent. I created one in the snippets
folder:
var util = require('util');
exports.hello = 'world';
console.log(util.inspect(module, false, 5, true));
Here is the output when we run it:
➜ parent-module node snippets/script.js
{ id: '.',
exports: { hello: 'world' },
parent: null,
filename: '[..]/thlorenz.com-blog/parent-module/snippets/script.js',
loaded: false,
children: [],
paths:
[ [ .. ].
'/Users/node_modules',
'/node_modules' ] }
As we can see, its parent
is null
since no other module required it.