require and module.exports
Node provides a built-in module mechanism which works with the
require()
method and the module.exports
global object. To demonstrate how require and module.exports work, let's say we have two files account-service.js
and utility.js
.
The
utility.js
has some generic methods and objects which we use in many projects and applications. In this example, we will import those generic methods into account-service.js
.
Here's the code of
utility.js
in which we expose code to account-service.js
(or any other program) by assigning it to a special global module.exports
:module.exports = function(numbersToSum) {
let sum = 0,
i = 0,
l = numbersToSum.length;
while (i < l) {
sum += numbersToSum[i++]
}
return sum
}
account-service.js
) imports the utility module and executes it to find out the total balance:const sum = require('./utility.js')
let checkingAccountBalance = 200
let savingsAccountBalance = 1000
let retirementAccountBalance = 20000
let totalBalance=sum([checkingAccountBalance, savingsAccountBalance, retirementAccountBalance] )
console.log(totalBalance)
The account-service.js
can be run from the same folder where the file is located with node account-service.js
. The code will import the utility.js
and invoke sum()
. Thus, the result will be output of the total balance.require usage
require()
can be used to import many different types of modules, not just for local node.js files. You can use require()
to do the following:- Import core modules/packages, e.g.,
const filesystem = require('fs')
- Import npm modules/packages, e.g.,
const express = require('express')
- Import single file in a project, e.g.,
const server = require('./boot/server.js')
- Import single JSON files, e.g.,
const databaseConfigs = require('./configs/database.json')
- Import folders in a project (an alias for importing an index.js in that folder), e.g.,
const routes = require('./routes')
More examples:
const filesystem = require('fs') // core module
const express = require('express') // npm module
const server = require('./boot/server.js') // server.js file with a relative path down the tree
const server = require('../boot/server.js') // server.js file with a relative path up the tree
const server = require('/var/www/app/boot/server.js') // server.js file with an absolute path
const server = require('./boot/server') // file if there's the server.js file
const routes = require('../routes') // index.js inside routes folder if there's no routes.js file
const databaseConfigs = require('./configs/database.json') // JSON file
Using require() with local files
To use
require()
with local files, specify the name string (the argument to require()
) of the file you are trying to import. In general, start the name string with a .
to specify that the file path is relative to the current folder of the node.js file or a ..
to specify that the file path is relative to the parent directory of the current folder. For example, const server = require('./boot/server.js')
imports a file named server.js
which is in a folder named boot
that is in the current folder relative to the code file in which we write require()
.Using require() with npm or core modules/packages
To use
require()
with an npm or core module/package, enter the module/package name as the name string. There should not be .
or ..
in the name string. For example, const express = require('express')
imports a package named express
. The package is in the node_modules
folder in the root of the project if it's an installed npm package, and in the system folder if it's a core Node module (exact location depends on your OS and how you installed Node).
As you can see,
require()
is very versatile and can be used in many cases.require() caching
require()
caches the results based on the filename and path. Any code outside of the module.exports
assignment will be run just once during the process execution. For example, the following code is a module named utility.js
and it has some code outside of module.exports
:console.log('This will be printed just once')
module.exports = function(numbersToSum) {
let sum = 0,
i = 0,
l = numbersToSum.length;
while (i < l) {
sum += numbersToSum[i++]
}
return sum
}
The
account-service.js
file uses our utility.js
module:const sum = require('./utility.js')
let checkingAccountBalance = 200
let savingsAccountBalance = 1000
let retirementAccountBalance = 20000
let totalBalance=sum([checkingAccountBalance, savingsAccountBalance, retirementAccountBalance] )
console.log(totalBalance)
This is
app.js
which imports two files. AYou can also use require()
to run code without assigning the result to anything (line 2).const sum = require('./utility.js')
require('./account-service.js')
let checkingAccountBalance = 200
let savingsAccountBalance = 1000
let retirementAccountBalance = 20000
retirementAccountBalance = 40000
let totalBalance=sum([checkingAccountBalance, savingsAccountBalance, retirementAccountBalance] )
console.log(totalBalance)
In
app.js
when you import the module utility.js
two or more times (directly and indirectly via account-service.js
), the code in utility.js
which prints This will be printed just once
(it's outside the module.exports
) will be run just once despite the fact that the function module.exports
(which we exported) is invoked twice: once in account-service.js
and the second time in app.js
.
Therefore, running
app.js
will result in its balance being printed twice, one time in account-service and another time in app.js
, but the This will be printed just once
console log only appears once:This will be printed just once
21200
41200
Why did the code outside
module.exports
run just once even though we imported the utility.js
module twice (once directly and one indirectly via account-service.js
)?
The reason is because Node.js will cache imports. The second time you
require()
the same file or a module, it's not running the code. The results of the module are already there for you to use.
Just keep this behavior in mind and as a general rule, have all the logic exported in
module.exports
to avoid any unwanted behavior or conflicts.Node Patterns for module.exports
There are several patterns which developers can use to export functionality from a module:
- Export a function:
module.exports = function(ops) {...}
- Export an object:
module.exports = {...}
- Export multiple functions:
module.exports.methodA = function(ops) {...}
which is the same asexports.methodA = function(ops) {...}
- Export multiple objects:
module.exports.objA = {...}
which is the same asexports.objA = {...}
module.exports.name = ...
or exports.name =...
are used for multiple export points in a single file. They are equivalent to using module.exports = {name: ...}
.
Be careful!
exports = ...
(without module
) is not a valid module/export statement.
Let's take a look at how to export and use multiple functions. We begin with a monolithic program named
print-greetings.js
that has all the logic to print hello in three languages.
print-greetings.js:
// greeting methods
var sayHelloInEnglish = function() {
return 'Hello'
}
var sayHelloInSwedish = function() {
return 'Hej'
}
var sayHelloInTatar = function() {
return 'Isänme'
}
console.log('Swedish ' +
sayHelloInSwedish() +
' & English ' +
sayHelloInEnglish() +
' & Tatar ' +
sayHelloInTatar())
You can see that if you add 50 more languages, this file will start to become difficult to manage. If you wanted to use the
sayHello...
methods in other files, then this monolithic file wouldn't work well either. Let's modularize the program by putting the translation methods into their own module named greetings.js
.
Exporting methods using exports.methodA = function(ops) {...}
We can export the greeting methods by individually defining the greeting methods on the
exports
object.
greetings.js:
exports.sayHelloInEnglish = function() {
return 'Hello'
}
exports.sayHelloInSwedish = function() {
return 'Hej'
}
exports.sayHelloInTatar = function() {
return 'Isänme'
}
Exporting methods using module.exports = {...}
We can also export the greeting methods by setting
module.exports
equal to an object that contains the greeting methods.
greetings.js:
module.exports = {
sayHelloInEnglish() {
return 'Hello'
}
sayHelloInSwedish() {
return 'Hej'
}
sayHelloInTatar() {
return 'Isänme'
}
}
Regardless of the export pattern you use,
module.exports
will end up being an object with three greeting methods.Importing with require()
Next, we can edit
print-greetings.js
to import methods from greetings.js
using require()
. The require()
method returns whatever was exported from the imported module. In this case, the require()
method returns an object with three greeting methods and that object gets assigned to the greetings
variable. The greetings methods are then accessible through the greetings
variable.
printGreetings.js:
var greetings = require('./greetings.js')
console.log('Swedish ' +
greetings.sayHelloInSwedish() +
' & English ' +
greetings.sayHelloInEnglish() +
' & Tatar ' +
greetings.sayHelloInTatar())
1. Microsoft: DEV283x: Introduction to Node.js
No comments:
Post a Comment