Jarad Light — Front-end Developer
Jarad is a proud son of Surrey and chooses to leave the City of Parks only when he needs to come to work or when he feels the call to travel to exotic Asian destinations.
Grunt and Bower are great command line tools for automating tedious front-end workflow tasks, and quickly adding libraries to a project. With Grunt we can define a series of tasks such as concatenating files, compressing images, running scripts, and so on. Bower is self-described as a “package manager for the web”. It provides an easy way to install a wide variety of libraries into a project, from twitter bootstrap, jQuery, font-awesome, and even your own personal repositories.
In this tutorial, we’ll look at one method of further streamlining the installation and integration of new Bower packages to a project with the help of Grunt. While the example is presented in the context of Drupal’s Omega theme, the principles can be applied to any project using Grunt and Bower.
Please note that this tutorial assumes you have a basic knowledge of both Grunt and Bower. I highly recommend taking some time to get familiar with these great tools at http://gruntjs.com/getting-started and http://bower.io
Once a library is installed with Bower, it usually sits in a
bower_components directory, waiting to be included in the project’s markup via a script tag or the script section in Drupal’s
.info file. It would be much simpler for us if these were added automatically. How we can tackle this?
Now, we could simply grab every file ending in
.js within the
bower_components directory, but that could potentially include library scripts that we don’t really need, as well as possibly including the same script twice in minified and source forms! Not all bower libraries are neatly organized, and many still come with test files and so on. Not something we necessarily need for our project.
This is where a nifty grunt plugin called
grunt-bower-concat comes in. With it, we can smartly concatenate all our Bower libraries, include and exclude specific files, and define which files need to be added before and after others.
Start by installing
grunt-bower-concat, and saving it as a development dependency:
$ npm install grunt-bower-concat --save-dev
Then add it to the
gruntfile so is loaded:
If you’d rather not have to manually add grunt tasks after installing them, it’s possible to auto-load them using another grunt task called
$ npm install load-grunt-tasks --save-dev
We can then replace all
grunt.loadNpmTasks calls with the following single line:
All tasks will now be loaded automatically, saving us from updating the Gruntfile each time a new plugin is added. Awesome!
More info can be found on the project’s repository: https://github.com/sindresorhus/load-grunt-tasks
Let’s set up some very basic configuration for our shiny new task. It’s pretty smart about grabbing the right files, so let’s see how it fares with Omega’s included Bower components. We’ll simply state a destination file that we want to add all of our libraries to.
Once that is done, we can give it a quick test to see what happens.
$ grunt bower_concat Running "bower_concat:all" (bower_concat) task File js/bower.js created. Done, without errors.
Great! All our libraries are bundled up nicely in the file we specified.
Sometimes this doesn’t happen so smoothly though. If
bower-concat cannot find the library’s files, you can tell it which files are required from each library. We can define this using the
mainFiles option, providing the library name followed by a list of files relative to the library directory.
Another important option that
bower-concat includes is dependency declaration. Usually the task is able to determine this from the
bower.json file included in the library’s root. If it isn’t included and concatenation order is important, you can define it like so:
In this case, underscore requires
jquery to be added first, while
mygallery requires both
fotorama to be concatenated before itself.
Finally, we can tell
bower-concat to ignore or only include specified libraries. This is fairly straightforward, and is done so as follows:
More options and documentation can be found at the project repo on github:
Now that our libraries exist in a single file, we can minify it using the
uglify task included in Omega’s Gruntfile. Let’s add a unique task for our Bower library file.
Since we’ll often be using our
uglify:bower tasks together, let’s create define a single task that runs them both.
We can now run both tasks with:
$ grunt buildbower
This command pulls our libraries out and concatenates them into a single file, then minifies it. All that’s left to do is to include this file in the theme’s
.info file, so it will automatically be included in the generated pages.
As it stands, our current workflow for installing a new Bower library is the following:
$ bower install jquery $ grunt buildbower
What we have so far is a great way to speed up integrating new Bower libraries into our project, but we can push it a bit further still.
It would be nice if new libraries were compiled the moment we installed them. We might try to make use of Grunt’s
watch task, but that would require us to run it every time we were about to start updating or installing libraries. Instead, we’ll try using
grunt-shell. And look! It’s right there waiting in Omega’s
Gruntfile waiting for us.
We’ll begin by adding some simple tasks to
Using ‘jquery’ as an example Bower library, these two tasks would be called like so:
$ grunt shell:bowerinstall:jquery $ grunt shell:bowerupdate:jquery
Each of them accepts a single parameter, in this case a Bower library name, and either installs the library and saves it as a dependency, or updates the library according to
We can now combine these shell tasks with our
Our new method of installing a bower library is as follows:
$ grunt bowerinstall:jquery
Both Grunt and Bower are great tools for speeding up day-to-day front end tasks. At the end of the day, your tools should suit your needs, and help you in doing your job. The method I've shown here is just one of the many possible ways of configuring them to achieve one specific goal. So give Grunt and Bower a shot, and see how they can help you out.