What is NPM?

NPM stands for Node Package Manager, and is the default way to extend your Node applications.

There are an absolute ton of packages available to install and use immediately, making NPM wildly popular for software developers.

What is Node?

Node.js, or often simply just Node, is a Javascript runtime environment that allows Javascript code to be executed outside of the web browser.

It first came about in 2009 when the creator (Ryan Dahl) took Google’s V8 Javascript Engine which powers its Chrome browser, and repurposed it. Adding in additional logic allowing it to be used independently to execute Javascript on the server.

This opened up a whole new world for frontend Javascript developers to start writing code for the backend. Many of these developers are called Full-Stack Javascript Developers now.

How to setup an NPM project

While NPM is a command-line (CLI) tool, it’s registry is available online at npmjs.com.

It’s very easy to search for packages directly from the website, before installing them locally.

In order to illustrate things better, let’s create an NPM Project and play around a bit with the package manager.

If you don’t have npm or node installed, then take a look here for a quick setup. Alternatively, download node here.

First, we need to make sure we have a directory to work in. Let’s create one and move into there.

1
2
mkdir -p ~/src/tutorials/npm_testing
cd $_

Great, now we will have to run npm init to initiate an NPM project.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ 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: (npm_testing)

We will now be asked to customise our application, but we’re happy with all the default for now, so just press Enter at each of the prompts for now.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ 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: (npm_testing)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/ao/src/tutorials/npm_testing/package.json:

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


Is this OK? (yes) yes

If you want to do this quickly next time, you can always just pass the -y flag to npm init and you won’t be prompted for any inputs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ npm init -y

Wrote to /Users/ao/src/tutorials/npm_testing/package.json:

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


   ??????????????????????????????????????????????????????????????????
   ?                                                                ?
   ?       New minor version of npm available! 6.4.1 ? 6.13.7       ?
   ?   Changelog: https://github.com/npm/cli/releases/tag/v6.13.7   ?
   ?               Run npm install -g npm to update!                ?
   ?                                                                ?
   ??????????????????????????????????????????????????????????????????

So what has really been created now?

Let’s take a look in the directory, issue the ls command and you will see a new file called package.json. If we cat this file, we see the following output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "name": "npm_testing",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

We now need a file called index.js as highlighted under the main key. You can change this to anything you like, but these defaults are fine for us at the moment.

Run touch index.js from the CLI to create the new file.

At this stage we opt to open our project directory in a code editor, my chosen one at the moment is Visual Studio Code. There is a command-line alias available that allows me to execute the command code . in the directory I want to open to load the project in vscode.

Now we can start writing some NodeJS code and make use of an NPM module.

Let’s put the following code in our index.js file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const request = require('request');

request('https://ao.gl', { json: false }, (err, res, body) => {
  if (err) { return console.log(err); }
  console.log(body.url);
});
```<figure class="wp-block-image size-large">

<img decoding="async" loading="lazy" width="959" height="430" src="https://ao.gl/wp-content/uploads/2020/02/image-2.png" alt="" class="wp-image-3557" srcset="https://blog.ataiva.com/wp-content/uploads/2020/02/image-2.png 959w, https://blog.ataiva.com/wp-content/uploads/2020/02/image-2-300x135.png 300w, https://blog.ataiva.com/wp-content/uploads/2020/02/image-2-768x344.png 768w" sizes="(max-width: 959px) 100vw, 959px" /> </figure> 

If we try to run this from the CLI, we are greeted by some errors:

$ node index.js

internal/modules/cjs/loader.js:583 throw err; ^

Error: Cannot find module ‘request’ at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15) at Function.Module._load (internal/modules/cjs/loader.js:507:25) at Module.require (internal/modules/cjs/loader.js:637:17) at require (internal/modules/cjs/helpers.js:22:18) at Object. (/Users/ao/src/tutorials/npm_testing/index.js:1:79) at Module._compile (internal/modules/cjs/loader.js:689:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10) at Module.load (internal/modules/cjs/loader.js:599:32) at tryModuleLoad (internal/modules/cjs/loader.js:538:12) at Function.Module._load (internal/modules/cjs/loader.js:530:3)

1
2
3
4

This is because we don&#8217;t have the `request` package available for use yet.

It is an easy fix, all we need to do is issue the `npm install request` command. (`npm i request` for short)

$ npm i request

npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN [email protected] No description npm WARN [email protected] No repository field.

  • [email protected] added 48 packages from 59 contributors and audited 63 packages in 3.773s found 0 vulnerabilities
1
2

Now let&#8217;s try and run `node index.js` once more.

$ node index.js

undefined

1
2

No errors this time, great! But we get an `undefined` response. Let&#8217;s fix that quickly. Update our code:

const request = require(‘request’);

request(‘https://ao.gl’, { json: false }, (err, res, body) => { if (err) { return console.log(err); } console.log(res.statusCode, body.length); });

1
2

And run it again:

$ node index.js

200 129761

1
2
3
4
5
6

We printed out 2 values, firstly the `status code` of the request, followed by the length of the HTML body we got back.

## NPM Modules Directory

NPM stores everything in a local directory called `npm_modules`.

$ ls -lp

total 48 -rw-r–r– 1 ao staff 189 … index.js drwxr-xr-x 50 ao staff 1600 … node_modules/ -rw-r–r– 1 ao staff 13120 … package-lock.json -rw-r–r– 1 ao staff 275 … package.json

1
2

If we take a look in the `node_modules` directory we will see all the recursive dependencies our project needs.

$ ls -lashp node_modules

total 0 0 drwxr-xr-x 50 ao staff 1.6K … ./ 0 drwxr-xr-x 6 ao staff 192B … ../ 0 drwxr-xr-x 6 ao staff 192B … .bin/ 0 drwxr-xr-x 9 ao staff 288B … ajv/ 0 drwxr-xr-x 6 ao staff 192B … asn1/ 0 drwxr-xr-x 7 ao staff 224B … assert-plus/ 0 drwxr-xr-x 12 ao staff 384B … asynckit/ 0 drwxr-xr-x 6 ao staff 192B … aws-sign2/ 0 drwxr-xr-x 8 ao staff 256B … aws4/ 0 drwxr-xr-x 7 ao staff 224B … bcrypt-pbkdf/ 0 drwxr-xr-x 7 ao staff 224B … caseless/ 0 drwxr-xr-x 7 ao staff 224B … combined-stream/ 0 drwxr-xr-x 8 ao staff 256B … core-util-is/ 0 drwxr-xr-x 8 ao staff 256B … dashdash/ 0 drwxr-xr-x 8 ao staff 256B … delayed-stream/ 0 drwxr-xr-x 8 ao staff 256B … ecc-jsbn/ 0 drwxr-xr-x 12 ao staff 384B … extend/ 0 drwxr-xr-x 11 ao staff 352B … extsprintf/ 0 drwxr-xr-x 10 ao staff 320B … fast-deep-equal/ 0 drwxr-xr-x 13 ao staff 416B … fast-json-stable-stringify/ 0 drwxr-xr-x 6 ao staff 192B … forever-agent/ 0 drwxr-xr-x 8 ao staff 256B … form-data/ 0 drwxr-xr-x 8 ao staff 256B … getpass/ 0 drwxr-xr-x 6 ao staff 192B … har-schema/ 0 drwxr-xr-x 6 ao staff 192B … har-validator/ 0 drwxr-xr-x 10 ao staff 320B … http-signature/ 0 drwxr-xr-x 7 ao staff 224B … is-typedarray/ 0 drwxr-xr-x 10 ao staff 320B … isstream/ 0 drwxr-xr-x 9 ao staff 288B … jsbn/ 0 drwxr-xr-x 13 ao staff 416B … json-schema/ 0 drwxr-xr-x 9 ao staff 288B … json-schema-traverse/ 0 drwxr-xr-x 10 ao staff 320B … json-stringify-safe/ 0 drwxr-xr-x 8 ao staff 256B … jsprim/ 0 drwxr-xr-x 8 ao staff 256B … mime-db/ 0 drwxr-xr-x 7 ao staff 224B … mime-types/ 0 drwxr-xr-x 6 ao staff 192B … oauth-sign/ 0 drwxr-xr-x 11 ao staff 352B … performance-now/ 0 drwxr-xr-x 9 ao staff 288B … psl/ 0 drwxr-xr-x 7 ao staff 224B … punycode/ 0 drwxr-xr-x 12 ao staff 384B … qs/ 0 drwxr-xr-x 9 ao staff 288B … request/ 0 drwxr-xr-x 7 ao staff 224B … safe-buffer/ 0 drwxr-xr-x 9 ao staff 288B … safer-buffer/ 0 drwxr-xr-x 10 ao staff 320B … sshpk/ 0 drwxr-xr-x 7 ao staff 224B … tough-cookie/ 0 drwxr-xr-x 6 ao staff 192B … tunnel-agent/ 0 drwxr-xr-x 14 ao staff 448B … tweetnacl/ 0 drwxr-xr-x 11 ao staff 352B … uri-js/ 0 drwxr-xr-x 14 ao staff 448B … uuid/ 0 drwxr-xr-x 9 ao staff 288B … verror/

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

It is very important to never commit this node_modules directory to your SVN, such as Github.

Using `git`, we can avoid this by adding the directory to the project&#8217;s `.gitignore` file.

`echo node_modules >> .gitignore`

## Closing remarks

NPM is a powerful package manager that gets you up and running quickly.

Writing Javascript Node applications has never been easier, as there are a plethora of community crafted packages available to use for free.

The `node_modules` directory can really get out of hand and is often massive for larger projects. Never ever commit it to Github and always run a fresh `npm i` when cloning a Node project locally.