npm, packages and modules
April 1, 2017 by Vinicius Isola
Node.js is a powerful Javascript runtime that can be used to build general purpose applications. npm extends Node.js capabilities with packages built by 3rd parties. These packages provide a variety of functionalities that you might need when building your application.
Let’s learn a little bit more about npm is and how it can help us.
packages and modules
Before diving into npm lets first understand what are packages and modules.
A package is a node.js application described by a package.json
file that lives somewhere that npm can access and make it available for your application. This somewhere can be a folder in your computer, a local or remote tarball file or a name/version combination that maps to one of the previous and was published to https://npmjs.com. A git url that when cloned results in a folder containing a package.json
file can also be used.
npmjs.com is npm’s public registry. People can make packages available there for others to use. And that’s where you’ll probably get your packages from.
But what’s inside a package? Any Node.js application can live inside a package. That means that full blown applications can be packaged. But the most common thing that people create packages for are modules.
A module is anything that can be loaded with the require
function, which includes packages that have a main
field declared in their package.json
, a javascript file or folders that contain an index.js
file.
Modules are, in my opinion, the main reason why Node.js community grew so fast in the last few years. npm provides a simple way for you to include 3rd party modules into your application. You just tell npm what packages you want and it will download and make them available to you next time you start your node.js application.
npm
So what’s npm? npm is a command line application that get’s installed when you install Node.js. It provides you with a simple way of installing 3rd party modules so that they are available inside your Node.js application.
For a simple example, let’s install and use a simple request
package that’s available in the registry.
request is a package that contains a module used to make HTTP requests in a simple way. Imagine that you want to download a file from the web in your application. Node.js provides APIs for you to do that, but they’re lower level and a bit cumbersome to deal with. That’s where request
comes in.
The first step is to install the module and for that, you just run the npm install
command passing the name of the module:
$ npm install request
/Users/visola/temp
└─┬ request@2.81.0
├── aws-sign2@0.6.0
├── aws4@1.6.0
...
│ └── punycode@1.4.1
├── tunnel-agent@0.6.0
└── uuid@3.0.1
npm WARN enoent ENOENT: no such file or directory, open '/.../package.json'
npm WARN temp No description
npm WARN temp No repository field.
npm WARN temp No README data
npm WARN temp No license field.
You can see that npm picked a version for you (the latest) and installed that package locally. It created a folder node_modules
and put the downloaded package in there. You can check that directory and its package.json
to see what’s inside:
$ ls -ls node_modules/request/
total 352
136 -rw-r--r-- 1 visola staff 65653 Mar 9 10:55 CHANGELOG.md
24 -rw-r--r-- 1 visola staff 9140 Nov 18 07:20 LICENSE
88 -rw-r--r-- 1 visola staff 43747 Mar 9 10:52 README.md
8 -rwxr-xr-x 1 visola staff 3993 Nov 18 07:20 index.js
0 drwxr-xr-x 12 visola staff 408 Mar 31 17:56 lib
8 -rw-r--r-- 1 visola staff 4043 Mar 31 17:56 package.json
88 -rw-r--r-- 1 visola staff 44706 Mar 9 10:52 request.js
$ cat node_modules/request/package.json
{
...
"dependencies": {
"aws-sign2": "~0.6.0",
"aws4": "^1.2.1",
"caseless": "~0.12.0",
"combined-stream": "~1.0.5",
"extend": "~3.0.0",
"forever-agent": "~0.6.1",
"form-data": "~2.1.1",
"har-validator": "~4.2.1",
"hawk": "~3.1.3",
"http-signature": "~1.1.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.7",
"oauth-sign": "~0.8.1",
"performance-now": "^0.2.0",
"qs": "~6.4.0",
"safe-buffer": "^5.0.1",
"stringstream": "~0.0.4",
"tough-cookie": "~2.3.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.0.0"
},
"description": "Simplified HTTP request client.",
...
"main": "index.js",
"name": "request",
...
}
In the package.json
there’re many details that we don’t care right now. The two things that’re important to notice are the main
and dependencies
properties.
As it was explained before, packages with a main
attribute contain a module. In this case it’s the lib
folder, which you can see contain a index.js
file (so it’s implicitly loaded).
The dependencies
attribute allow packages to have runtime dependencies. These runtime dependencies are required to run whatever the package contains and npm will automatically download and make available all dependencies that your dependencies have. You can check that the node_modules
directory has many other directories in it. Those are request
’s dependencies:
$ ls -la node_modules/
total 0
drwxr-xr-x 64 visola staff 2176 Feb 13 20:24 .
drwxr-xr-x 3 visola staff 102 Feb 13 20:16 ..
drwxr-xr-x 7 visola staff 238 Feb 13 20:24 .bin
drwxr-xr-x 6 visola staff 204 Feb 13 20:24 ansi-regex
drwxr-xr-x 6 visola staff 204 Feb 13 20:24 ansi-styles
drwxr-xr-x 9 visola staff 306 Feb 13 20:24 asn1
...
drwxr-xr-x 15 visola staff 510 Feb 13 20:24 uuid
drwxr-xr-x 13 visola staff 442 Feb 13 20:24 verror
drwxr-xr-x 11 visola staff 374 Feb 13 20:24 xtend
So let’s use our new installed modules. For that, lets create a file called downloadImage.js
inside the same directory where we installed the request
package. Add the following content to it:
const request = require('request');
const fs = require('fs');
request('https://farm2.staticflickr.com/1706/25031430855_1f4b306d32_k_d.jpg')
.pipe(fs.createWriteStream('northern_lights.jpg'))
.on('close', function () {
console.log("Finished downloading the image.");
});
When you run your script using Node, you can see that the library did all the heavy lifting of “talking HTTP”, copy all bytes directly to a file and augumenting the request with helpful events like close
which notifies when the download is finished.
Here is how it looks when you run the script above:
$ node downloadImage.js
Finished downloading the image.
And you can see that now you have the image in the current directory:
$ ls
downloadImage.js node_modules northern_lights.jpg
References
- What is a package? At npm’s documentation.