The Brunch Build Tool
This is a guest post by Michael Schmatz, Lead Developer at CodeCombat
One of the most important parts of CodeCombat’s development workflow is Brunch. In this post I’ll tell you why CodeCombat chose Brunch, run through setting up a basic Brunch project, explain CodeCombat’s Brunch configuration, and compare Brunch to several popular alternative build systems.
Why CodeCombat uses Brunch
In early 2013, CodeCombat was just getting started. One of the cofounders, Nick, wanted a workflow skeleton to kickstart development. After examining several different tools, including Brunch and Yeoman, he ended up choosing Brunch, mainly because of the awesome project skeletons available.
As time went on and the build times grew and grew, we appreciated one design choice of Brunch more and more: incremental rebuilding and caching. For small projects, the time difference between partial and complete rebuilds isn’t very significant. However, for large projects, long build times can be very detrimental to developer efficiency and happiness. Doing a complete rebuild of CodeCombat can take a few minutes on older computers, whereas partial rebuilds only take a few seconds, if that. Such responsiveness is integral to our development process.
Setting up a basic Brunch project
First, we need to install Brunch. Once you have npm installed, just run:
npm install -g brunch
To get us started, we can use Brunch’s built in skeleton installer. There are many skeletons to choose from; I chose one of the more popular ones that includes AngularJS, CoffeeScript, LESS, and Jade.
brunch new gh:scotch/angular-brunch-seed jetbrains
All we have to do now is start Brunch. Move into the new directory, and then start the Brunch watcher/server.
cd jetbrains brunch watch --server
Now any time we make a change to our app, Brunch will automatically recompile the files that changed, rebuild the app, and refresh the page. On my machine, this takes only about 70ms.
Let’s change the header on the front page. Open up your favorite IDE and start editing
app/partials/todo.jade. In addition, open a web browser to the URL Brunch provided, in my case,
Notice how, if you change something, for instance the
<h2>, the app automatically is rebuilt and the page refreshes.
CodeCombat’s Brunch Configuration
sysPath = require 'path' startsWith = (string, substring) -> string.lastIndexOf(substring, 0) is 0
The file starts off by importing the
pathmodule and declaring a utility function,
exports.config = paths: 'public': 'public' conventions: ignored: (path) -> startsWith(sysPath.basename(path), '_') sourceMaps: true
Then, we tell Brunch to place all compiled files in the
publicfolder, ignore all paths which start with an underscore, and generate source maps.
order: before: [ 'bower_components/jquery/dist/jquery.js' 'bower_components/lodash/dist/lodash.js' 'bower_components/backbone/backbone.js' # Twitter Bootstrap jquery plugins 'bower_components/bootstrap/dist/bootstrap.js' # CreateJS dependencies 'vendor/scripts/easeljs-NEXT.combined.js' 'vendor/scripts/preloadjs-NEXT.combined.js' 'vendor/scripts/soundjs-NEXT.combined.js' 'vendor/scripts/tweenjs-NEXT.combined.js' 'vendor/scripts/movieclip-NEXT.min.js' # Validated Backbone Mediator dependencies 'bower_components/tv4/tv4.js' # Aether before box2d for some strange Object.defineProperty thing 'bower_components/aether/build/aether.js' 'bower_components/d3/d3.min.js' 'vendor/scripts/async.js' ]
This section specifies all of the files that should be loaded before the others are compiled.
This section specifies how the stylesheets and templates should be compiled, as well as the skeleton framework.
plugins: autoReload: delay: 300 coffeelint: pattern: /^app\/.*\.coffee$/ options: line_endings: value: "unix" level: "error" max_line_length: level: "ignore" no_trailing_whitespace: level: "ignore" no_unnecessary_fat_arrows: level: "ignore" uglify: output: semicolons: false
This specifies the plugins we use:
auto-reloadis used to refresh the browser whenever Brunch recompiles,
coffeelint-brunchis used to keep our CoffeeScript files clean, and
uglify-js-brunchis used to, well, Uglify our code.
The final step is to replace the source map URLs in the compiled files with a small Perl regex.
Gulp, the newest system of the three, is a bit different from either Brunch or Grunt in that it uses Node streams to achieve high performance. Its ecosystem isn’t as large as Grunt’s, but it’s still pretty large with 600+ plugins. The configuration files are very simple. Like Grunt, it doesn’t have great skeleton support or caching or incremental rebuilds built in, but has well-supported plugins which provide that functionality. Those plugins combined with the streams make Gulp the winner in terms of pure performance.
You really can’t go wrong these days with build tools as long as you consider the anticipated scope, size, and technology requirements of your projects. Grunt has the largest ecosystem and most flexibility, Gulp has the best performance, and Brunch provides the easiest setup and great out-of-the-box performance. At CodeCombat, we’re very satisfied with Brunch, but can’t wait to see what the future holds in terms of new and improved build tools.