Manage web project dependencies using NPM

Libraries/Dependencies/Packages - there are many names for reusable pieces of code. We are using them from the begin of software engineering. They help us to resolve complex problems with relatively small effort. Nowadays, even simple projects may depend on many different sources spread across the internet. Downloading libraries by hand from the websites is not the best way to include them in our projects. Storing libraries on disk, or worse, keeping them in VCS is really bad idea. Staying up-to-date is another issue. Java world, for example, has their maven to automate dependencies management. It works ok with jars not with java scripts. How modern web resolve these problems...

Background

NPM (Node package manager) has been invited to help Node.js developers manage their javascript dependencies. It turns out that npm can be successfully used in projects not related to the Node.js technology. Let's leave Node topic for one of the further posts. For now, you should know that Node.js is a javascript runtime (using V8 engine internally), providing so-called event-driven, non-blocking I/O model designed to build scalable network applications.

If you are still interested what Node.js is in details I highly recommend you to watch this video.

NPM installation

NPM can be installed together with Node.js using installer from the official website (npm is written entirely in javascript and use Node.js as a runtime environment). Mac or Linux users may use integrated package manager, npm is available in homebrew or yum. To check if npm is installed you can simply run:

npm -v

Playing with NPM

Let's assume that our project require jQuery. To download it just execute

npm install jquery

NPM should create node_modules/jquery directory containing jquery files. Piece of cake. But our project is growing! It turns out that we need also bootstrap and underscore. We can install them using the same command as before, but this is not convenient when we need to share our project with others. It would be great if we can just define all the dependencies within single configuration file (like pom.xml from maven). It is possible by project.json descriptor. We can create it manually or using interactively command. To do so, just type

npm init

and follow the prompts.

Example file may look as follows

{
  "name": "awesome-modern-web-project",
  "version": "1.0.0",
  "description": "some project description",
  "main": "index.js",
  "dependencies": {
    "jquery": "^2.2.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "make test"
  },
  "author": "cslysy",
  "license": "ISC"
}

For now, the most important part is dependencies and devDependencies. Within dependencies we can define our runtime project dependencies whereas devDependencies defines libraries required to develop like coffeescript to javascript transpiler or unit-test support.

New dependencies can be added in a two ways, manually or using a command. In order to tell npm that we need bootstrap just add it within dependencies:

{
  "dependencies": {
    "jquery": "^2.2.0",
    "bootstrap": "^3.3.6"
  }
}

and execute

npm install

As a result, npm will download bootstrap. As it was mentioned before we can do the same using npm command

npm install underscore --save

The --save argument tells npm to add underscore definition to dependencies section after downloading. If you need some libraries only for development support just define them in deveDependencies or execute

npm install coffee-script --saveDev

That's the way to install developer dependencies. What if we decide to use coffe-script in other projects, do we need to install it again? The answer is NO. Coffee-script transpiler is only a tool. Do you install Netbeans or other favourite IDE for every single java project you are working on? NPM let's us decide whether we want to use package locally (single project scope) or globally. By default packages are installed locally. In order to install package globally use -g (or --global) mode

npm install some-pakage-name -g

This command may require some write permission. If you receive EACCES error try to fix npm permissions according to this how to.

Conclusions

Node package manager is a great tool that help us control all the mess related to project dependencies management. Someone may say that NPM is not the best choice for the web projects favoring Bower as a better one. If you are interested what is wrong with Bower please read Why We Should Stop Using Bower.

What's next

Our dependencies are downloaded but how to use them? Linking them in our project by pointing into node_modules/modulename sounds at least strange. Dependencies should be copied somewhere creating, together with other files, target project structure ready to be deployed to development or production environment. Copying all of them manually is pure madness. That's the topic for the next experiment. How to automate copy or minification processes? How to build project distribution? Stay in touch by subscribing my blog activities!