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.
mkdir -p ~/src/tutorials/npm_testing
cd $_
Great, now we will have to run npm init
to initiate an NPM project.
$ 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.
$ 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: "Introduction to NPM"
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.
$ 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:
{
"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:
const request = require('request');
request('https://ataiva.com', { json: false }, (err, res, body) => {
if (err) { return console.log(err); }
console.log(body.url);
});
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.<anonymous> (/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)
This is because we don’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
Now let’s try and run node index.js
once more.
$ node index.js
undefined
No errors this time, great! But we get an undefined
response. Let’s fix that quickly. Update our code:
const request = require('request');
request('https://ataiva.com', { json: false }, (err, res, body) => {
if (err) { return console.log(err); }
console.log(res.statusCode, body.length);
});
And run it again:
$ node index.js
200 129761
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
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/
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’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.