Creating & Using Modules In Node.js & Understanding Paths

Javascript libraries are commonly referred to as “modules”. The modules are typically imported by other Javascript files to use their functionality. Modules could contain class definitions, or helper functions.

Node.js uses the global require() method to load modules. It is similar to import statement in Java or include in PHP. require is a Node.js function and is not part of the standard Javascript.

PHP’s include VS Node.js’ require

To include a file in PHP, we would do something like the following:

include 'filename.php';

To include a module in Node.js:

var module_name = require('filename.js');

The key difference is that PHP merges the content of the included file into current file’s scope. Whereas, in Node.js the contents of the imported module are accessible through the variable.

module.exports Object

A call to require() function returns module.exports object. The module.exports is automatically set to the same object as the module, so we can do something like this:

//filename: util.js
function add(num1, num2)
{
    return num1+num2;
};
exports.add = add;

This exposes the add() function to the world.

In the calling Javascript file, we can import and use the module as follows:

var utils = require('./utils'); // include the module we created

var result = utils.add(1, 2); // call the add function which was exported by the module
console.log(result); // prints 3

The name added to the exports object doesn’t have to be the same name as the internal function it is exposing. For example, consider the following code:

//filename: util.js
function addTwoNumbers(num1, num2)
{
    return num1+num2;
};
exports.add = addTwoNumbers; //Exposing addTwoNumbers() as add()

The calling script can do the following:

var util = require('./util.js');
util.add(1,2);

A common practice among Node.js developers is to use anonymous functions when exporting. Let’s take a look:

//filename: util.js
exports.add = function(num1, num2) { //exposes the anonymous 2-arg function as add
    return num1 + num2;
};

If you are wondering what is the difference between `export` and `module.exports`, it is nicely explained by Hack Sparrow:

Here is an eye-opener – module.exports is the real dealexports is just module.exports‘s little helper. Your module returns module.exports to the caller ultimately, not exports. All exportsdoes is collect properties and attach them to module.exports IF module.exports doesn’t have something on it already. If there’s something attached to module.exports already, everything onexports is ignored.

Node.js’ Import Path

Node.js uses a non-trivial algorithm when searching for a module specified in require() statement. Let’s look at several cases Node.js considers:

Case I: Absolute or Relative Path

This is the easiest case: If the path in require statement is absolute or relative, Node.js knows exactly where the module is located.

var moduleA = require('./moduleA'); // Module 'moduleA.js' is in the same folder as this script
var moduleB = require('../moduleB'); // moduleB.js is in the parent folder
var moduleC = require('/var/www/html/js/moduleC'); // absolute path

Case II: Core Modules

If the path (relative or absolute) is not specified, and the module that is loaded is one of Node.js’ core modules, it is automatically loaded. Node.js knows where the core module is located. The core modules are sys, http, fs, path, etc.

var moduleA = require('http');
var moduleB = require('fs');

Case III: No path and not core

This is where the algorithm uses non-trivial logic to locate the module, if you don’t specify path and the module you are loading is not a core module. For example:

var moduleA = require('myModule'); // no path given!

The module search algorithm in Node.js will attempt to find a directory called “node_modules”. It starts with the directory of the running script and will keep moving up the hierarchy (parent directories) until it locates the “node_modules” directory. When the node_modules directory is found, Node.js then looks whether the module is a .js file or is a subfolder. If the module is a .js (e.g. myModule.js), Node will simply load it. If there is a subdirectory called myModule/ (e.g. node_modules/myModule) then Node.js will attempt to load index.js or package.json inside the subdirectory. This looks confusing, let me use some illustration.

Going back to our example, suppose we require a certain module called “bigbangtheory”.

var moduleA = require('bigbangtheory'); // no path given!

Here’s how Node.js will look for it:

node_modules/bigbangtheory.js
node_modules/bigbangtheory/index.js
node_modules/bigbangtheory/package.json

The search will start in the same directory as the executing script and will work its way up the parent directories.

If the module is still not found, Node.js then uses “require.path” array, which lists include directory paths. The paths can be set using environment variable called NODE_PATH or programatically by scripts.