All About NPM Packages

Every Node.js project starts with a package.json file.

In the previous part of the Node.js Simplified Tutorial series, you learned about exporting and requiring Node.js modules. Here, I'll talk about npm, an indispensable tool in your Node.js experience.

Node's package manager, suggestively named npm, is a very powerful tool used to share your code as packages. Not only that, but it allows you to reuse code written by other developers inside your own package, as dependencies. Each package is identified using a package.json file.

The package.json file is used for specifying important details about your project such as its name, description, version, entry file, production dependencies, and development dependencies. You can even define command line scripts to be run through npm, slowly eliminating the need for task runners.

Creating a npm package

Creating your first package is as simple as writing a single command line. Open up your terminal, go to your project's root folder and run the following command:

npm init

This is going to ask you to provide basic details about your npm package. The name and description you provide here are the ones that will be used when publishing the package to npm. Don't worry about the entry point for now: the default is index.js and you'll see why that is in the following section.

name: (project) my-project
version: (1.0.0) 1.0.0
description: This is a sample project for the Node.js Simplified Tutorial.
entry point: (index.js) index.js
test command: 
git repository: https://github.com/alexgrozav
keywords: nodejs
author: Alex Grozav
license: (ISC) ISC

After you're done , the command will generate a file called package.json that will contain all the details you provided. This will be the configuration of your npm package.

Your package.json file should look like this:

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "This is a sample project for the Node.js Simplified Tutorial",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/alexgrozav"
  },
  "keywords": [
    "nodejs"
  ],
  "author": "Alex Grozav",
  "license": "ISC"
}

The package.json file does a lot more than provide basic package details. It's the place where you specify the development and production dependencies that your package has, but we'll get back to that later in this article.

For now, it's easiest to think of every Node.js project as a package and to think of every package as a module.

Requiring a npm package

In my previous tutorial you've learned how Node.js handles require statements for relative paths. You can also require npm packages in the same way.

It's important to understand that when you require a package you will actually require the file specified in the main field of your package.json file. This is same as the entry point you specified during the npm init step.

const myPackage = require('package-name');

After path resolving, Node.js will require the file specified in the main field of the package-name/package.json file or, if the main field isn't specified, it will look for an index.js file:

const myPackage = require('package-name/index.js');

Adding package dependencies

Undoubtedly, the best thing about creating your own npm package is that you can specify, install and then use other developer's packages. This saves up a lot of time, with the npm registry offering more than 600,000 packages for you to use.

When I was learning Node.js, I didn't understand the difference between production and development dependencies very clearly. Here's what is different:

Installing dependencies for production

Production dependencies are the ones that your package actually depends on. These dependencies will need to be installed alongside your own package in order for it to run. Don't worry though, npm handles the dependencies for you.

What this basically means is that, when someone else installs your package, the production dependencies you specify will be automatically installed together with it.

npm install --save lodash

Note: You can use the -S shorthand instead of --save.

Installing dependencies for development

Specifying development dependencies is perfect for installing packages that help you get to the final version of your package, but do not directly affect the functionality of your package.

Development dependencies usually provide you with capabilities such as testing, compiling, bundling, and other things needed during development only.

npm install --save-dev gulp

Note: You can use the -D shorthand instead of --save-dev.

Installing packages globally

Global packages are made available system-wide. You should only install packages globally if they offer a command line executable or if their documentation suggests you to do so.

Typically, you will need install test runners, testing frameworks, task runners, languages, and bundlers globally.

npm install --global gulp-cli

Note: You can use the -g shorthand instead of --global.

The node_modules folder

Every time you install a local dependency, npm downloads and installs the package and its dependencies inside a folder called node_modules, where you can find and explore all of your package's dependencies.

After each saved installation, your production or development dependencies will be listed inside the package.json file under dependencies and devDependencies, respectively:

{
    ...
    "dependencies": {
        "lodash": "^4.17.5"
    },
    "devDependencies": {
        "gulp": "^3.9.1"
    }
}

If you want to install all the dependencies of an existing package, simply run the install command without any argument:

npm install

Publishing your package to npm

When you're ready to share your package with the world (if you want to, of course), you can publish your package to the public npm repository.

  • First, make sure you're logged into npm using the login command. This will ask you for your npm username, password, and email.
npm login
  • Next, make sure you have specified a unique name, valid repository url, and semantic version in your package.json. Publish your package by running the publish command:
npm publish
  • Now your package is available for installation to other developers using the name you've specified.
npm install --save your-package-name

Lately, good npm package names have been pretty scarce, like domains, because everyone is trying to reserve a nice name for themselves.

What's next?

Now you're ready to create packages, install dependencies and perhaps, even give something back to the open source world someday.

In my Power of NPM Scripts article, I've written about the now-popular npm scripts and how they work. They're a great addition to your workflow, and you won't need to rely on a task runner such as gulp or grunt anymore.