When you call require and pass a value, node makes a desicion based on the format of that string.
The process it uses is written in sudo code in the documentation.
When you create a module you (usualy) want to be able to export something to be used by the calling code.
To do this the result of a require call will always be the value of the module.exports property.
// test.js
module.exports = 'myCoolTestValue';
// index.js
var testValue = requie('./test');
console.log(testValue === 'myCoolTestValue'); // true
A reference to module.exports is also available as exports.
Imagine this line of code is inserted at the top of every module.
var exports = module.exports = {};
This means than exports can be used as a shorter reference to module.exports, but I prefer not to uses it to avoid confusion when that reference is broken.
The most common use case for a module is to return a namespace or object that groups related functionality together.
This is done by setting module.exports to an object that has properties pointing to the functionality
// simpleMath.js
function add(a, b){
return a + b;
}
function subtract(a, b){
return a - b;
}
module.exports = {
add: add,
subtract: subtract
};
var simpleMath = require('./simpleMath');
simpleMath.add(2, 3); // 5
Another pattern is to return a single function or constructor.
This is done by setting module.exports the function and is an example of why not to use exports.
// dog.js
function Dog(){
this.name = 'Rover';
this.speak = function(){
console.log('Woof');
}
}
// This will not work
// exports = Dog;
module.exports = Dog;
var Dog = require('./dog'),
rover = new Dog();
rover.speak(); // Woof
A higher-order function is a function that returns another function.
This is usefull if you want to return a function from your module but need additional input to do so.
// fooLogger.js
function createFooLogger(logger){
return function(value){
logger.log('foo ' + value)
}
}
module.exports = createFooLogger;
var fooLogger = require('./fooLogger')(console);
fooLogger('bar'); // foo bar
Because require caches the value assigned to module.exports based on the resolved filename, all subsequent calls to require() will (usualy) return the same instance.
There is a case where sub modules may have their own versions of a module in their node modules folder and in this case the require call will resolve to a different filename and thus return a different instance of the module.
This is not very common and probably points to a bigger problem with dependencies.
As a result, this is not recomended for every day, use but it can be resolved.
// singleton.js - module 1
if(global.myCoolSingleton){
module.exports = global.myCoolSingleton;
return;
}
var myCoolSingleton = 'Version 1';
module.exports = global.myCoolSingleton = myCoolSingleton;
// singleton.js - module 2
if(global.myCoolSingleton){
module.exports = global.myCoolSingleton;
return;
}
var myCoolSingleton = 'Version 2';
module.exports = global.myCoolSingleton = myCoolSingleton;
var singleton1 = require('./singleton'), // module 1
singleton2 = require('some/other/module/singleton'); // module 2
console.log(singleton1) // 'Version 1'
console.log(singleton2) // 'Version 1'
Modules do not nessesarily have to return something to be usefull.
Because the code is run at require, they can also be used to run single use code or to extend other objects.
// stringExtentions.js
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
var foo = ' My cool string ';
console.log(foo.trim); // undefined
require('./stringExtentions');
console.log(foo.trim); // [Function]
console.log(foo.trim()); // 'My cool string'
Lets build a modular http server that: