§3.3.

A web project

Creating a Node project

Enter the following commands to a directory named chapter03_express and display the current location:

$ mkdir chapter03_express
$ cd chapter03_express
$ pwd
/home/devel/chapter03_express
$

Next, you will initialize a blank Node Package Manager (NPM) project. When you do this, it will ask for some settings. You can keep pressing Enter to accept all the defaults.

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (chapter03_express) 
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /home/devel/chapter03_express/package.json:

{
  "name": "chapter03_express",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Is this OK? (yes) 
$

Next, you can type the following command:

$ npm install express
...
$

Now, open your editor to view all the files in the new directory.

Use your editor to create a file named index.js in the new directory and type the following code into index.js:

const express = require('express');
const app = express();

function indexHandler(request, response) {
    response.send(`<!DOCTYPE html>
                   <title>Hello, World!</title>
                   <h1>AIP</h1>
                   <p>Hello, World!</p>`);
}
app.get('/', indexHandler);

console.log('Running on http://localhost:8080/');
app.listen(8080);

Finally, enter the following command into your terminal or console window:

$ node index.js
Running on http://localhost:8080/

You can open your web browser and visit http://localhost:8080/ to see the output of this program.

To restart the server (e.g., if you have made a change to the code), press Control+C in the terminal window to kill the existing process.

$ node index.js
Running on http://localhost:8080/
^C
$
Tip
On most operating systems, the caret character (^) is used to denote Control-key sequences. In other words, ^C will often appear in the terminal when you press Control+C.

Understanding the project

Use your editor, file explorer or terminal to view the contents of your project:

$ ls
index.js  node_modules  package.json  package-lock.json
$

What are in each of these files/directories?

index.js

This is a JavaScript script file. It is the code that runs the web server.

node_modules/

This directory contains all the code for the libraries and requirements used by your project. If you look inside node_modules, you might see as many as 49 separate projects that your code depends on. When you ran npm install express, it installed Express into the directory node_modules/express along with all of the dependencies for Express.

package.json

This is the configuration file for your project. You can customize this file with information about your project (e.g., edit the author with your own name). When you ran npm install express, a dependency for Express was automatically added for you in package.json:

{
  "name": "chapter03_express",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "*"
  }
}
package-lock.json

This file contains information about the exact version of every dependency downloaded into node_modules.

Tip
package.json contains enough information to recreate node_modules. If you delete node_modules and then run npm install your node_modules directory will be automatically recreated.
Warning
When you work in a team, do not share your node_modules directory (i.e., don’t commit it to git). Instead, let your team members recreate node_modules themselves by running npm install.

Vendoring

Dependency management is an old problem in computing.

A team of people wrote Express. It is a package that makes it easy to build web servers. In index.js, you made use of this package to build a very simple web server. Thus Express is a dependency of the project.

Dependency management is the problem of tracking and using such dependencies.

Dependency management is a longstanding design problem in computing because it has no solution. Consider some of the conflicting goals:

Which version to use?
  • “Upgrading to the newest versions of Express means that we have the latest bug fixes.”

  • versus: “Upgrading to the newest versions of Express might cause some of our existing code to stop working because of unexpected changes in Express.”

Where should it be stored?
  • “We should have just one copy of Express in a central location on our computer, to save disk space and to ensure that nothing is out-of-date.”

  • versus: “We should support multiple installations of Express, because different projects need to use different versions.”

Who can manage versions?
  • “Our system administrator should manage the versions of Express to ensure consistency across the company.”

  • versus: “Every project should have its own version of Express because it is useful for developers to add or remove individual versions by themselves.”

Like all design problems, there is no best solution to this problem. People have different goals and objectives.

NPM’s approach is known as vendoring: by default, it keeps a copy of each dependency in every project (in the node_modules) project. This means that if you have 100 projects that depend on Express, then you will have 100 node_modules, and each of those 100 directories will have its own installation of Express. This might sound wasteful but your time as a professional programmer is likely to be far more valuable than the cost of a few gigabytes of disk storage.

Tip
It is possible to avoid vendoring. You can install dependencies into a single, global location on your computer using the --global option (e.g., npm install --global express).
Reflection: Vendoring

How would vendoring affect development in a team?

When would vendoring be a good idea? When would it be a bad idea?

When would a team decide to install dependencies globally, rather than using vendoring?

Reflection: Layering

Why is using a dependency an example of layering?