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;
}
Code language: JavaScript (javascript)
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;
Code language: JavaScript (javascript)
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;
Code language: JavaScript (javascript)
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);
Code language: JavaScript (javascript)
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] }
Code language: JavaScript (javascript)
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}`);
Code language: JavaScript (javascript)
Output:
20 + 5 = 25
20 - 5 = 15
Code language: JavaScript (javascript)
To make the code more concise, you can use object destructuring in the app.js
module as follows:
const { add, subtract } = require('./math');
// ...
Code language: JavaScript (javascript)
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;
// ...
Code language: JavaScript (javascript)
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;
Code language: JavaScript (javascript)
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}`);
Code language: JavaScript (javascript)
Output:
20 + 5 = 25
Code language: JavaScript (javascript)
Mixing 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;
Code language: JavaScript (javascript)
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;
// ...
Code language: JavaScript (javascript)
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
});
Code language: JavaScript (javascript)
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;
});
Code language: JavaScript (javascript)
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
module
andexports
.
Notice that the exports
object references the module.exports
:
console.log(module.exports === exports); // true
Code language: JavaScript (javascript)
Importing 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');
Code language: JavaScript (javascript)
Second, import the dblogger.js
module twice in the app.js
:
let dbLogger = require('./dblogger');
dbLogger = require('./dblogger');
Code language: JavaScript (javascript)
Output:
DBLogger is loaded.
Code language: JavaScript (javascript)
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.exports
object. - 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.