Checking in front-end dependencies
July 30, 2013
Package management is an important and evolving area in front-end development. It's also a contentious one with some favoring Bower, others preferring npm and Browserify and a number remaining undecided about the true benefits of these tools. Regardless of the solution you opt for you will come to a point where you will need to decide whether or not you want to check-in the dependencies installed by your package manager into source control.
Note: For those new to Bower, it's an unopinionated, generic package manager for the web platform that aims to help with front-end package management. Bower works over git, its packages can be made up of any type of asset HTML/CSS/JS and use any type of transport (CJS/AMD/ES6 modules). It's currently used by Bootstrap, Normalize, AngularJS and many other open-source projects.
For those used to working in Node, this is not a new problem and has been regularly discussed in terms of checking-in node_modules into git. It is however a topic that requires some thought around newer solutions like Bower. The following advice is listed on the Bower homepage:
“If you aren’t authoring a package that is intended to be consumed by others (e.g., you’re building a web app), you should always check installed packages into source control.”
This takes a number of developers by surprise, as some feel you should only have to check-in your bower.json file and run bower install
as a part of your tooling-chain instead of checking in all of your /bower_components
. Let's talk through the pros and cons of both approaches.
Check Them In?
Let's say you're deploying to production and perhaps have an install or pre-deploy step that runs bower install
. GitHub is having network issues, so now you can't deploy because your dependencies cannot be fetched. This is one of a number of reasons you might want to check in your /bower_components
folder.
Those that like checking in their dependencies do so to avoid the remote being down (which may in fact prevent deployment) and to prevent bad dependencies from breaking their app. This could happen even with the presence of a build step as you probably don’t test on each build. Another concern people have is the longevity of package managers and their tooling - as one developer put it: "I worry that 5 years down the road when my app is still in use, these tools may not be around or be completely different".
That said, the main reason proponents of checking dependencies in favor it is that GitHub may be down, a sub-sub dependency might be unpublished and you really just want to be able to keep the same environment most of the time. Sindre Sorhus, of the Yeoman and Bower teams, prefers this approach, as locking down dependency versions, even at a deep level, isn’t always sufficient as tags and versions may be overridden.
Checking in dependencies is considered a best-practice for deployable projects (not reusable modules) in Node and some feel it should be followed when using Bower too.
Keep Them Out?
The flip-side of the argument to check in your dependencies is that you should only check in your bower.json file, and not your /bower_components
folder. The benefit of this approach is that this will keep your repo smaller.
As mentioned, those that prefer to just keep around their bower.json file might just be running bower install
as a part of their continuous integration. Your CI might just pull in your dependencies, run all the tests and if it happens that everything works, deploy the exact copy generated onto your staging system.
The downside to this approach is that while you can pin down the dependencies your application directly uses, you can’t directly control the dependencies further down the graph until bower receives a shrinkwrap capability. Running bower install
used to be quite slow, but with the recent release of 1.0 bower gained a dramatically improved cache which makes this less of an issue.
With a clear separation between the staging and production deployment processes, this approach can work really well. On a staging system, the application can be thoroughly tested and once it has been verified to work with its current dependencies, the whole project can be cloned over to the production system. This ensures that no further version changes occur between the staging and production deployment.
In Bower 1.0, the --offline
flag can help if the remote isn’t available as it can fully fetch package dependencies if they have been fetched before and happen to be compatible. Bower will also be getting a shrinkwrap option in the future, which will allow you to lock a project’s dependencies to a specific version installed so that when someone installs a locked project it will get the exact same code (by checking out commits etc). A combination of the --offline flag, a persistent CI environment keeps the Bower cache between builds and Bower’s shrinkwrap might alleviate the need to commit dependencies.
Words from the Bower team
On this topic, Andre Cruz, one of the main maintainers of Bower feels that if the project you are working on is a medium-large in size where you can't simply rely on the package manager, then commit your dependencies. On the other side, if you can't live with huge repositories, where 3rd party code is also committed, then don't do it. Note that committing deps is only a problem that exists at the top level (application level), not in reusable modules.
So...
Ultimately, the choice of whether or not to check-in all of your /bower_components
directory is up to you but it's important to be able to justify the option you choose for the right reasons. We hope that this post at least provides some food for thought during that decision process.
With thanks to Sindre Sorhus, Pascal Hartig, Stephen Sawchuck and Andre Cruz