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 deal.exports
is justmodule.exports
‘s little helper. Your module returnsmodule.exports
to the caller ultimately, notexports
. Allexports
does is collect properties and attach them tomodule.exports
IFmodule.exports
doesn’t have something on it already. If there’s something attached tomodule.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.