Manage project dependencies with npm

featured image

Proper handling of javascript dependencies allows every team member to use the same library versions during project development. Keeping them consistent prevents many elusive errors and can be easily achieved with npm.

Requirements

You will need npm, the Node package manager, installed on your local machine. The nodejs package contains the nodejs binary as well as npm, but the version of the latter can be a little behind the latest available. It is considered good practice to install the most recent  npm version separately. To see whether you already meet those prerequisites, run in your command line:

If they are not present, run:

Shall you need to, check out other resources for more detailed information and alternative options to install nodejs and npm on Ubuntu.

Manage npm modules

To organize external javascript libraries, we need to keep all information required to download them in our repository. This will allow every team member to build the application with the same dependencies. It is attainable thanks to the package.json file which can be easily generated from your command line.

If you are using a framework, check out its documentation to see where the package.json file should be stored.

In this example, we are managing assets in a Spring Boot application and this framework uses the static directory to store all static resources. Go to it’s location:

Run $ npm init --yes  to create the default package.json file. In case you want to specify some information about your project, just run the command without the --yes flag, so you can answer questions from the questionnaire:

You can find an explanation to every attribute in the npm documentation.

An example file structure:

Libraries required during the development process can be included with  $ npm install --save-dev package_name, those needed on a production environment are installed simply by typing  $ npm install package_name .

Use SemVer notation to control versions consciously

This notation separates changes in a library lifetime into three categories: major, minor and bug fixes. By suffixing a required version with ^ or ~ you can regulate which improvements will be part of your project dependencies with every $ npm install  and $ npm update .

You can specify allowed versions in the package.json file with:

  • ^4.5.1  – the update will install the newest release of the major version (4.*.*), which will introduce patches and new features but hold the backwards compatibility;
  • ~4.5.1  – the update will install the newest release of the minor version (4.5.*), which will introduce just bug fixes;
  • using npm range calcucator.

You can read more about SemVer in its documentation.

Commit only the files you need

The package.json  as well as package-lock.json files should be commited. The latter can be created by running the following command in the directory which already contains the package.json file:

It contains information about specific version, location as well as requirements for every dependency given in the package.json file. It also confirms the integrity of the installed dependecies with hashes. Thanks to all those data, the package-lock is the source of truth for javascript dependencies and every time someone installs them, the downloaded libraries will be exactly the same, despite the latest major or minor release available (remember the semver notation from above). This allows you to share unified dependencies across the team.

In contrast, there is one directory you have to exclude from tracking, namely node_modules. It is created during either:

  • $ npm install package_name  – if there are no dependencies in the package.json;
  • $ npm install  – if there are already defined dependencies in the package.json.

The directory contains all libraries specified in the package.json file and additional modules required by npm itself. Each developer will have this folder downloaded locally by npm, so add it to your .gitignore file:

Now you can commit your changes:

Update or remove a package

A package is identified by its name and version. When you want to change a package version to a newer one  (allowed by a ^ or ~ suffix), run $ npm update package_name . Remember that calling $ npm update  updates all packages in accordance with given ranges.
To remove a package from your project dependencies, execute $ npm uninstall package_name .

Unify dependencies across all machines

Now every developer working on the project can have the same dependencies installed on his or her local machine by simply running the following command:

This will result in installing all required libraries in their given versions. The packages will be placed in the node_modules directory.

Technically, all libraries can be downloaded manually and placed in the correct directories. However, it is time-consuming and can lead to confusion among the project contributors and errors during collaboration. I think that keeping your node_modules organized with npm makes sharing the project much more effortless.

Automatic security check

From npm@6, you can check the libraries installed in your project for security issues. Just run:

in a directory with the package-lock.json file and examine the outcome. Some of the found vulnerabilities can be fixed automatically by running:

It’s a very convenient way of assuring that your project is free from javascript security liabilities.

You can find countless useful features of npm by browsing its blog.

Photo by Tim Trad on StockSnap

Leave a Reply

Your email address will not be published.