Summary: in this tutorial, you will learn about Node.js modules and understand how they work.
Introduction to the Node.js modules #
In Node.js, a module is a reusable piece of code placed in a .js file. Node.js supports two module systems:
This tutorial focuses on the CommonJS modules.
In a module, when you define variables, functions, and classes, these identifiers are accessible only in that module.
To use these objects in another module, you need to export them using one of the following export mechanisms or combine them:
- Named exports
- Default exports.
Named exports #
In the named export, you assign identifiers to individual properties of the module.exports object. This allows you to export multiple identifiers from a module and import them individually into another module.
Let’s take a look at an example of using named exports.
First, create a new module called math.js with two functions add and subtract:
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}The add and subtract functions are visible only in the math.js module.
To use these functions in another module, you need to export them by assigning them to the properties of the module.exports object.
Second, export the add and subtract functions from the math.js module:
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports.add = add;
module.exports.subtract = subtract;In the assignments, you use the function names without parentheses and assign them to the individual properties of the module.exports object.
Note that you can use different names when exporting a function like this:
module.exports.sum = add;
module.exports.deduct = subtract;For now, we’ll keep the same function names when exporting.
Third, create a new module called app.js and import the math module into the app.js module:
const math = require('./math');
console.log(math);To import a module, you use the require() function. The require() function accepts a path to the module without or without .js extension.
The ./ indicates that the math.js module is located in the same directory as the app.js module.
The console shows that math is an object that includes two functions add and subtract as its properties:
{ add: [Function: add], subtract: [Function: subtract] }Finally, call the add and subtract functions via the math object:
// app.js
const math = require('./math');
let a = 20,
b = 5;
let result = math.add(a, b);
console.log(`${a} + ${b} = ${result}`);
result = math.subtract(a, b);
console.log(`${a} - ${b} = ${result}`);Output:
20 + 5 = 25
20 - 5 = 15To make the code more concise, you can use object destructuring in the app.js module as follows:
const { add, subtract } = require('./math');
// ...In this syntax, we destructure the properties of the object returned by the require() function to the add and subtract variables.
It’s equivalent to the following:
// app.js
const math = require('./math');
const add = math.add,
subtract = math.subtract;
// ...Default exports #
A default export allows you to export a single identifier (a variable, function, object, or class) from a module. A module can have one and only one default export. Consider the following example:
The following shows how to use a default export in the math.js module:
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = add;In this example, we assign the add function to the module.exports object instead of its property. It is called a default export.
In the app.js module, you can import the add function from the math.js file directly:
// app.js
const add = require('./math');
let a = 20,
b = 5;
let result = add(a, b);
console.log(`${a} + ${b} = ${result}`);Output:
20 + 5 = 25Mixing default & named exports #
First, export identifiers in the math.js module using both default and named exports:
// math.js
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = add;
module.exports.subtract = subtract;Second, import the add and subtract functions from the math.js into the app.js module:
const math = require('./math');
const add = math;
const subtract = math.subtract;
// ...Understanding the module wrapper function #
Before executing a module, Node.js wraps all the code inside that module with a function wrapper which looks like the following:
(function(exports, require, module, __filename, __dirname) {
// Module code
});For example, the code of the math.js module before execution will look like this:
(function (exports, require, module, __filename, __dirname) {
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports.add = add;
module.exports.subtract = subtract;
});By doing this, Node.js achieves the following important goals:
- Keep the top-level variables (
var,let, andconst) scoped to the module instead of the global object. - Make some module-specific variables like global variables for example
moduleandexports.
Notice that the exports object references the module.exports:
console.log(module.exports === exports); // trueImporting the same module multiple times #
When you use the require() function to import the same module multiple times, the require() function evaluates the module once only at the first call and places it in a cache.
From the subsequent calls, the require() function uses the exports object from the cache instead of executing the module again.
The following example illustrates how it works:
First, create a new module called dblogger.js that has the following code:
console.log('Connected to the DB');Second, import the dblogger.js module twice in the app.js:
let dbLogger = require('./dblogger');
dbLogger = require('./dblogger');Output:
DBLogger is loaded.In this example, you can see the message 'DBLogger is loaded.' only once, not twice. This means that Node.js evaluated the dblogger.js only once.
Summary #
- In the CommonJS modules, Node.js treats a JavaScript file as a module.
- All identifiers including variables, constants, functions, and classes, declared in a module are scoped to the module, not the global scope.
- Export identifiers from a module by assigning them to the properties of the
module.exportsobject. - Node.js wraps the module code in a module wrapper function before executing it.
- Node.js executes a module only once and places the result in the cache for the next use.
Thank you for your feedback!