This lab goes through the basics of the Node.js platform.
Node.js (https://nodejs.org) is a platform built on Chrome’s JavaScript runtime V8 for easily building fast, scalable network applications. Node.js supports the same basic JavaScript programming language as web browsers. As the first example, let’s run the following program p101.mjs in both browser and Node. (Follow instruction to install Node.)
// p101.mjs
// return the largest number in an array
// assume at least 1 entry, and all entries are numbers
function largest (A) {
let big=A[0];
for (let i=1; i<A.length; i++) {
if (big<A[i]) big=A[i];
}
return big;
}
let N = [ 3, 7, 6, 8, 2, 5 ];
console.log(`The largest is ${largest(N)}`);
We save JavaScript programs in files with extension
*.mjs
instead of*.js
in this chapter. The extension informs Node.js that this file is a ES module, instead of the default of Common JS module. This allows us to use the modern syntaximport
to import modules. Instead of use themjs
extension, you can also set the default module type in thetype
attribute of thepackage.json
config file.
The JavaScript engine provides some common features in both Node and browsers:
console.log()
setInterval()
, setTimeout()
let now = new Date()
JSON.parse()
, JSON.stringify()
But Node misses some features specific to the browser platform, e.g.
Similar to JavaScript runtime in browser, Node includes an event loop that handles events. The event loop continues until all events are handled and there are no future events. Some common cases that trigger events are:
Trace the execution of the following program.
// p102.mjs
// countdown from 10
let N = 10;
function tick() {
if (N<=0) {
console.log('Time\'s up!');
clearInterval(timer);
} else {
console.log(N); N--;
}
}
// this starts the timer
const timer = setInterval(tick, 1000);
// event loop goes here ...
At any time, Node runs at most 1 event handler. If there are no pending events, the event loop blocks and waits for any future events. If Node determines that there are no more future events, it quits.
Node also support the new standard of JavaScript module known as ES module (online reference). This allows you to import new functionalities to the Node platform. The Node platform comes with some built-in modules (which are installed together with Node). See the online reference for a list of the built-in modules.
Many modules in Node provide a default export, and usually the default export is an object that encapsulate functions or classes of the module.
To import this kind of modules, use import variableName from 'moduleName'
. This function returns an object that represents the module in your program. You can assign this to a variable of any convenient name.
The following example demonstrates how to use another built-in module os
to find some basic hardware information of your computer.
// p103.mjs
// show basic info about CPU and memory
import os from 'os';
let cpus = os.cpus();
console.log(`CPU: ${cpus[0].model}, ${cpus.length} core`);
console.log(`Total memory: ${os.totalmem()/1024**3}G`);
Node.js comes with many built-in modules that cover various network services. But usually programmers take advantage of many high-quality third-party JavaScript libraries. These libraries are packed as packages, and Node.js used the built-in NPM command line tool to download and install packages.
By default, the NPM command line tool downloads packages from https://npmjs.com/, which is the largest registry of JavaScript packages.
For example, the systeminformation package provides a lot more information than the Node built-in module os
.
// p104.mjs
import si from 'systeminformation';
si.cpu()
.then(data => console.log(data));
In order to run the above example, you have to first download the systeminformation
module from npmjs.com with the following command. This command creates a folder ./node_modules
and install downloaded packages locally in the current project.
$ npm install systeminformation
# or, a shorthand notation
$ npm i systeminformation
After installing the package, you can now run example p104.mjs.
$ node p104.mjs
As we mentioned in previous lectures, a Node project is a folder that contains the JavaScript programs, JavaScript libraries / modules and other assets (e.g. HTML, images) for an application.
Instead of installing packages locally in a project, you can also install packages globally with
npm install -g packageName
. However, we’ll not do this in this course.
Remembering and installing the dependencies of a Node application manually is error-prone. Dependencies of an application refer to the packages that must be installed properly before this application and run successfully. Fortunately, Node.js already supports a configuration file at the root of an application project folder called package.json
. Among other functionality, package.json
contains a property dependencies
that list the packages required by the application. Run this command to create a package.json
at the current folder.
$ npm init -y
You’ll see the following data in the package.json
generated.
{
"name": "chap4-1",
"version": "1.0.0",
"dependencies": {
"systeminformation": "^5.9.2"
},
// other properties omitted for brevity
}
From now on, when you install more packages locally, it is assumed that the packages are new dependency of the current applicatoin, and npm
will update package.json
to include the dependency. For example, install the following package, and check the update in dependencies
in package.json
.
$ npm install prompts
When you pack your Node application for sharing (e.g. upload to npmjs.org), deployment (i.e. to run in production environment), or hand in your assignment, DON’T include the node_modules folder. There are several reasons.
With the dependencies listed in package.json
, one can install them easily with the following command.
$ npm install
In package.json
, you might notice a version number after each mention of package.
"dependencies": {
"prompts": "^2.4.1",
"systeminformation": "^5.9.2"
},
This software versioning convention, called semantic versioning (online reference), is an important part of package management in Node / NPM. An explanation at the official page of https://semver.org/ is quoted below.
Given a version number MAJOR.Minor.patch, increment the:
- MAJOR version when you make incompatible API changes,
- Minor version when you add functionality in a backwards compatible manner, and
- patch version when you make backwards compatible bug fixes.
Check the Version History of the systeminformation package and explain the meaning of version updates.
The dependencies section of package.json
adds the symbol ^
before the version number. For version >= 1.0.0, the caret range ^a.b.c
means a version >= the given version a.b.c
, but smaller than a+1.0.0
. For example, "systeminformation": "^5.9.2"
means that, in the future, npm install
can install the following versions of the package because they are considered as compatible with the application: 5.9.2
, 5.9.3
, 5.10.0
, 5.10.1
, 5.23.45
. However, versions before 5.9.2
are not acceptable. (They may have less features, or they include a bug that has been fixed in 5.9.2
. Moreover, version 6.x.y
is not acceptable because they will introduce breaking changes. For other possibilities of specifying usable versions, refer to the online reference.
The example source files are available here.