Recently I’ve been doing some work on a set of AngularJS component
(directives, services, etc) and I’d like them to be available in Bower.
There are plenty of guides out there on installing Bower components, but I couldn’t find many on creating, registering and updating your own Bower component.
One of the difficulties I’ve been facing is how to publish the build files without dirtying up our PRs*. If build files were checked in with the PRs, then code reviews would be difficult, due to it being littered with minified/generated files that don’t really need review.
In my search for an answer, I ran across a post about treating the build directory as a Git Submodule. In theory, you can keep a separate repo for the build files and, using a git submodule, commit the build files to that separate repo while in the same main directory.
I tried what was outlined in the post. I created my separate repo. I created a Git submodule. But all the while a voice in the back of my head kept saying, “You know git submodules have a reputation of being too complex and unwieldy”. After a few hours of trying, I had finally admitted to myself I was right. I just don’t know enough about Git and submodules to make the complexities of it work.
Luckily, right after giving that path up, it hit me that I could use a specific Grunt plugin to do the dirty work for me. While there are some Bower Grunt tasks out there, the one I ended up using had nothing to do with Bower.
Through some quick configuration, I realized that the Grunt gh-pages plugin had a feature in it that was perfect for my needs. Instead of using a submodule, I’d just configure gh-pages to publish my build folder to the separate repo.
What’s great about this method is that it’s so clean. The plugin makes a temporary copy of your code in a .grunt folder, checks out a different branch (which would normally be ‘gh-pages’), then copies the code back in and commits it to the branch (along with pushing, tagging, etc).
While it doesn’t specifically need it, the gh-pages plugin has an option to publish to a repo other than the one you’re in. This was perfect for my needs. Here’s the config I used for the gh-pages options object:
bower: {
options: {
base: 'bower',
branch: 'master',
message: 'chore(bower): release v<%= pkg.version %>',
repo: 'https://github.com/rackerlabs/encore-ui-bower.git',
tag: '<%= pkg.version %>'
},
src: '**/*'
}
By being able to customize the base folder to use, the repo I want to publish to, and by being able to tag each release with a version, it satisfies all the requirements I need to get bower working.
There was some other work I had to set up to copy and rename all the files to prep them for Bower. Since Bower uses tags instead of filenames for versioning, I have to strip out that version number from the filename. I do that with the Grunt Copy task:
bower: {
files: [{
expand: true,
cwd: 'dist/',
src: '**/*',
dest: 'bower/',
// remove version number from file names
rename: function (dest, src) {
var strippedVersion = src.replace(/\-(?:\d\.){2}\d/g, '');
return dest + strippedVersion;
}
}, {
src: 'bower.json',
dest: 'bower/bower.json'
}
]
}
I also copy the bower.json file from the root folder into the bower folder.
The major drawback to all of this is having to manage two repos, which includes managing permissions for both. This means any time someone new joins the team (or someone old leaves), permissions need to be updated in two place.
To avoid this, I need to figure out how to have bower load from a specific branch in a repo. Then I can just publish the code to a ‘bower’ branch in just the same way I do with gh-pages.
For now this works and is an acceptable place to be.
*I may be naive for thinking build files can’t be checked in. There’s probably a really simple method for managing it. After all, there are libraries out there that check in their build files (YUI3 being one of them). But it looks like they just check in their build files with their PRs, which is what I want to avoid. I’d venture a guess that a tool like TravisCI could help out, but I haven’t looked in to it yet.