Modules Part 2 - Writing modules

NAVIGATION

Write modules by assigning to module.exports

Call to require() is replaced by module.exports

Module has local variables and functions

Returning a function

Conclusion

Modules are used to organize and create structure in program code. You know how to load modules using require. Now you're wondering "How am I supposed to write them?". Let's see how modules work from the module writers perspective so you can use them to divide your application into logical components.

Write modules by assigning to module.exports

Writing modules in Node.js is straightforward. Create a .js file and write your program logic and assign to module.exports what you want to pass to the consumer of that module. There are no restrictions on what you can pass - both functions and variables are allright.

module.exports.identifier = 'b7b6442c';
module.exports.load = function () {
    console.log("Loading...");
}

The module.exports object is initially created as an empty object literal. Fill it with objects that you want to pass to the caller of require(). As a shorthand, the same object is also available in exports.

You can use module.exports or exports shorthand. The following are equivalent, using module.exports explicitly

module.exports.identifier = 'b7b6442c';
module.exports.load = function () {
    console.log("Loading...");
}

and using exports shorthand

exports.identifier = 'b7b6442c';
exports.load = function () {
    console.log("Loading...");
}

Call to require() is replaced by module.exports

In the calling end the require() call gets replaced with module.exports of the loaded module.

Require call gets replaced by module.exports
Figure 1. The require() call gets replaced by module.exports.

Here the call to require('./log') can be thought as if it was replaced by contents of the module.exports object from log.js.

const log = require('./log');
log.logDate();
In main.js
exports.logDate = function () {
    console.log(new Date());
}
In log.js

and running main would output:

$ node main
Thu Jul 02 2017 09:48:03 GMT+0300 (EEST)

Module has local variables and functions

The module source can be thought as if it would be wrapped inside a function. All variables and functions are local to the source file and only what is assigned to module.exports will be passed to the caller.

For example in a more complex module

const dao = require('./dao');

function markUserRegistered(user) {
    user.registered = true;
}

exports.register = function(username) {
    var user = dao.findUserByUsername(username);
    markUserRegistered(user);
    dao.updateUser(user);
}

here markUserRegistered() will not be visible to the caller of require().

Returning a function

Instead of assigning properties to empty module.exports object literal you can also replace it completely with a function. This can be used for returning initialization functions or constructors to be called using new. It is important to note that assigning function simply to exports will not bring the desired result, module.exports must be explicitly used.

Remembering that require() is directly replaced with module.exports of the loaded module. This allows a pattern where a function call is immediately performed on the returned module. This is commonly seen pattern in the debug module.

const debug = require('debug')('worker');

debug('starting');

Conclusion

That's all there really is to writing modules. Write program logic in a separate file and assign to module.exports what you want pass to the consumer of the module.

Related articles

Semantic Versioning Cheatsheet

Semantic Versioning Cheatsheet

Learn the difference between caret (^) and tilde (~) in package.json.

Get Cheatsheet

Loading Comments