Contribute to help us improve!

Are there edge cases or problems that we didn't consider? Is there a technical pitfall that we should add? Did we miss a comma in a sentence?

If you have any input for us, we would love to hear from you and appreciate every contribution. Our goal is to learn from projects for projects such that nobody has to reinvent the wheel.

Let's collect our experiences together to make room to explore the novel!

To contribute click on Contribute to this page on the toolbar.

Package Managers Workflow

Introduction

This document aims to provide you the necessary documentation and sources in order to help you understand the importance of dependencies between packages.

Projects in NodeJS make use of modules, chunks of reusable code made by other people or teams. These small chunks of reusable code are called packages [1]. Packages are used to solve specific problems or tasks. These relations between your project and the external packages are called dependencies.

For example, imagine we are doing a small program that takes your birthday as an input and tells you how many days are left until your birthday. We search in the repository if someone has published a package to retrieve the actual date and manage date types, and maybe we could search for another package to show a calendar, because we want to optimize our time, and we wish the user to click a calendar button and choose the day in the calendar instead of typing it.

As you can see, packages are convenient. In some cases, they may be even needed, as they can manage aspects of your program you may not be proficient in, or provide an easier use of them.

For more comprehensive information visit npm definition

Package.json

Dependencies in your project are stored in a file called package.json. Every package.json must contain, at least, the name and version of your project.

Package.json is located in the root of your project.

If package.json is not on your root directory refer to Problems you may encounter section

If you wish to learn more information about package.json, click on the following links:

Content of package.json

As you noticed, package.json is a really important file in your project. It contains essential information about our project, therefore you need to understand what’s inside.

The structure of package.json is divided in blocks, inside the first one you can find essential information of your project such as the name, version, license and optionally some Scripts.

{
  "name": "exampleproject",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  }

The next block is called dependencies and contains the packages that project needs in order to be developed, compiled and executed.

"private": true,
  "dependencies": {
    "@angular/animations": "^4.2.4",
    "@angular/common": "^4.2.4",
    "@angular/forms": "^4.2.4",
    ...
    "zone.js": "^0.8.14"
  }

After dependencies we find devDependencies, another kind of dependencies present in the development of the application but unnecessary for its execution. One example is typescript. Code is written in typescript, and then, transpiled to JavaScript. This means the application is not using typescript in execution and consequently not included in the deployment of our application.

"devDependencies": {
    "@angular/cli": "1.4.9",
    "@angular/compiler-cli": "^4.2.4",
    ...
    "@types/node": "~6.0.60",
    "typescript": "~2.3.3"
  }

Having a peer dependency means that your package needs a dependency that is the same exact dependency as the person installing your package

"peerDependencies": {
    "package-123": "^2.7.18"
  }

Optional dependencies are just that: optional. If they fail to install, Yarn will still say the install process was successful.

"optionalDependencies": {
    "package-321": "^2.7.18"
  }

Finally you can have bundled dependencies which are packages bundled together when publishing your package in a repository.

{
  "bundledDependencies": [
    "package-4"
  ]
}

Here is the link to an in-depth explanation of dependency types​.

Scripts

Scripts are a great way of automating tasks related to your package, such as simple build processes or development tools.

For example:

{
  "name": "exampleproject",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "build-project": "node hello-world.js",
  }

You can run that script by running the command yarn (run) script or npm run script, check the example below:

$ yarn (run) build-project    # run is optional
$ npm run build-project

There are special reserved words for scripts, like pre-install, which will execute the script automatically before the package you install are installed.

Check different uses for scripts in the following links:

Or you can go back to Content of package.json​.

Managing dependencies

In order to manage dependencies we recommend using package managers in your projects.

A big reason is their usability. Adding or removing a package is really easy, and by doing so, packet manager update the package.json and copies (or removes) the package in the needed location, with a single command.

Another reason, closely related to the first one, is reducing human error by automating the package management process.

Two of the package managers you can use in NodeJS projects are "yarn" and "npm". While you can use both, we encourage you to use only one of them while working on projects. Using both may lead to different dependencies between members of the team.

npm

We’ll start by installing npm following this small guide here.

As stated on the web, npm comes inside of NodeJS, and must be updated after installing NodeJS, in the same guide you used earlier are written the instructions to update npm.

How npm works

In order to explain how npm works, let’s take a command as an example:

$ npm install @angular/material @angular/cdk

This command tells npm to look for the packages @angular/material and @angular/cdk in the npm registry, download and decompress them in the folder node_modules along with their own dependencies. Additionally, npm will update package.json and create a new file called package-lock.json.

After initialization and installing the first package there will be a new folder called node_modules in your project. This folder is where your packages are unzipped and stored, following a tree scheme.

Take in consideration both npm and yarn need a package.json in the root of your project in order to work properly. If after creating your project don’t have it, download again the package.json from the repository or you’ll have to start again.

Brief overview of commands

If we need to create a package.json from scratch, we can use the command init. This command asks the user for basic information about the project and creates a brand new package.json.

$ npm init

Install (or i) installs all modules listed as dependencies in package.json locally. You can also specify a package, and install that package. Install can also be used with the parameter -g, which tells npm to install the Global package.

$ npm install
$ npm i
$ npm install Package
Earlier versions of npm did not add dependencies to package.json unless it was used with the flag --save, so npm install package would be npm install --save package, you have one example below.
$ npm install --save Package

Npm needs flags in order to know what kind of dependency you want in your project, in npm you need to put the flag -D or --save-dev to install devDependencies, for more information consult the links at the end of this section.

$ npm install -D package
$ npm install --save-dev package

The next command uninstalls the module you specified in the command.

$ npm uninstall Package

ls command shows us the dependencies like a nested tree, useful if you have few packages, not so useful when you need a lot of packages.

$ npm ls
npm@@VERSION@ /path/to/npm
└─┬ init-package-json@0.0.4
  └── promzard@0.1.5
example tree

We recommend you to learn more about npm commands in the following link, navigating to the section CLI commands.

About Package-lock.json

Package-lock.json describes the dependency tree resulting of using package.json and npm. Whenever you update, add or remove a package, package-lock.json is deleted and redone with the new dependencies.

 "@angular/animations": {
      "version": "4.4.6",
      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.4.6.tgz",
      "integrity": "sha1-+mYYmaik44y3xYPHpcl85l1ZKjU=",
      "requires": {
        "tslib": "1.8.0"
      }

This lock file is checked every time the command npm i (or npm install) is used without specifying a package, in the case it exists and it’s valid, npm will install the exact tree that was generated, such that subsequent installs are able to generate identical dependency trees.

It is not recommended to modify this file yourself. It’s better to leave its management to npm.

More information is provided by the npm team at package-lock.json

Yarn

Yarn is an alternative to npm, if you wish to install yarn follow the guide getting started with yarn and download the correct version for your operative system. NodeJS is also needed you can find it here.

Working with yarn

Yarn is used like npm, with small differences in syntax, for example npm install module is changed to yarn add module.

$ yarn add @covalent

This command is going to download the required packages, modify package.json, put the package in the folder node_modules and makes a new yarn.lock with the new dependency.

However, unlike npm, yarn maintains a cache with packages you download inside. You don’t need to download every file every time you do a general installation. This means installations faster than npm.

Similarly to npm, yarn creates and maintains his own lock file, called yarn.lock. Yarn.lock gives enough information about the project for dependency tree to be reproduced.

yarn commands

Here we have a brief description of yarn’s most used commands:

$ yarn add Package
$ yarn add --dev Package

Adds a package locally to use in your package. Adding the flags --dev or -D will add them to devDependencies instead of the default dependencies, if you need more information check the links at the end of the section.

$ yarn init

Initializes the development of a package.

$ yarn install

Installs all the dependencies defined in a package.json file, you can also write "yarn" to achieve the same effect.

$ yarn remove Package

You use it when you wish to remove a package from your project.

$ yarn global add Package

Installs the Global package.

Please, refer to the documentation to learn more about yarn commands and their attributes: yarn commands

yarn.lock

This file has the same purpose as Package-lock.json, to guide the packet manager, in this case yarn, to install the dependency tree specified in yarn.lock.

Yarn.lock and package.json are essential files when collaborating in a project more co-workers and may be a source of errors if programmers do not use the same manager.

Yarn.lock follows the same structure as package-lock.json, you can find an example of dependency below:

"@angular/animations@^4.2.4":
  version "4.4.6"
  resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.4.6.tgz#fa661899a8a4e38cb7c583c7a5c97ce65d592a35"
  dependencies:
    tslib "^1.7.1"
As with package-lock.json, it’s strongly not advised to modify this file. Leave its management to yarn

You can learn more about yarn.lock here: yarn.lock

Global package

Global packages are packages installed in your operative system instead of your local project, global packages useful for developer tooling that is not part of any individual project but instead is used for local commands.

A good example of global package is @angular/cli, a command line interface for angular used in our projects. You can install a global package in npm with "npm install -g package" and "yarn global add package" with yarn, you have a npm example below:

npm global package
npm install –g @angular/cli

Package version

Dependencies are critical to the success of a package. You must be extra careful about which version packages are using, one package in a different version may break your code.

Versioning in npm and yarn, follows a semantic called semver, following the logic MAJOR.MINOR.PATCH, like for example, @angular/animations: 4.4.6.

Different versions

Sometimes, packages are installed with a different version from the one initially installed. This happens because package.json also contains the range of versions we allow yarn or npm to install or update to, example:

"@angular/animations": "^4.2.4"

And here the installed one:

 "@angular/animations": {
      "version": "4.4.6",
      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-4.4.6.tgz",
      "integrity": "sha1-+mYYmaik44y3xYPHpcl85l1ZKjU=",
      "requires": {
        "tslib": "1.8.0"
      }

As you can see, the version we initially added is 4.2.4, and the version finally installed after a global installation of all packages, 4.4.6.

Installing packages without package-lock.json or yarn.lock using their respective packet managers, will always end with npm or yarn installing the latest version allowed by package.json.

"@angular/animations": "^4.2.4" contains not only the version we added, but also the range we allow npm and yarn to update. Here are some examples:

"@angular/animations": "<4.2.4"

The version installed must be lower than 4.2.4 .

"@angular/animations": ">=4.2.4"

The version installed must be greater than or equal to 4.2.4 .

"@angular/animations": "=4.2.4"

the version installed must be equal to 4.2.4 .

"@angular/animations": "^4.2.4"

The version installed cannot modify the first non zero digit, for example in this case it cannot surpass 5.0.0 or be lower than 4.2.4 .

You can learn more about this in Versions

Problems you may encounter

If you can’t find package.json, you may have deleted the one you had previously, which means you have to download the package.json from the repository. In the case you are creating a new project you can create a new package.json. More information in the links below. Click on Package.json if you come from that section.

Using npm install or yarn without package.json in your projects will result in compilation errors. As we mentioned earlier, Package.json contains essential information about your project.

If you have package.json, but you don’t have package-lock.json or yarn.lock the use of command "npm install" or "yarn" may result in a different dependency tree.

If you are trying to import a module and visual code studio is not able to find it, is usually caused by error adding the package to the project, try to add the module again with yarn or npm, and restart Visual Studio Code.

Be careful with the semantic versioning inside your package.json of the packages, or you may find a new update on one of your dependencies breaking your code.

In the following link there is a solution to a problematic update to one package.

A list of common errors of npm can be found in: npm errors

Recomendations

Use yarn or npm in your project, reach an agreement with your team in order to choose one, this will avoid undesired situations like forgetting to upload an updated yarn.lock or package-lock.json. Be sure to have the latest version of your project when possible.

Pull your project every time it’s updated. Erase your node_modules folder and reinstall all dependencies. This assures you to be working with the same dependencies your team has.

AD Center recommends the use of yarn.


1. A package is a file or directory that is described by a package.json. .