Be the first user to complete this post
|
Add to List |
Understanding nodejs module exports and require
Nodejs allows you to write modular code by dividing your business logic into single purpose files called modules. When you are new to nodejs, it can sometimes be difficult to understand what is happening and how things are connected.
Consider the following lines of code in a file called add.js in my project root.function add(x,y){
return x+y;
}
We can convert this file into a module that can be used in a nodejs application.
function add(x,y){
return x+y;
}
module.exports = add;
The only difference in the two versions of the add.js file is the last line. First lets see how this could normally be used as a nodejs module from another file in my root directory, say index.js.
var adder = require('./add.js');
console.log(adder(1,100));
This is probably the simplest example of how a nodejs module is defined and used. Now lets try to understand the concepts behind how the pieces are connected.
In your index.js file, when you say require('./add.js')
, node searches for a file called add.js in the currenty directory. Then, this file is loaded and loaded just once. i.e. a call to require the same file - add.js from either index.js or any other file will not cause the file to be loaded again.(This is why you need to restart your nodejs server everytime you make changes to your modules since they are not automatically reloaded on change).
When the file add.js is loaded, everything inside of it is wrapped inside a closure. This means that any local variables declared in your files using the var keyword will not be visible outside the file. Since we defined an add function within our file that we want other files to be able to use, we definitely want it to be exposed. The only way to expose any local variables or functions is by setting the value of the module.exports.
You might wonder, what the hell is module.exports. Isint that supposed to cause a javascript error since its not defined anywhere in sight?
Apparently, when nodejs loads a file as a module, it is provided this file with some variables as listed in the docs here
Think about your add.js file to be converted to something like this in memory.
(function(module,__dirname, process){ //... and other global variables
function add(x,y){
return x+y;
}
module.exports = add;
}(module, directoryName, processDetails));
Now you can clearly see the closure and the module variable. The module variable has a special property called the exports which is the value that is returned by a require call. So, if you set it to an object, the require call for this module will result in that object (e.g. useful for configuration objects). If you set it to a function, the require call returns that function, as seen in our example.
NOTE: A lot of times people also use ‘exports’ direcly as a shorthand instead of writing ‘module.exports’ since exports also one of the global variables passed into the closure. Although exports is essentially same as module.exports, reassigning exports to a new object does not reassign module.exports to the new object and can cause confusion if you’re not careful about what you are doing. My recommendation, avoid the pain and just use module.exports because staying sane is more important than code brevity.
Lets just reinforce the concept of nodejs modules with another simple example. This time, we will export an object instead of a function from our new file - utils.js
function add(){
return x+y;
}
function subtract(){
return x-y;
}
module.exports = {
add: add,
sub: subtract
};
Notice that since our functions are defined inside the module, we were able to use a different function name when exposing the subtract function.
Here’s how you could use your utils.js module in your index.js file
var utils = require('./utils.js');
console.log(utils.add(1,100));
console.log(utils.sub(100,1));
I hope this post has helped you get a better understanding of why you need write a module.exports at the end of a nodejs module and why it actually works.
Also Read:
- Dynamic module loading with require
- Scaling a basic nodejs application using clusters
- Understanding semver versioning for your nodejs packages
- set the default node version using nvm
- Testing promise sequence using mocha, chai, chai-as-promised, sinon