Let's have a look at Node's module system and the different categories of the Node.js modules.
The Module System
Application Modularization
Like most programming languages, Node.js uses modules as a way of organizing code. The module system allows you to organize your code, hide information, and only expose the public interface of a component using module.exports.
Node.js uses the CommonJS specification for its module system:
- Each file is its own module, for instance, in the following example, index.js and math.js are both modules
- Each file has access to the current module definition using the module variable
- The export of the current module is determined by the module.exports variable
- To import a module, use the globally available require function
Let's look at a simple example:
// math.js file
function add(a, b)
{
return a + b;
}
…
…
module.exports =
{
add,
mul,
div,
};
// index.js file
const math = require('./math');
console.log(math.add(30, 20)); // 50
The code files for the section The Module System are placed at Code/Lesson-1/b-module-system.
Module Categories
We can place Node.js modules into three categories:
- Built-in (native) modules: These are modules that come with Node.js itself; you don't have to install them separately.
- Third-party modules: These are modules that are often installed from a package repository. npm is a commonly used package repository, but you can still host packages on GitHub, your own private server, and so on.
- Local modules: These are modules that you have created within your application, like the example given previously.
Built-In Modules
As mentioned earlier, these are modules that can be used straight-away without any further installation. All you need to do is to require them. There are quite a lot of them, but we will highlight a few that you are likely to come across when building web applications:
- assert: Provides a set of assertion tests to be used during unit testing
- buffer: To handle binary data
- child_process: To run a child process
- crypto: To handle OpenSSL cryptographic functions
- dns: To do DNS lookups and name resolution functions
- events: To handle events
- fs: To handle the filesystem
- http or https: For creating HTTP(s) servers
- stream: To handle streaming data
- util: To access utility functions like deprecate (for marking functions as deprecated), format (for string formatting), inspect (for object debugging), and so on
For example, the following code reads the content of the lesson-1/temp/sample.txt file using the in-built fs module:
const fs = require('fs');
let file = `${__dirname}/temp/sample.txt`;
fs.readFile(file, 'utf8', (err, data) =>
{
if (err) throw err;
console.log(data);
});
The details of this code will be explained when we look at asynchronous programming later in this chapter.
npm – Third-Party Module Registry
Node Package Manager (npm) is the package manager for JavaScript and the world's largest software registry, enabling developers to discover packages of reusable code.
To install an npm package, you only need to run the command npm install <package-name> within your project directory. We are going to use this a lot in the next two chapters.
Let's look at a simple example. If we wanted to use a package (library) like request in our project, we could run the following command on our Terminal, within our project directory:
npm install request
To use it in our code, we require it, like any other module:
const request = require('request');
request('http://www.example.com', (error, response, body) =>
{
if (error) console.log('error:', error); // Print the error if one occurred
else console.log('body:', body); // Print the HTML for the site.
});
When you run the npm install <module-name> command on your project for the first time, the node_modules folder gets created at the root of your project.
Scanning for node_modules
It's worth noting how Node.js goes about resolving a particular required module. For example, if a file /home/tony/projects/foo.js has a require call require('bar'), Node.js scans the filesystem for node_modules in the following order. The first bar.js that is found is returned:
- /home/tony/projects/node_modules/bar.js
- /home/tony/node_modules/bar.js
- /home/node_module/bar.js
- /node_modules/bar.js
Node.js looks for node_moduels/bar in the current folder followed by every parent folder until it reaches the root of the filesystem tree for the current file.
The module foo/index.js can be required as foo, without specifying index, and will be picked by default.
Handy npm Commands
Let's dive a little deeper into npm, by looking at some of the handy npm commands that you will often use:
- npm init: Initializes a Node.js project. This should be run at the root of your project and will create a respective package.json file. This file usually has the following parts (keys):
- name: Name of the project.
- version: Version of the project.
- description: Project description.
- main: The entry-point to your project, the main file.
- scripts: This will be a list of other keys whose values will be the scripts to be run, for example, test, dev-server. Therefore, to run this script, you will only need to type commands such as npm run dev-server, npm run test, and so on.
- dependencies: List of third-party packages and their versions used by the project. Whenever you do npm install <package-name> --save, this list is automatically updated.
- devDependencies: List of third-party packages that are not required for production, but only during development. This will usually include packages that help to automate your development workflow, for example, task runners like gulp.js. This list is automatically updated whenever you do npm install <package-name> --save-dev.
- npm install: This will install all the packages, as specified in the package.json file.
- npm install <package-name> <options>:
- With the --save option, installs the package and saves the details in the package.json file.
- With the --save-dev option, installs the package and saves the details in the package.json, under devDependencies.
- With the --global option, installs the package globally in the whole system, not only in the current system. Due to permissions, this might require running the command with administrator rights, for example, sudo npm install <package-name> --global.
- npm install <package-name>@<version>, installs a specific version of a package. Usually, if a version is not specified, the latest version will be installed.
- npm list: Lists the packages that have been installed for the project, reading from what is installed in node_modules.
- npm uninstall <package-name>: Removes an installed package.
- npm outdated: Lists installed packages that are outdated, that is, newer versions have been released.
Local Modules
We have already looked at how local modules are loaded from the previous example that had math.js and index.js.
Since JavaScript Object Notation (JSON) is such an important part of the web, Node.js has fully embraced it as a data format, even locally. You can load a JSON object from the local filesystem the same way you load a JavaScript module. During the module loading sequence, whenever a file.js is not found, Node.js looks for a file.json.
See the example files in lesson-1/b-module-system/1-basics/load-json.js:
const config = require('./config/sample');
console.log(config.foo); // bar
Here, you will notice that once required, the JSON file is transformed into a JavaScript object implicitly. Other languages will have you read the file and perhaps use a different mechanism to convert the content into a data structure such as a map, a dictionary, and so on.
When you run npm install, without specifying the module to install, npm will install the list of packages specified (under dependencies and devDependencies in the package.json file in your project). If package.json does not exist, it will give an error indicating that no such file has been found.
Activity: Using a Third-Party Package for the Previous math.js Code
Before You Begin
This activity will build upon the, Running Basic Node.js activity of this chapter.
Aim
If the argument is a single array, sum up the numbers, and if it's more than one array, first combine the arrays into one before summing up. We will use the concat() function from lodash, which is a third-party package that we will install.
Scenario
We want to create a new function, sumArray, which can sum up numbers from one or more arrays.
Steps for Completion
- Inside Lesson-1, create another folder called activity-b.
- On the Terminal, change directory to activity-b and run the following command:
npm init
- This will take you to an interactive prompt; just press Enter all the way, leaving the answers as suggested defaults. The aim here is for us to get a package.json file, which will help us organize our installed packages.
- Since we will be using lodash, let's install it. Run the following command:
npm install lodash--save
Notice that we are adding the --save option on our command so that the package installed can be tracked in package.json. When you open the package.json file created in step 3, you will see an added dependencies key with the details.
- Create a math.js file in the activity-b directory and copy the math.js code from Activity, Running Basic Node.js into this file.
- Now, add the sumArray function right after the sum function.
- Start with requiring lodash, which we installed in step 4, since we are going to use it in the sumArray function:
const _ = require('lodash');
- The sumArray function should call the sum function to reuse our code. Hint: use the spread operator on the array. See the following code:
function sumArray()
{
let arr = arguments[0];
if (arguments.length > 1)
{
arr = _.concat(...arguments);
}
// reusing the sum function
// using the spread operator (...) since
// sum takes an argument of numbers
return sum(...arr);
}
- At the end of the file, export the three functions, add, sum, and sumArray with module.exports.
- In the same activity-b folder, create a file, index.js.
- In index.js file, require ./math.js and go ahead to use sumArray:
// testing
console.log(math.sumArray([10, 5, 6])); // 21
console.log(math.sumArray([10, 5], [5, 6], [1, 3])) // 30
- Run the following code on the Terminal:
node index.js
You should see 21 and 30 printed out.
The solution files are placed at Code/Lesson-1/activitysolutions/activity-b.