Why Bower is still relevant

A guide to front-end dependencies, part II: Bower

Author's image
Tamás Sallai
10 mins

Background

Many developers consider Bower to be a thing of the past that is superseded by npm. If you are using a bundler, like Webpack or Rollup, it's certainly true. But if your webapp is missing this compilation step, using Bower is a big improvement over the traditional methods of managing dependencies.

In this article, we'll look into how to get started with Bower, then the potential issues you might encounter. This overview should give enough context so that you can hit the ground running if there is a need to introduce it to a project.

This is the written version of a screencast I've done for SitePoint. If you have a subscription, be sure to check out that too at this link.

Bower 101

Install

To install it, only npm and git are needed. After that, simply issue

npm install -g bower

to install it globally (might need sudo in some cases). After installation, use it with bower from the command line.

Usage

To install something, use bower install <packagename>; as an illustration, bower install lodash installs Lodash. Bower will download the latest version into the bower_components directory. Likewise for uninstalling, use bower uninstall lodash to remove it, and as an alternative, you can simply delete the lodash folder.

To see what packages are available, the easiest way is to use a browser and search the repository at bower.io, under Search packages. Just start typing to see the potential candidates.

bower.json

Since you usually don't want to install everything by hand, Bower supports listing the dependencies along with their versions in a configuration file. In this bower.json, you can put all the libraries and install them in a batch later with a simple bower install.

To bootstrap the config file, use bower init, which is a simple next-next-finish-style wizard. After you have it, specify --save when you install something, and Bower will update the configuration file with the new dependency. For example, bower install lodash --save will download lodash, same as before, but will also add it to the config.

Using bower.json renders the bower_components folder redundant and disposable. In case you don't have all the dependencies installed, just run bower install and everything will be downloaded. Using this, you don't need to check in the libraries to the version control, which is a bad practice anyway.

Similarly, in order to update a library, just modify the bower.json, run bower install, and push just a single line of change to the VCS.

Advanced topics

Download types

Basically, Bower requires a bower.json file at the root of the library that specifies which files are production artifacts that should be downloaded. This is the reason why many people say package maintainers should not support Bower, as it puts additional burden on them. Firstly, maintaining a separate configuration file, and secondly, to put the production artifacts into the repository.

Bower support is waning, as new libraries are unlikely to support it. But fortunately, Bower supports different types to download. If you specify a GitHub repository that is missing bower.json, Bower will download the whole repository. In this case, if the production artifacts are in the repo, they will be downloaded too, without explicit support to Bower. For example, if you issue bower install https://github.com/sashee/gentoo.git, bower_components/gentoo will contain all the files.

Bower can download any file, just like you would manually. If you specify a URL that points to a single file, Bower will download it. For example, bower install https://unpkg.com/lodash@4.17.2/lodash.min.js will create bower_components/lodash.min/index.js with lodash. This allows you to use any CDN. If you want to reference the production artifact from the npm repo, use unpkg, if you need files from GitHub, use RawGit. See the previous article where we've talked about these in detail.

Bower can also download and unpack zip files. With bower install https://jqueryui.com/resources/download/jquery-ui-1.12.1.zip, the bower_components/jquery-ui-1.12.1 will contain the contents of the package.

Use with npm

It's likely that if you have a node.js backend you are also using npm to manage its dependencies. Using bower side-by-side is tedious, and it would be nice if a simple npm install would fetch the frontend dependencies too. Also, it's usually a burden for fellow developers to manually install a new tool; ideally, npm could manage it on a per-project basis.

For this to work, list bower as a dev dependency. This is as simple as adding a new entry to the devDependencies section:

"devDependencies": {
	"bower": "1.8.0"
},

This will make bower itself managed by npm, but a separate bower install step is still needed. Fortunately, you can use a postinstall script in the package.json, that npm will run after every install.

"scripts": {
	"postinstall": "bower install"
},

This runs bower install after every npm install.

This works fine for installing new packages, but you might notice that it won't remove unused ones. If you try out a new library, then change your mind, it's not enough to simply remove it from bower.json. If you do just that, you'll still have the lib at your bower_components, but others might not.

Bower provides a prune command just for that. If a dependency is installed, but missing from the json, it will uninstall it. Since it's idempotent, it's safe to run every time.

"scripts": {
	"postinstall": "bower prune && bower install"
},

This takes care of cleaning up with every install.

Bower installer

One downside of Bower is that it downloads a plethora of unneeded files, and gives you no control over this. If a library is missing the bower.json file - which is likely - the whole repository will be downloaded.

Bower-installer is a project with the aim to remedy this. It can override which files will be downloaded and you can specify a different path and directory structure.

For several months, it seemed like the project is abandoned. But just recently Richard Quadling stepped up to maintain the library, therefore its future seems bright for now.

To get started with bower-installer, simply install it with npm install -g bower-installer and replace every call to bower install with bower-installer. Finally, define an install path in the bower.json, like this:

"install": {
	"path": "dependencies"
},

If you forget this last step, running bower-installer will raise a cryptic TypeError: Cannot read property 'ignore' of undefined. Just add the install path and the error will be gone.

If you run bower-installer, you can see that only the main files are moved to the dependencies folder. For example, if you depend on lodash, bower_components/lodash will contain the whole repository, but dependencies will contain only lodash/lodash.js.

For a dependency that supports bower, like underscore, there are still extraneous files by default. Bower-installer cuts down everything but the main file.

The best thing about bower-installer is that it's configurable, in case the default does not fit. For example, if you install bootstrap, you'll end up with a bootstrap.js and a bootstrap.less, which is definitely not enough. But with a few lines of config, you can fix it:

"install": {
	"path": "dependencies",
	"sources": {
		"bootstrap": "bower_components/bootstrap/dist/**"
	}
},

Removing unused dependencies can be done with bower-installer -rp. This removes the dependencies directory before running, and the bower_components after. This is a clean state, as no extra files are retained, and provides a clean output.

The drawback is it's slow. Removing the bower_components mean that bower needs to initialize everything, every time. A better way is to combine prune with bower-installer -p:

bower prune && bower-installer -p

This takes care of the leftover libraries in the bower_components as well as having a clean state at the dependencies. Just remove the bower_components from the VCS, and you are good to go.

SRI

We've already covered SRI in detail in the previous article, so you should read that first if you haven't already. At first sight, it seems like it's only useful to tame corrupted CDNs, and it has nothing to do with Bower. But since Bower does not check the downloaded files in any way, you still can not be sure that those are the expected files. Using SRI adds an extra layer of security, and as it's just a minor inconvenience, you should use it.

There are a few ways to generate the hashes. If you use a library that is available to the public, simply generate the hash for the upstream version and use that.

For example, if you use Lodash from CDNJS, you can install it with:

bower install https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.js

Then go to srihash.org, input the URL (https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.js), and copy-paste the hash.

Remember that this works only for the files that are publicly accessible.

Another approach is to use the snippet, and generate it yourself:

openssl dgst -sha384 -binary bower_components/lodash/index.js | openssl base64 -A

Just don't forget to add the sha384- prefix.

This works for all your dependencies, public or private, as the hash is generated locally.

Or, if you want to be super lazy, temporarily host the files and point srihash.org to that URL. One way to do this is to install localtunnel and http-server to host the files.

npm install -g http-server localtunnel
http-server --cors -p 9999 bower_components/ | lt --port 9999

This gives back an URL. Open it in a browser, find the files you'd like the hash for, open srihash.org, and generate for each file. Finally, copy-paste the hash and you are done.

You can use this method for any dependency. Just keep in mind that you are exposing all the library files for a short period of time, therefore it should not be done for anything secret.

Pros

Bower does what you would do by hand, only better. It provides a single place to define dependencies, and does everything else automatically. This way, you don't need to check libraries into VCS, as all the files can be regenerated from the bower.json.

Also, you don't need any other tools to manage dependencies. For a simple project without any modern transpilers or bundlers, it's the way to go.

Using Bower separates the front-end dependencies from the others. If you have a backend and use npm, the dependencies will be listed at the package.json and at the bower.json, nicely separated.

Cons

The biggest drawback is that it's hardly enough to issue a bower install --save and hope that all and only the needed files will be there. It's more likely that you end up with entire repos downloaded or missing files. Luckily, with bower-installer, you can fine-tune this, but it's still a tedious process.

Conclusion

If you don't use a bundler and want to avoid relying on CDNs, definitely use Bower. Avoid managing dependencies by hand and also checking them to the VCS. Bower does a good job on automation, and while you might spend some time tinkering with the configurations, you will reach a point where a simple npm install will set everything up for the project.

December 21, 2016
In this article