Antoine Lehurt

npm as a front-end package manager

Vous pouvez lire la version française de cet article.

npm has played an important role in Node.js success. It facilitates the creation, sharing and installation of packages and allows developers to follow the Unix philosophy where each module “do one thing well”. (Avoids complexity, facilitates code reusability and testing.)

However, npm isn’t limited to JavaScript modules. It’s possible to publish any type of file and this is where it gets interesting for our front-end modules, which can be CSS, HTML, fonts, etc..

JavaScript module

If you are not used to creating packages, I recommend you run the command npm init which helps you to generate the package.json (this file contains all the information used by npm).

{
  "name": "my-javascript-module",
  "version": "0.0.1",
  "main": "index.js"
}

If you want to write a module that work everywhere: AMD (RequireJS) , CommonJS (Browserify) or directly with the window object, you should take a look to UMD patterns repository. There are different types of wrapper to export your API. For instance:

(function (root, name, definition) {
  if (typeof define === 'function' && define.amd) {
    define([], definition);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = definition();
  } else {
    root[name] = definition();
  }
})(this, 'ModuleName', function () {
  // Here, you define the API of your module.

  // You can return a value, a function or like
  // in this example, an object.
  return {};
});

Module for other file types

In the [files](https://docs.npmjs.com/files/package.json#files) field, we can define the list of files we want to publish (CSS, fonts, SVG, etc.). For instance, a package.json for a CSS grid module.

{
  "name": "grid-system",
  "version": "0.0.1",
  "files": [
    "grid.css"
  ]
}

Once you have published and installed (npm install grid-system --save) the package, the grid.css file will be located in node_modules/grid-system/grid.css. Therefore you can include it in your HTML files or @import it inside your Sass files. (The Sass option --load-path is really useful if you don’t want to have to specify the path to node_modules each time you import a module.)

<link href="node_modules/grid-system/grid.css" rel="stylesheet" type="text/css" />

Also, if you need to publish different versions of your JavaScript module (dev, prod, minified) you can add them to the “files” field as well.

How to install a module without a package.json

Sometimes you find the perfect module that fits your needs, unfortunately it doesn’t have a package.json. Therefore you can’t install it with npm. You have two options that can solve this:

Solution 1: Fork the repository

The first solution is to fork the repository, add the missing package.json and submit a pull request. In the meantime you can install the package using the Github namespace: npm install yourUsername/the-perfect-module --save. But sometimes people don’t want to “pollute” their repository with a bunch of configuration files and reject your PR.

Solution 2: Napa

Napa is “a helper for installing repos without a package.json with npm”. Once you have installed it, you are able to add the perfect module as a dependency of your project. Napa will download the entire repository in node_modules directory. Napa’s readme file is well detailed, I don’t think it’s necessary to c/c everything here.

For instance, a project using Three.js:

{
  "name": "my-project",
  "version": "0.0.1",
  "scripts": {
    "install": "napa"
  },
  "napa": {
    "threejs": "mrdoob/three.js#r67"
  },
  "devDependencies": {
    "napa": "^0.4.1"
  }
}

Why npm rather than another package manager:

  • It has already proved its worth with Node.js.
  • No need to install new tools, you just need a package.json.
  • You can manage all your dependencies with npm: tasks runner (Gulp, Grunt, etc.), JavaScript modules, tests, CSS, assets… everything!

I think it’s important to keep things simple, starting with using only one package manager. Especially when you just need to download packages. (Some, like Component, have a build system in addition to the dependency manager.)

So, why do you need Bower?