Posted by & filed under Content - Highlights and Reviews, Programming & Development.

code A guest post by Domenic Denicola, who works on web apps as a consultant at Lab49 in New York City, while in his spare time maintaining many open-source Node.js and web libraries. He’s recently been involved in building better standards for the web and for JavaScript as a whole, such as the Promises/A+ specification, the ES6 promises spec, and the work-in-progress WHATWG streams specification, and can be reached at @domenic.

In the last post in our series, we set you up with Grunt on a very simple demo project. We only had Grunt run a single task, but ended the article by promising you that much more was possible. It’s time to make good on that promise.

Automatic Module Bundling with grunt-browserify

Every project that gets large enough needs a module system, and browserify is one of the more powerful out there. Browserify needs a build step, which can be tricky to set up, and certainly annoying to run manually. But let’s make Grunt do that for us, so we can tie it into our larger task setup and reap the benefits.

Open our project directory from last time. To install the grunt-browserify plugin with npm, run the following command:

This will install grunt-browserify into your project, and also save it in your package.json’s devDependencies section. Now, let’s add a couple of modules to your project. Get rid of lib/script.js from last time, and add these two:

Also, modify index.html‘s <script> tag to point to bundle.js, instead of the old lib/script.js.

Finally, we need to add the grunt-browserify task to our Gruntfile. Here’s one way to do that:

As before, we first load the task at (1), configure it at (2), and at (3) we create a new task, called build, that encapsulates running both JSHint and browserify. The configuration says that we’ll be creating a file called bundle.js by browserifying the lib/entry.js file as our starting point; anything that it require()s will be automatically bundled as well, so we don’t need to list those explicitly. And we create a build task because later, we might want to compile our Stylus or Sass as part of the build, so it’s good to keep the command names generic. Also, at (4), note that I added a node: true line to our JSHint config, since browserify lets you use Node’s module system, and you need to tell JSHint about that.

With this all in place, we can try out our new build process by running grunt build. The result should be something like the following:

Multi-tasks and targets

You may have noticed that something was slightly different about our browserify config vs. our JSHint config in the Gruntfile. Namely, the Browserify config had an extra dev object in which we put the files and options fields. This is because grunt-browserify is a so-called “multi-task.” This means you can configure it in multiple different ways, by specifying different options for each target.

Targets are a pretty useful concept when running tasks for your project. For example, let’s configure browserify to have separate dev and release targets. In release mode, we won’t run JSHint, and we’ll turn off browserify’s Source Maps by setting debug: false. The resulting Gruntfile looks like:

Now, you can run grunt dev to get the previous behavior, or run grunt release to get a release bundle! Things are starting to come together.

Watch Mode with grunt-contrib-watch

Perhaps the most impressive trick Grunt has to offer is the grunt-contrib-watch plugin. This simple plugin allows you to run any set of Grunt tasks when certain files change, releasing you from the tedium of manually running your build steps. The fact that its usefulness is multiplied by that of the entire Grunt plugin ecosystem is the best part.

For now, let’s just set ourselves up to run our build:dev task in the background. First, run:

Then, add it to our Gruntfile, in a manner that is probably starting to become familiar:

The watch task has a bunch of useful options that you might want to configure, but for now we’ll leave it at the defaults.

To fire up the watch process, run grunt watch, and open up index.html in your browser and open the console to see the results. You’ll first just see this:

Now go and change something! For example, I added an exclamation point to the logged string in lib/entry.js, and got this:

Then I reloaded the index.html page in my browser, and indeed, the exclamation point appeared!

This works for the JSHint part of the build:dev task too. Try removing the 'use strict'; from the top of lib/adder.js:

So now you have Grunt set up to automatically catch lint errors as you work, in addition to browserifying your modules. You can see where this is going: we could use another Grunt plugin to run our tests in PhantomJS, or another to compile our Stylus into CSS.

The Endgame

Where does it end? Well, for a serious web development project, you’ll probably end up with a Gruntfile something like this:

Here we’re combining many Grunt plugins to provide many possibilities:

  • grunt validate will just run JSHint and your Mocha tests to make sure everything’s working.
  • grunt dev will do a full development build, validating first and then compiling the Stylus into CSS and browserifying our JS modules, both with debug-friendly options turned on.
  • grunt dev-novalidate will do the same as grunt build:dev, but skipping the validate task, in case you want to just hack a bit.
  • grunt release will do a full release build, browserifying without debug information, then using UglifyJS to minify the bundle in-place, and finally compiling and minifying the Stylus files.

We also have the watch tasks:

  • grunt watch:validate will watch for any changes to your JavaScript modules, and run our JSHint and Mocha tests on them.
  • grunt watch:browserify will watch for any changes to your JavaScript modules, and browserify them.
  • grunt watch:stylus will watch for any changes to your Stylus files, and compile them into CSS.
  • grunt watch will run all three of these in a row.

Conclusion

Hopefully I have given you an idea of the true power of Grunt for automating your web development workflow. You can learn more from the Grunt documentation, or get an idea of the possibilities by checking out the official Grunt plugin list.

But there’s still a few more tricks to learn. Come back next time for a short article exploring some ways to get fancy with Grunt.

See below for Grunt resources from Safari Books Online.

Not a subscriber? Sign up for a free trial.

Safari Books Online has the content you need

Jasmine JavaScript Testing is a practical guide to a more sustainable JavaScript development process. You will learn by example how to drive the development of a web application using tests and best practices, and you’ll find a good section on Grunt.
Developing a Backbone.js Edge incorporates best practices and the techniques from the combined authors’ experience of developing many Backbone applications. Some of the resources on the web advocate inefficient or inelegant solutions and there are few that cover the whole library, and you’ll find a section on Grunt.
Eloquent JavaScript is a guide to JavaScript that focuses on good programming techniques rather than offering a mish-mash of cut-and-paste effects. The author teaches you how to leverage JavaScript’s grace and precision to write real browser-based applications. With clear examples and a focus on elegance, Eloquent JavaScript will have you fluent in the language of the web in no time.

Tags:

Comments are closed.