How to create Node.js modules#

A Node.js module is a standalone JavaScript program which exposes an object that can be imported and used by other programs. The object exposed by the module can be of any JavaScript data type.

Writing Node.js modules is very easy and they help to keep your codebase modular and easy to maintain. Create and use them whenever you can.

Learning via examples#

Let's look at some examples to better understand how Node.js modules work.

A Node.js module which exports the value of Pi:

./pi.js
module.exports = 22/7;

Now the pi.js module can be imported in another file and used for showing the value of Pi.

./main.js
const pi = require('./pi.js');
console.log(`The value of Pi is ${pi}`);

On running main.js, it will display the value of Pi:

$ node main.js
The value of Pi is 3.142857142857143

In practical applications, Node.js modules mostly export an object or a function, instead of primitive data types like the example above.

Here is an example of a Node.js module which exports an object of functions for performimg arithmetic operations:

./arithmetic.js
module.exports = {
  add: function (a, b) {
    return a + b;
  },
  subtract: function (a, b) {
    return a - b;
  }
}
./main.js
const arithmetic = require('./arithmetic.js');
const add = arithmetic.add;
const subtract = arithmetic.subtract;

console.log(`1 + 2 = ${add(1, 2)}`);
console.log(`5 - 3 = ${subtract(5, 3)}`);

If your module exports an object, you can optimize the implementation using the exports object.

./arithmetic.js
exports.add = function (a, b) {
  return a + b;
}

exports.subtract = function (a, b) {
  return a - b;
}

What's the difference between defining the functions on an object and defining them on the exports object? Find out here.

Here is a module which exports a function:

./users.js
module.exports = function (id) {
  const users = [
    {name: 'Kim'},
    {name: 'Jong'},
    {name: 'Kong'}
  ];
  return users[id];
}
./main.js
const users = require('./users.js');
const selected = users(0);
console.log(`${selected.name} is Number 1!`);

Modules implemented as functions are great for requirements where you want to configure the behavior of the module.

This module is initialized with a configurable password to implement a very simple authorization system:

./users.js
module.exports = function (masterPassword) {
  masterPassword = masterPassword || 'letmesee';
  return function (id, password) {
    const users = [
      {name: 'Kim', balance: 92399012},
      {name: 'Jong', balance: 34555355},
      {name: 'Kong', balance: 63465534}
    ];

    const user = users[id];
    if (password === masterPassword) {
      return user;
    } else {
      return { name: user.name };
    }
  }
}
./main.js
const users = require('./users.js')('sup3rs3cr3t');
let selected = users(0);
console.log(selected); // Doesn't show balance
selected = users(0, 'sup3rs3cr3t');
console.log(selected); // Shows balance

Module variables#

Variables defined in a module file are local to the module. This localized scope is a good feature for sharing objects between functions defined in the module.

let count = 0;

exports.add = function (a, b) {
  count++;
  return a + b;
}

exports.subtract = function (a, b) {
  count++;
  return a - b;
}

Calling require() does NOT return a new intance of the module each time. The module object is cached when require() is called for the first time, all subsequent calls will return the cached module object.

Module variables are shared by all the "instances" of your module. If you have defined module variables and require() your module more than once, you will very likely have bugs in your application.

If you want to create real instances of your module, export a class or a function that can be instantiated.

./user.js
module.exports = class User {
  constructor(name) {
    this.name = name || 'Johnny';
  }
}
./main.js
const User = require('./user.js')
const u = new User('Anthony');
console.log(u.name);

Using a local module in a project#

The answer to the question, "How do you use a Node.js module?" will very likely be, "Install it in your project using npm".

But what if the module is on your local machine and is not published on npm yet? Maybe you don't plan to publish it on npm at all.

It is very easy to load a local module in your project.

The first step is to convert your module into an npm package. Run the following command in your module directory.

~/projects/my-module
$ npm init

Fill in the details and your Node.js module is now an npm package.

An npm package is a Node.js module with a package.json file.

Next, run the npm link command to make this module available for installation on your machine.

~/projects/my-module
$ npm link
npm WARN my-module@1.0.0 No repository field.

/Users/yaapa/.nvm/versions/node/v10.14.2/lib/node_modules/my-module -> /Users/yaapa/projects/my-module

This creates a symbolic link on the system's node_modules directory to your module directory.

Now you can "install" this module in your project by running the npm link <module name> command in your project directory.

~/projects/my-project
$ npm link my-module
/Users/yaapa/projects/my-project/node_modules/my-module -> /Users/yaapa/.nvm/versions/node/v10.14.2/lib/node_modules/my-module -> /Users/yaapa/projects/my-module

Now you can call require('my-module') to load the module in your project.

Summary#

Node.js modules are modular JavaScript programs that can be included in other programs using require(). Their functionality are exposed using the module.exports or exports objects. Local Node.js modules can be "installed" using the npm link command.

References#

  1. Node.js: exports vs module.exports
  2. Node.js: Publishing an npm package
  3. Node.js - Modules
  4. npm