Building Javascript with Grunt, Bower, Browserify


Note: This post has been updated as of October 23, 2015.

This post is continuation of a previous post covering bower and browserify; if you haven’t read it yet, I highly recommend you start off by reading Getting Familiar with Bower and Browserify before starting here. Let’s review our goals regarding javascript building that we landed upon at the end of the last post:

Goal: We want to automate the gathering actions of bower and javascript-building actions of browserify in our workflow to make for a seriously powerful javascript pipeline that we don’t have to continually maintain.

We’ve covered a brief intro into bower and browserify, and now we’re ready to get our hands dirty with them both by using them with grunt.

Installing Grunt

If you’re unfamiliar with what grunt.js is, or build automation in general, please check out the grunt.js homepage for an introduction. Despite the rising popularity of Gulp (another build automation tool), I am choosing to stick with grunt as it currently still has a larger plugin community.

Assuming you already have bower and browserify installed (if you don’t, see the last post), then all we need to install is the grunt CLI:

Now that we have the grunt CLI installed, we need to establish a package.json file for our project in order to install the rest of the grunt plugins we’ll use.

Installing Grunt Plugins

Create a new package.json at the root of your project folder, or update your existing one, to include the following devDependencies:

Let’s also create a bare bones bower.json file with some base libraries:

To install node modules:

This will install the bower and browserify grunt tasks, as well as verifying that you have the regular browserify module installed. Let’s hold off on installing our bower components yet, we’ll let grunt take care of that.

Now that we have everything set up, we can finally start our Gruntfile. Let’s start off with the basics:

Creating the Gruntfile

We don’t have anything exciting yet – just a basic Gruntfile skeleton. Let’s start off our workflow by automating our bower component installation:

These settings are customizable, but I’m a fan of dumping all my vendor packages into a /vendor directory. The layout attribute states that the package will be within its own folder (as opposed to default js/css/etc. folders that bower likes to use), and the cleanup option ensures that prior to the install command being run, the directory will be wiped out.

Now we can install our bower components like so:

We will now have jQuery and Modernizr installed in /vendor/bower_components. Perfect – now let’s get to using those files with the help of browserify. Let’s add this to our Gruntfile:

This will take a javascript source file (or many) and build it out into a browserify bundle that is browser friendly. So our end goal is to create a bundle from a file like this:

But can we do this? Alas, no, not yet. We have three problems:

  1. While we have jQuery and modernizr installed through bower, browserify has no idea where they’re located, so we can’t just require them like we are – we would need to require exact script locations.
  2. With modular programming, we would need to assign jQuery to the $ variable, and modernizr to the Modernizr variable before we could use them in that way.
  3. Browserify can only require CommonJS style scripts … so basically modules, and while the scripts we have for jQuery and modernizr may be built as modules, we can’t be sure. Plus, we still want to be able to require other vendor scripts even if they’re not modules.

So have we come this far for me to tell you we can’t do anything, and you can only use browserify for your own CommonJS style scripts? No, absolutely not! We can fix this with an awesome node module called browserify-shim.

Adding Browserify-Shim

Browserify-shim is a node module which allows you to include non-CommonJS style scripts into browserify’s require command, and to also assign them to aliases that you can use in your scripts. You can check out the GitHub repo to see all the features, but we’ll just go over installation and implementation here.

Install (as a devDependency here):

And then add this to your package.json:

In a nutshell, browserify-shim is exposing our jQuery and modernizr packages as a different name for browserify to look for (jquery and modernizr, respectively), and then we are aliasing the modules to the variables we’re used to using: $ and Modernizr. Lastly, we tell browserify to run browserify-shim prior to building out the files, which is what allows all of this to happen.

Browserify-shim can do even more than this, but that’s all we need it for. Now will this javascript work?

Yup, 100% as long as we’re using grunt to build our javascript.

Summary

I know we’ve covered a lot here, but if you can implement this workflow into your javascript pipeline, you’ll seriously boost your productivity. To review everything we’re doing here:

  • Using bower to simplify how we get our vendor scripts, as well as managing versions easily.
  • Using browserify-shim to turn all non-CommonJS scripts into browserify-compatible modules.
  • Using browserify to write modular javascript code, and build everything we want into a small amount of organized bundles.
  • Running everything through grunt to handle all the tedious work for us, so we can concentrate on the fun stuff.

While the big benefit here is that we have really improved our workflow to allow powerful services to do the work for us, another thing to consider is that now we can really true modular code. That’s a best practice in every language, and having that at our disposal allows us to write clean, beautiful javascript that is very readable and very debuggable.

You made it to the end, and now at least have some familiarity with using bower and browserify in your project. Give it a try and see how you feel about your new javascript build process. I promise you won’t be disappointed!

  • Is there any way to automatically fetch all dependencies from bower? For example one of my projects uses a lot of external libraries, including jquery, react, noty, etc. It is going to be a little bit hard to import all those dependencies via browserify-shim.

    • alkrauss48

      Not yet I don’t think, but this shouldn’t be difficult to implement. One option if you are using a common lib like jquery or react is to use the node module version and include it in your package.json as normal, which would skip browserify-shim altogether. Browserify will see it in there and know how to compile it.

      But more realistically for smaller libs, you should only have to add a line like this to the browser key in your package.json file like:

      “jquery”: “./vendor/bower_components/jquery/jquery.js”,

      subbing the parts out to be specific to your plugin. That should be all you need to add.

      • A lot of packages on bower comes in compliance with CommonJS standard, but you still have to import them trough package.json, which is not cool.

        • alkrauss48

          Really? Maybe I’ve just gotten lucky, but if I download a CommonJS dependency through bower, then I just have to “require” the actual file path in my pre-browserified javascript and it all seems to work. Additionally, if you want to load a non-CommonJS plugin into the general scope like you would a normal javascript file (and not assign it to a variable), you could also just require the file path as well and not assign it to anything in your pre-browserified javascript.

          Have you run into any problems using it like that? I’m not sure what the best practices are about that, seeing as how browserify is ideally used for CommonJS modules.

          • I actually don’t know what are the best standards here, because I just started to use browserify with Flux/React. But actually after reading trough bunch of source code I think I’m finally got the idea behind browserify. There is no difference between frontend and server side, your code can be executed anywhere and produce same result. That’s why they use npm instead of browserify.

      • CameronJRoe

        Considering browserify is all about requires in front-end code, wouldn’t it be useful for it to traverse bower packages similar to node_modules for installed dependencies? This way one could easily use a lib from bower or npm with just the package name.

        • alkrauss48

          That would be very nice, but I haven’t seen any tools that do that. Browserify-shim, while still very awesome, requires you to list out the file locations in your packcage.json of your non-CommonJS files. One thing to keep in mind too though is that a lot of front-end packages these days are being written in CommonJS style anyway, so you don’t even need browserify-shim for those. So for your larger JS libs, you really shouldn’t have much problem requiring them with plain browserify – but for the smaller libs, I just stick them in the browserify-shim section of the package.json

  • bob

    Your second to last screenshot “And then add this to your package.json:” isn’t that actually your Gruntfile.js?

    • alkrauss48

      No, that’s the package.json. Those keys (browser, browserify, and browserify-shim) are all valid keys that browserify and browserify-shim will look for. Grunt just handles the automation – both of those packages still require config in the package.json because they are both node modules.

      • bob

        Thanks, just learning this. How do I browserify both bower_components (jquery, bootstrap, etc.) AND application javascript files (main.js, etc.)? My goal is for all js to end up in one minified file than will work with browserify requires….

        • alkrauss48

          If you look at that last code block in this post, you’ll see I both require jquery and modernizr (both of which are bower_components with paths set in the package.json). Just as you require those modules, you can also require custom modules that you write as well, and use the path of the file inside the require quotes. Now you might think “I’m not writing modules, I just have regular client-side code;” if that’s the case, I suggest you look at how to write a CommonJS style module to house your javascript. It’s just a great way to structure your javascript, even if it’s all client-side logic. If you do any Node.js too, that’s the same style that node modules use too.

          Alternatively, if you don’t want to write CommonJS-style javascript, then you can ‘require’ the physical path of those files too, but you’ll probably need to use browserify-shim and update your package.json to do that like we discuss in this post. Some javascript code is still ‘requireable’ even if it’s not CommonJS-style, but it’s best to keep it CommonJS such when you use browserify with custom JS code.

          To show you an example project, Staplegun (my company) has a starter-template that browserifies both vendor javascript and custom javascript in the same file:

          https://github.com/Staplegun-US/site-start/blob/master/src/js/app.js

          Check out the full github repo to see how everything fits, but that repo is a full example that uses everything discussed in this blog post.

  • Pingback: Getting Familiar with Bower and Browserify | Aaron Krauss()

  • Marcello De Sales

    Do you have a git repo with a starter code?