The Bower Bird CC BY-SA 3.0 taken by benjamint444@yahoo.com

Why my team uses npm instead of bower

tl;dr

My team moved away from Bower because:

  • Its interface kept changing
  • Some features, like the url shorthand, are entirely broken
  • Using both bower and npm in the same project is painful
  • Keeping bower.json version field in sync with git tags is painful
  • Source control != package management
  • CommonJS support is not straightforward

Substantive discussion

My team builds an SDK for creating and deploying web apps at Opower. A basic requirement for us is providing some sort of package management. We originally gravitated towards bower because it was simple and “for the web”, but since switched to npm, which provided several key advantages (at the time — this is not intended to be a side-by-side comparison of bower versus npm today). I am not recommending everyone use npm instead of bower regardless of the circumstances — I only wish to describe our evolution.

Programmatic usage is painful

Our SDK requires heavy programmatic integration with our package manager, and Bower was a little rough around the edges there. For instance, calling the API would return user-formatted strings instead of a js object, and commands did not emit meaningful events. (To Bower’s credit, they accepted PRs of mine fixing those issues.) Additionally, before the Big Rewrite, logic about parsing and normalizing bower config was locked up inside bower. After the rewrite, they fixed this with modules like bower-config.

Tool interface is unstable

Through Bower’s development, they changed interfaces and standards. This is perfectly reasonable for a pre-1.0.0 tool to do, and I don’t expect anyone to get it right the first time. However, it did add churn to our process to rename component.json to bower.json in all our packages, and our .bowerrc ended up bloated to support multiple versions of bower being used:

Some features are entirely broken

Some aspects of using bower just didn’t appear to be fully thought through. For example, the shorthand-resolver feature appears to be a nice syntactic sugar for specifying where to find dependencies. However, this feature takes effect across the entire dependency tree, which may include packages that you don’t control and don’t want to use your resolver setting. This totally breaks the feature, as people have pointed out with bower#1369 and bower#1342. If a package requires their own shorthand resolver, and you install that package as a transitive dependency of one of your own, you would see the same resolver mismatch issue.

Not everyone wants a flat dependency tree

The flat dependency tree is a good idea in many cases for web development. It’s a best practice not to send three different versions of a dependency like lodash to the browser just because you have a tree like this:

Bower added complexity for our users

Speaking of our users, Bower made their lives harder in other ways. When you specify a version of a package to install, Bower used that spec to find a git tag that matches. The version field of bower.json wasn’t actually used in this process. If there was a mismatch between bower.json and the git tag, great confusion could result. Our team had to develop tooling around this that would read bower.json and tag the repo automatically. With npm, this isn’t a problem, because when you run `npm publish`, whatever is in your package.json version field is what’s used. You’re free to tag your repo as well, but that’s just for your own workflow.

Bower conflates source control with published package management

The Bower server is essentially a url shortener. It allows you to specify a dependency like so:

Bower doesn’t make CommonJS as easy as npm

Finally, we wanted our developers to be able to use commonjs modules. Browserify (or, more recently for us, webpack) and npm work together smoothly to achieve this. If you wanted to do AMD, npm wouldn’t be such a slam-dunk, but we felt comfortable dictating this choice for our users.

Where are we now?

Because of the aforementioned issues, my team was curious about alternate solutions, such as Browserify and npm. In Fall 2013, we did a prototype, and since the first time we wrote “var _ = require(‘lodash’);” and saw it working, we never looked back. There are many modules on npm, and having a simple way to share code between the server and client is super nice. Because we’re using CommonJS, we are no longer dictating what choice our users make on whether or not to have only one version of a dependency in their tree.

Senior UI engineer @ Netflix. Opinions are those of your employer.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store