How to setup an NPM package

How to setup an NPM package

Ever wondered how an NPM package gets initialized? This article walks you through the process.

Featured on Hashnode

Every time you'd like to start building a Node app from scratch, it's highly recommended for you to setup an NPM package so that your app can be easily managed and maintained either by you or other developers.

💡 This article assumes that both Node and NPM are already installed on your operating system. If not, you might want to head up to this other article before you continue on this one.

Table of contents:

📁 Create a directory for the app to live in

The package will hold everything for your app. This includes: source code, configurations, assets and even documentation. Everything co-exists in a directory together, and it can be manually created. You may use your favorite directory creation method. The only recommendation for you is not to use spaces on the directory's name. Why? well, this will make it easier to navigate and prevent errors in some scenarios. Once the directory is created, go inside of it:

mkdir react-from-scratch && cd react-from-scratch

📦 Initialize the NPM package

An NPM package depends a lot on a very important file called package.json. It stores information about the package using the JSON syntax and though it supports several standard keys/properties, only 2 of them are required: "name" and "version".

One can create and fill this file manually but fortunately, NPM comes with a built-in initializer for this file that helps a lot. To bring it up, one has to use following CLI command:

npm init

When this command is invoked, a questionnaire gets prompted for you to help the initializer fill the document. The questions are shown on your CLI one by one and they look like this:

package name: (react-from-scratch)
version: 0.0.1
description: Very cool react app built from scratch
entry point: src/app.tsx
test command:
git repository: <url-to-git-repo>
keywords: react typescript sass
author: Carlos Jasso
license: MIT

and the resulting file contains this:

{
  "name": "react-from-scratch",
  "version": "1.0.0",
  "description": "Very cool react app built from scratch",
  "main": "src/app.tsx",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "react",
    "typescript",
    "sass"
  ],
  "author": "Carlos Jasso",
  "license": "MIT"
}

🔬 Anatomy of the package.json file

Have you noticed that some values are given within parenthesis? Those are the default values that the initializer will write to the package.json if you just hit the ENTER key when the question prompts for the answer. You can change those values to anything of your preference.

Each of the fields represents the following:

  • "name": contains your package's name. It must be written in lowercases, not include spaces but it may contain hyphens or underscores. Its default value is the directory's name.
  • "version": this value must be in the <MajorRelease>.<MinorRelease>.<PatchRelease> form or x.x.x. Its default value is 1.0.0.
  • "description": self explanatory, right? its value can even be an empty string "" (default).
  • "main": it references the file that the assembly starts with. Commonly, one can find this field with the values "index.js", "app.js", "my-app-name.js". If you're not sure what to fill this with, you may as well leave it blank and will cause no harm.
  • "scripts": its value is a nested json object with key/value entries for each of the "actions" needed to execute the package (or app) in one or other way. It by default has a "test" script that simply prints Error: no test specified to your CLI when executed.
  • "keywords": an array of words that can be used to describe the package. It's common to find the names of the technologies involved in the project and by default, it's an empty value.
  • "author": so that it's easy to find out whom a package was created by, it's convenient to add the author's information. It's suggested to follow the format <Name> <email@example.com> <http://example.com)> but just adding your name should be enough. An empty value is included by default.
  • "license": a license should be specified to let people know how they are allowed to use your package and what constraints you've set for it. The value must be a SPDX license identifier which default value is "ISC".

🤓 Taking a shortcut

At this far, you may be wondering if there's a quicker way to create the package.json file. Fortunately, there's a way to indicate the NPM initializer to answer all the questions of the questionnaire with their default values. This is done by passing the -y argument to the command like this:

npm init -y

but this may not be as fun as entering your own data.

🧩 Dependency version specification

Most of the times, NODE apps are not only composed by the source code written by a developer but they also feature several packages written by others. In order to keep every dependency neat and tidy, whether they get used on the final product or only during build-time, the package.json file features a section where those dependencies are specified:

{
  ...,
  "dependencies": {
    "react": "^17.0.1",
    "react-dom": "~17.0.0"
  },
  "devDependencies": {
    "ts-loader": "8.0.0",
    "typescript": ">=4.1.0",
    "webpack": "<=5.0.0",
    "webpack-cli": "~4.5.0"
  }
}

Commonly, the name and version of each dependency is included in the package.json file and NPM will know what package to look for. Also, the path to a tarball or git URL can be specified.

The version value of a dependency is written in a rather specific notation that is pretty easy to understand:

  • version: (no special characters) must match version exactly.
  • >version: must be greater than version.
  • >=version: must be greater than or equal to version.
  • <version: must be lower than version.
  • <=version: must be lower than or equal to version.
  • ~version: approximately equivalent to version. Allow patch-level or minor-level changes.
  • ^version: allow upgrades compatible with version.
  • 1.2.x: could be 1.2.0, 1.2.1, etc., but not 1.3.0.
  • *: matches any version
  • "": (empty string) same as *
  • version1 - version2: same as >=version1 <=version2.
  • range1 || range2: passes if either range1 or range2 are satisfied.

At first, you may find that the package.json file doesn't contain neither a "dependencies" nor a "devDependencies" section, and that's because those sections aren't included when the file gets first initialized, however, it's important to know what these two sections are used for.


I hope you've found this article to be useful. Now you know how to properly initialize an NPM package and understand the contents of a package.json file a bit better.

If you'd like to go deeper into the topic, you may want to give this awesome document a read.

fun fact: this is my very first published article ever.

Cover Credits: Mockup psd created by freepik - www.freepik.com | Boboss74, CC BY-SA 4.0, via Wikimedia Commons

 
Share this