Node Packages

This document is focused on Node, NPM, webpack, babel with fading sections on Bower. It also covers the package.json and bower.json files.

Babel

npm install -D babel-loader @babel/core @babel/preset-env webpack

You don’t need to put this in webpack.config.js if you are using .babelrc:

module: {
    rules: [
        {
            test: /.js?$/,
            exclude: /(node_modules|bower_components)/,
            use: [
                {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            ]
        }
    ]
}

Just do this in .babelrc:

{
    "presets": ["@babel/preset-env"]
}

NPM ShortCuts

A few commonly used NPM shortcuts:

Task Basic Quick
Install npm install pkg npm i pkg.
Global Install npm i –global pkg npm i -g pkg.
Dependency npm i –save pkg npm i -S pkg.
Dev Dependency npm i –save-dev pkg npm i -D pkg.
list dependencies npm ls npm ls –depth=0

Here is additional information on NPM scripts, dependencies, init, and test:

Task Basic
See Scripts npm run
npm Init npm init -y
npm Init npm init -f
npm test npm t

Also:

  • npm docs
  • npm version
  • npm repo

Using package.json

All your projects should include a file called package.json. To create one from scratch, go to the root of your project and issue this command:

npm init

You will be presented with a series of prompts to fill out. Just step through them one by one, leaving the ones that don’t interest or confuse you blank. When you are done, there will be a file called package.json in your current directory.

To add packages to package.json, issue a command like this:

npm install require --save

This installs the package called require into a folder called node_modules. It also saves a command to install the package into package.json. To reinstall require later, just type this command:

npm install

This command processes package.json and automatically installs all the packages you saved into it. You can, of course, save information about many packages into a single package.json file.

The key point to remember is that npm install processes the contents of the file called package.json. It installs all the libraries listed in that file in a local directory called node_modules. By locally, I mean that the directory is now included in your project.

If you follow the link to package.json for BridgeSailor you will see that karma is listed in that file:

"devDependencies": {
    "requirejs": "^2.1.11",
    "karma": "^0.12.14",
    "karma-jasmine": "^0.2.0",
    "karma-requirejs": "^0.2.1",
    "karma-chrome-launcher": "^0.1.3",
    "karma-firefox-launcher": "^0.1.3"
}

This means that running npm install will install all the files listed above, including the karma library.

The point of npm install and package.json is that they work together to install a series of libraries, rather than asking you to type the following series of individual commands:

npm install requirejs
npm install karma
npm install karma-jasmine
npm install karma-requirejs
npm install karma-chrome-launcher
npm install karma-firefox-launcher

Typing all of the above commands is time consuming, error prone and repetitious. Therefore we use package.json, which needs to be configured correctly once, and works automatically thereafter.

Save to Package.json

To put the thing you installed in package.json use –save or –save-dev. If it is going to be used on the client side, then use –save, if it is debugging or other developer tool that is used only during development, then use –save-dev

	npm install "express" --save
	npm install "karma-script-launcher" --save-dev

Adding entries to package.json

Usually all you need to do is process package.json by typing npm install. However, you may occassionally. want to add your own dependency to package.json. Here is how to put a library called karma-script-launcher in package.json:

npm install "karma-script-launcher" --save-dev

The command shown above first installs karma-script-launcher into node_modules. It then adds an entry for it to package.json. Then next time you run npm install the karma-script-launcher package will be installed automatically because it is now included in package.json.

Consider this command:

npm install karma --save-dev

This command installs the library, and saves the library name into package.json if it is not already there.

Command Result
npm install process package.json and install all packages it references into node_modules
npm install chai install chai into node_modules
npm install chai –save install chai into node_modules and add chai to package.json
npm install chai –save-dev install chai into node_modules and add chai to package.json in a section listing packages used during development.

NPM and Express

You may have a project that depends on express. In such cases, the author of the project will probably create a file called package.json that will contain a reference to express. If this file exists, you can just type the following to install express and any other libraries that the project depends upon:

npm install

Here is the contents of a simple package.json file that installs both express and openid as well as a library called mdirp:

	{
		"name": "OpenId04",
		"version": "0.0.1",
		"private": true,
		"scripts": {
			"start": "node ./bin/www"
		},
		"dependencies": {
	    "body-parser": "~1.13.2",
    	"cookie-parser": "~1.3.5",
    	"debug": "~2.2.0",
    	"express": "~4.13.1",
    	"jade": "~1.11.0",
    	"morgan": "~1.6.1",
    	"serve-favicon": "~2.3.0"  	
		}
	}

Cannot Find Module

One useful tip:

  • Delete your node_modules folder
  • Try to start your project: npm start

You might see something like this:

$ npm start

> Week02-NpmBower@0.0.0 start /home/bcuser/Git/isit320-foo-2015/Week02-NpmBower
> nodemon ./bin/www

28 Sep 17:54:30 - [nodemon] 1.7.1
28 Sep 17:54:30 - [nodemon] to restart at any time, enter `rs`
28 Sep 17:54:30 - [nodemon] watching: *.*
28 Sep 17:54:30 - [nodemon] starting `node ./bin/www`
module.js:338
    throw err;
    ^

Error: Cannot find module 'express'

Study this error message. You are likely to see this error quite frequently. In particular, pattern Error: Cannot find module ‘XXX’. Getting that error usually means we have not run npm install or we have a problem in our package.json file.

The facts are simple. We often forget to run npm install. We make mistakes in our package.json files, usually because we forgot to include –save when we installed a particular package:

  • Correct: npm install jquery –save
  • Incorrect: npm install jquery

They both install jquery, but only the first adds an entry to package.json.

Understanding the source of errors like those shown above is very helpful. Remember, we fix this error by running the following command:

npm install

Understand when to run that command, and what it does. In particular, understand that it processes the contents of package.json.

More on Node and Package.json

NPM related issues are specific to node, not to Linux. If you were using node on Windows or the Mac, npm behaves in a very similar fashion.

npm is the Node Package Manager. It installs libraries that are used by Node projects. Some of the libraries, such as fs (the File System package) are built into node, but most are open source projects hosted on GitHub.

Here are a few node packages (libraries) that I often install globally:

~/npm/lib/node_modules
├─┬ express-generator@4.0.0
├─┬ grunt-cli@0.1.13
├─┬ jasmine-node@1.14.3
├─┬ js-beautify@1.5.1
├─┬ jshint@2.5.0
├─┬ karma-cli@0.0.4
└─┬ npm@1.4.9

These are stored here on a typical Linux system:

$ ls -l /usr/lib/node_modules/
total 28
drwxr-xr-x 5 nobody charlie 4096 Apr 21 12:24 express-generator
drwxr-xr-x 6 nobody charlie 4096 Apr 20 09:57 grunt-cli
drwxr-xr-x 9 nobody charlie 4096 Apr 21 16:02 jasmine-node
drwxr-xr-x 4 nobody charlie 4096 Apr 26 15:43 js-beautify
drwxr-xr-x 6 nobody charlie 4096 Apr 21 18:31 jshint
drwxr-xr-x 4 nobody charlie 4096 Apr 27 10:23 karma-cli
drwxr-xr-x 9 root root 4096 May 5 07:56 npm

We install these global packages by typing something like:

sudo npm install -g karma-cli

Where karma-cli is the package we want to install.

Each project also has packages that it uses. Each individual project might rely on a particular version of a package. For instance, one express project might use express 3.5.1, while another might use express 4.0.0. As a result, we don’t install these packages globally. Instead, we install them inside the project we are currently using. This way, a particular project can rely on a particular version of a package. Specifically, we install them in a folder called node_modules.

Here, for instance, are the packages installed for a project called Week02Jade:

charlie@MountainStreamsLinux:~/Git/Prog282/Week02Jade
$ ls -l node_modules/
total 28
drwxrwxr-x 3 charlie charlie 4096 Apr 26 16:44 body-parser
drwxrwxr-x 5 charlie charlie 4096 Apr 26 16:44 cookie-parser
drwxrwxr-x 3 charlie charlie 4096 Apr 26 16:44 debug
drwxrwxr-x 5 charlie charlie 4096 Apr 26 16:44 express
drwxrwxr-x 5 charlie charlie 4096 Apr 26 16:44 jade
drwxrwxr-x 3 charlie charlie 4096 Apr 26 16:44 morgan
drwxrwxr-x 2 charlie charlie 4096 Apr 26 16:44 static-favicon

These packages get installed when we type npm install. This action causes npm to process the contents of package.json, and to install the packages listed there:

    $ cat package.json
    {
      "name": "application-name",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "start": "DEBUG=my.application node ./bin/www"
      },
      "dependencies": {
        "express": "~4.0.0",
        "static-favicon": "~1.0.0",
        "morgan": "~1.0.0",
        "cookie-parser": "~1.0.1",
        "body-parser": "~1.0.0",
        "debug": "~0.7.4",
        "jade": "~1.3.0"
      }
    }

Do you see that the directory listing is the same as the packages listed in package.json? The bottom line is that we need to think in terms of both global and local versions of our npm packages.

You can find all the npm packages here:

Error: Couldn’t Read Dependencies

Sometimes you may also see this error:

npm install
npm ERR! install Couldn't read dependencies
npm ERR! package.json ENOENT, open '/home/charlie/package.json'
etc...

This errror occurs, needless to say, because a copy of package.json is not found. As mentioned above, there are cases when a node program does not rely on any libraries, and hence package.json does not exist. But the error above usually occurs because you are not in the proper directory. For instance, you are in your home directory, and the program you want to run is in ~/Git/JsObjects/JavaScript/Design/SimpleQueue.

To return to our main point: the primary problem that developers encounter when the see this error is simply forgetting to type npm install.

Error: Address in Use EADDRINUSE

The EADDRINUSE (Error Address In Use) message usually means that the port is in use by another program. For instance, you left an instance of a program running on the port where you want to launch your node server. Usually, fixing this is just a matter of finding the SSH or Windows command prompt where the server is running, and pressing Ctrl-C to stop the server:

C:\Git\P282\CanvasGrid>node server.js
  Listening on port :30026
^C   <== Here I press Ctrl-C
C:\Git\P282\CanvasGrid>

An important variation on this error can occur if you are running upstart. Details about that variant of the EEADDRINUSE error are discussed below.

Bower

Many developers use NPM to install server side dependencies, bower to install client side dependencies. We don’t have to do things this way, but it helps us neatly partition our app if we follow this policy.

NOTE: The introduction of webpack and ES6 has meant that most developers are moving on from Bower when creating new projects. However, there are still many older style projects in existence, and if you want to create an ES5, rather than an ES6, application, then Bower is still a good choice.

To begin, we need to create a bower.json file. You can do this in one of two ways:

  • Run bower init
  • Copy a sample bower.json from elsewhere: cp $ELF_TEMPLATES/bower.json ..

If you choose the first option, you can take all the defaults for the prompts that you see, or fill in the obvious fields with sensible values. If you choose for the second option, don’t forget the period at the end of the text for the copy command. It specifies where you should copy bower.json. In particular, it says: copy it here. The environment variable $ELF_TEMPLATES points at:

~/Git/JsObjects/Utilities/Templates

By default, bower installs your files not into node_modules but into a directory called bower_components. In express applications, however, we might want to install bower components into a different directory. In particular, we might choose to place them in our project’s public/bower_components folder. To ensure that happens, copy a bower configuration file into your project:

cp $ELF_TEMPLATES/.bowerrc .

This small text file contains the following text, which tells bower to install its components into the public/components folder:

{
  "directory": "public/bower_components"
}

More on Bower

Bower is like npm. Use NPM for server side code. Use Bower for client side code. This is not absolutely necessary, but it is common. As a result, we will learn about both NPM and Bower in this class.

Install Bower:

npm install -g bower

Create a bower.json file in the root of your current project:

bower init

You will be prompted for input. Take all the defaults or use your common sense to fill in the fields as you are prompted for them.

Remember that Windows does not like to start a file with a period. As a result, we need to create .bowerrc like this:

echo { } > .bowerrc

Edit .bowerrc in geany and add the following so that we will install bower components into the public/components directory:

{
  "directory": "public/bower_components",
  "json": "bower.json"
}

Again, test in jsonlint.com to make sure it is valid.

Install jquery:

bower install jquery --save

The –save parameter saves your request for jquery into the bower.json file.

My bower.json file now looks like this:

{
  "name": "Week02-ExpressJQuery",
  "version": "0.0.0",
  "authors": [
    "Charlie CedarIsle Calvert <charlie@elvenware.com>"
  ],
  "description": "JQuery Demo",
  "main": "bin/www",
  "keywords": [
    "JQuery"
  ],
  "license": "MIT",
  "homepage": "www.elvenware.com",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "jquery": "~2.1.3"
  }
}

The most important part is the dependencies object at the end of the file.

Modify /views/layout.jade to include jquery and Control.js

doctype html
html
    head
        title= title
        link(rel='stylesheet', href='/stylesheets/style.css')
        script(src='components/jquery/dist/jquery.js')
        etc...

NOTE: When I type etc…, that can sometimes be translated as: “Filling in this part of the file is left as an exercise for the reader.”