You can test if the module was run directly or require()’d

Any Python developers out there? It’s quite common to see (and use) the Python module test to see if it was run directly or loaded by doing a simple conditional test __name__ == '__main__' . Node.js has almost an identical feature, except the conditional test looks is require.main === module . Here’s a quick sample…

// 1.js if (require.main === module) {

console.log('1.js was run directly!');

}

else {

console.log('1.js was require()\'d');

} const two = require('./2'); // 2.js if (require.main === module) {

console.log('2.js was run directly!');

}

else {

console.log('2.js was require()\'d');

}

Running node 1 (you don’t need to include the filename hint see below for why) you get the output…

1.js was run directly!

2.js was require()’d

When would this come in handy? Say you write a module that can be run directly (i.e. node your-module ) but it also has great functionality that might be consumed by another module. You’ll want to use this conditional test to determine if any action should be taken for the former condition.

You don’t have to specify the ‘.js’ (or ‘.json’) extension

Node.js doesn’t require (err… confusing choice of words?) that you specify a file extension when loading modules provided the destination file has one of the following extensions: js , json , node (the *.node extension is for binary addons). This is perfectly fine, we don’t have to specify require('./2.js') , we can shorten that a bit…

// 1.js const two = require('./2');

console.log(two.message); // 2.js exports.message = "hi from 2.js!";

The output of this is the expected hi from 2.js! message. But… what happens if there are multiple modules with the same name but differing extension? In other words, what if in the same directory there was a file named 2.json with the following content…

{

"message": "hi from 2.json!"

}

The require('./2') call will look for the 2.js file first. If it finds it, it’ll use it. If not, then it’ll try to find the 2.json file.

You can load a directory (sorta)

I have noticed this one picking up in popularity. If you try to load a directory, Node.js is actually quite ok with that!… provided that directory either has a package.json file explicitly stating a main property set to a filename for Node.js to load. If not that, then the directory should include an index.<ext> file where ext is one of the three accepted implicit loading extensions js , json , or node . Here’s an example of this…

// 1.js const dirIndex = require('./mydir'); // mydir/index.js console.log('hello from mydir/index.js!');

Running node 1 the output is the expected hello from mydir/index.js! . This is because we require()’d a directory, and Node.js found an index.js file in that directory and loaded that file itself.

This is a huge convenience and readability factor when the consumer doesn’t need to know the directory’s structure or care about it at all: The directory itself can be a form of code containerization.

Consumed modules are cached

What would you expect the output from this to be?

// 1.js const two = require('./2');

console.log(two.myDateTime); setTimeout(() => {

const twoAgain = require('./2');

console.log(twoAgain.myDateTime);

}, 2000); // 2.js exports.myDateTime = Date().toLocaleString();

If you guessed that the outputted date/time strings were the exact same, then you were correct! But why is this? Node.js should’ve loaded the module twice, roughly two seconds apart, right? Nope! Here’s why: Node.js caches loaded modules, which is what we are seeing here. Date().toLocaleString() was only run once, and Node.js cached it to assign the value to two.myDateTime and then subsequently the same value to twoAgain.myDateTime .

exports is just a reference to module.exports!

I saved this one for last because I think it is the source of tons of confusion. I see this all over the place, “when do I use exports or when do I need to do module.exports ?”. When you finally realize this simple fact, you’ll never need to memorize anything or wonder this again: exports is just a reference to module.exports .

console.log(`exports is module.exports is a ${exports === module.exports} statement`);

Run that, you get a dose of truth: exports is module.exports is a true statement . Not proof enough for you?

exports.message = 'hello world'; console.log(`exports.message is ${exports.message}`);

console.log(`module.exports.message is ${module.exports.message}`); module.exports.anotherMessage = 'hey universe'; console.log(`exports.anotherMessage is ${exports.anotherMessage}`);

console.log(`module.exports.anotherMessage is ${module.exports.anotherMessage}`);

Low and behold, you see the following output…

exports.message is hello world module.exports.message is hello world exports.anotherMessage is hey universe module.exports.anotherMessage is hey universe

There’s a catch here, though. Seeing how exports is just a reference to module.exports you’ll have undesired behavior if you ever did exports = ... . At that point, exports will no longer be a reference to module.exports and that’s most definitely not your intended result.

Summary

It’s so easy and comfortable to just gloss over what appears to be simple. But it is worth taking the time to do some research on some of the nooks and crannies of even the simplest things… you’ll find that they have some mysterious and cool capabilities that you didn’t already know! I hope this blog post enlightened a few of those points about Node.js modules.