Posted by admin at March 20, 2020
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 }
The main program (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()
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:
const filesystem = require('fs')
const express = require('express')
const server = require('./boot/server.js')
const databaseConfigs = require('./configs/database.json')
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
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()
.
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()
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.
There are several patterns which developers can use to export functionality from a module:
module.exports = function(ops) {...}
module.exports = {...}
module.exports.methodA = function(ops) {...}
which is the same as exports.methodA = function(ops) {...}
module.exports.objA = {...}
which is the same as exports.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
.
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' }
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.
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())
Core modules come with Node.js and don’t need to be installed. Core modules provide low-level functionality and helper methods. They allow Node.js to work with the filesystem, networking, binary data, streams, spawn external processes, parse query strings, file paths and URLs, and perform other helpful tasks such as creating HTTP(S) agents/clients and servers.
Here’s the list of main core modules:
fs
: module to work with the file system, files and folderspath
: module to parse file system paths across platformsquerystring
: module to parse query string datanet
: module to work with networking for various protocolsstream
: module to work with data streamsevents
: module to implement event emitters (Node observer pattern)child_process
: module to spawn external processesos
: module to access OS-level information including platform, number of CPUs, memory, uptime, etc.url
: module to parse URLshttp
: module to make requests (client) and accept requests (server)https
: module to do the same as http only for HTTPSutil
: various utilities including promosify which turns any standard Node core method into a promise-base APIassert
: module to perform assertion based testingcrypto
: module to encrypt and hash informationThere is no need to install or download core modules. To include them in your application, all you need is to use the following syntax:const http = require('http') //replace `http` with the core module you want to use
fs
handles file system operations such as reading to and writing from files. There are synchronous and asynchronous methods in the library. Some of the methods include the following:
fs.readFile()
: reads files asynchronouslyfs.writeFile()
: writes data to files asynchronously
Comments