Learning Node.js Part 1 – require() and modules

By | January 29, 2014

When I first started learning Node.js, I did what everyone else does: I searched google for “nodejs tutorial”, picked one of the top choices, and followed along. While it was great, I eventually discovered that these tutorials skipped over a very important aspect of Node.js. Specifically, they never really go into how require() and modules work.

As a PHP developer, I understand how require() works very well, at least in PHP. You include a file, it runs through some code in the same scope, and then possibly return some data.

Naturally, I assumed that it would be the same in Node.js… Not quite! In Node.js, require() does in fact work very similar, but it has the whole idea of modules tied into it. That is, each and every file you have is actually a module. I know that doesn’t really say anything (i.e., what’s a module?), so let’s just get to the important stuff:

Directly from the Node.js documentation:

Node has a simple module loading system. In Node, files and modules are in one-to-one correspondence.

Modules are cached after the first time they are loaded. This means (among other things) that every call to require(‘foo’) will get exactly the same object returned, if it would resolve to the same file.

What does this mean? It means that when you call require() on a file, it will return an instance of the module. To be more precise, it will return the same instance every time.

Going back to the previous question, what is a module? Well, when you think about it with the info I just provided, you could say that a module is a global variable. Or, you could say that a module is global object (because everything in javascript is an object). Thus, the module could be a string, number, class, function, or anything else.

Let’s go through an example. Take these three files:

// File: test.js
var apple1 = require('./apple'); 
console.log('apple1 is ' + apple1.getColor()); // outputs red

apple1.setColor('green');
console.log('apple1 is ' + apple1.getColor()); // outputs green

var apple2 = require('./apple');
console.log('apple2 is ' + apple2.getColor()); // outputs green

var test2 = require('./test2');
console.log('test2 = apple3 is' + test2.getColor()); // outputs green
//-----------------------------------
// File: apple.js
function Apple (type) {
  this.color = "red";
  this.getColor = function() {
    return this.color;
  };
  this.setColor = function(newColor) {
    this.color = newColor;
  };
}

module.exports = new Apple;
//-----------------------------------
// File: test2.js
var apple3 = require('./apple');

module.exports = apple3;

//-----------------------------------

Whew! Okay, the code is simple but may be a little hard to follow. Let me explain by explaining the three files:

test.js – the main script file that you can via node test.js.
apple.js – the apple module which returns an object Apple.
test2.js – the test2 module which is a wrapper and also returns an Apple object.

Now, let’s break the code down in steps:

1) Loads apple module into var apple1 and immediately outputs color “red” (defined directly in apple.js)
2) Changes color via apple1.setColor('green'); and outputs color “green”
3) Loads apple module again, this time into var apple2, and outputs .. “green”! This is the important part right here, because the apple module is returning the old, cached instance and not creating a new one!
4) Loads test2 module, which in turn loads the apple module yet again – this time into var apple3 and returns it. Outputs color “green” yet again

As you can see, this is vastly different from PHP. In PHP, you would get a new instance every time and thus get “red”, “green”, and “red” again.

So that’s how require() modules work in Node.js If you have any questions, let me know in the comments below.

One last note: I didn’t mention it explicitly, but it was described in the code. The line module.exports = {{data}} is how you return data from a module. Without it, the script would just run through the code procedurally and not return anything at all. Note, however, that even though it wouldn’t return anything, it could still affect other modules!

More info on this in my next post, so stay tuned!

Leave a Reply

Your email address will not be published. Required fields are marked *