Writing modular code is one of my very favorite things to do, so it wasn’t long in my adventure with Node.js before I was trying to understand how to build a custom module. I think I’m finally beginning to grasp exactly how custom modules are typically constructed as well as how they are pulled in as dependencies to my Node application.
First, I’ll create an app.js file from which my experiments will run. For now, I’ll leave app.js empty. Side note: app.js is the typical name of the main file of your new Node.js application.
1 2 3 4 5 6
Even though my utils module defines two perfectly good functions, these functions are not yet available to my application. In order to bring my utils module into my application, I define a dependency by using the require() function. In my app.js, I’ll add the following:
Unfortunately, if I try to run
console.log(utils.addHello("Honey")); in my app.js, the code will break. The
require() function doesn’t just include the code in my module. Instead, it wraps the code in my module up in a closure that then returns anything set to
module.exports. In other words, I need to add the functions I created to a special object called
module.exports so that requiring my module will return the
addGoodbye() methods. I can do this my modifying utils.js in a couple of different ways:
1 2 3 4 5 6 7 8
OR through direct assignment:
1 2 3 4 5 6
Now when I try to use these functions in app.js, everything should work swimmingly.
1 2 3
So far so good? Good. There are some other things to be aware of.
module.exports vs. exports
You may notice that sometimes, people will use the variable exports instead of module.exports. In my utils.js, I can replace all my references to module.exports with just exports, and everything will continue to work as expected.
1 2 3 4 5 6
Remember that wrapper I mentioned, that is responsible for packaging the code in my module? Well, before it pulls in my code, it assigns
exports, so that
exports is just a pointer to
module.exports. Take a look at this excellent answer from StackOverflow: Difference between “module.exports” and “exports” in the CommonJS Module System.
In other words,
exports is a shortcut to
module.exports (less typing), but it’s not the variable that is returned, so I have to be careful. As a result of this, I see the following pretty often, especially when a custom module is a constructor:
That’s a lot of assignment! This statement not only ensures that
module.exports are the same, but it also assigns the module function to a variable that can be used for anything I like outside of the constructor function (like adding methods to the prototype, for example).
Interestingly, I can
require() a directory, not just a single file. Node.js will gladly look in the directory and see if I have an index.js file to use, and pull that in if it exists. If I wanted to package up a bunch of modules into one
require(), I might add something like this to index.js (assuming one.js and two.js exist in the same folder):
1 2 3 4
Then I can require the directory in app.js (assuming index.js, one.js, and two.js live in a directory called “stuff”):