Adding HoganJS to Brunch

As we described in an ealier post, Brunch is really just a simple way to build and develop any HTML5 application. Part of that simplicity is rooted in how it handles compilation of files with plugins.
Brunch doesn’t care
When you build on top of Brunch, a plugin actually handles the compilation and minification of each file. Brunch is responsible for watching for changes and making sure the appropriate plugin is notified of any changes.
For example, when Brunch comes across a file with a .coffee extension, it sends the contents of that file to the Coffeescript plugin for compilation and includes the result in the final application.
Lets take a look at the Coffeescript plugin code:
coffeescript = require 'coffee-script'
module.exports = class CoffeeScriptCompiler
brunchPlugin: yes
type: 'javascript'
extension: 'coffee' # Here's where we determine what files to handle
compile: (data, path, callback) ->
try
result = coffeescript.compile data
catch err
error = err
finally
callback error, result
Now when we include any .coffee file in our project, the final result will be compiled automatically every time it changes. But this is a trivial example, lets try something a little more complex.
You’ve got some compilation in your mustache
While mustache is our preferred templating language, we also wanted to precompile the templates to Javascript, a capability found in both Handlebars and HoganJS.
Of course it’s a little more involved then that, because while they get precompiled and served as JS, they still rely on the HoganJS/Handlebars library to render in the browser.
Brunch has this handled as well, and we were able to quickly write a HoganJS plugin by adding an ‘include’ method to the module.
hogan = require 'hogan.js'
sysPath = require 'path'
module.exports = class HoganCompiler
brunchPlugin: yes
type: 'template'
extension: 'mustache'
# Returns a precompiled template with a 'render' function
# Usage Example:
# @$el.html(template({name: "mdp", city: "SF"}))
compile: (data, path, callback) ->
try
content = hogan.compile data, asString: yes
result = "module.exports = new Hogan.Template(#{content});"
catch err
error = err
finally
callback error, result
# Add '../node_modules/hogan.js/web/builds/2.0.0/template-2.0.0.js'
# to vendor files.
include: ->
[(sysPath.join __dirname, '..', 'node_modules', 'hogan.js', 'web', 'builds', '2.0.0', 'template-2.0.0.js')]
Now when we use HoganCompiler in a project, Brunch will ensure that the file ‘template-2.0.0.js’ is automatically included in the output JS, and all the templates will be precompiled by the Hogan.js node library. All in less than 30 lines of code.
Final thoughts
The Brunch docs give the best overview of how to build your own plugins, but like many thing looking at some actual example plugins helped immensely. Here’s a quick list of some important ones you’ll probably want to use at some point:
Javascript Compilers
CSS Compilers
Minifiers
Other Related Posts
Photo courtesy of cote
Published: Sunday, May 6 2012
Author: Mark Percival
Death of a hashbang

A lot has been written about the hashbang, so instead of starting up the debate again, I’m instead going to simply show how we killed it, and why we think it never mattered in the first place.
Background
The hashbang is no longer just something for web developers to argue about; it’s been implemented in a number of frameworks (most notably Backbone.js), and a number of large sites (Twitter being the best example). The idea is simple, in browsers that don’t support HTML pushstate, we revert to using an anchor (the hashbang - #!) in the URL to hold state.
So when you click on a link in Safari, you may see this in your URL bar:
http://mysite.com/posts/123
But inside IE, your URL would display:
http://mysite.com/#!posts/123
The hashbang in this case prevents the page from reloading, and allows the Backbone router to handle running the appropriate action. But it’s a hack, and as you’ll see, it’s not entirely necessary.
Do we even need it?
While the hashbang does allow for quicker and smoother page transitions for older browsers, you still must handle someone directly hitting the URL. For example, if I wind up on /posts/12345, I could expect to hit refresh and have the page correctly reload the content and view.
So do I even need hashbangs for IE, or can I just let them load the link as they normally would?
It’s all about the expectations
The downside of this is obvious, the page is going to completely re-render for an older browser. But this was always the case before pushstate came into existance. Most of your assets will be cached at this point, so at worst it’ll take the time to 304 and run the Backbone.js applicaiton. And most importantly, for a user on an older browser, this reload is already expected. You’re not making their experience worse, but you are improving the experience for other users.
The nitty gritty
First, we should prevent the Hashbang from ever occuring by overriding Backbone’s ‘loadUrl’ method (Hat tip to Michael Franzkowiak):
Backbone.History.prototype.loadUrl = (fragmentOverride) ->
fragment = this.fragment = this.getFragment(fragmentOverride,
this._wantsPushState &&
!this._wantsHashChange)
matched = _.any this.handlers, (handler) ->
if handler.route.test(fragment)
handler.callback(fragment)
return true
matched
Then we need to find a way to make certain links pushstate capable.
$(document).delegate "a.pushState", "click", (evt) ->
# Get the anchor href and protocol
href = $(this).attr("href")
protocol = this.protocol + "//"
# Ensure the protocol is not part of URL, meaning its relative.
# Stop the event bubbling to ensure the link will not cause a page refresh.
if href.substring(0, protocol.length) != protocol
# Leading /'s break Backbone router nav
if href.charAt(0) == '/'
href = href.substr(1, href.length)
if Backbone.history._hasPushState
evt.preventDefault()
app.router.navigate href, trigger: true
else
#Do Nothing
Now when an IE9 browser clicks on a link that has the class ‘pushState’ we simply allow the click to happen and the browser to load the new page. And likewise, when a pushState capable browser clicks the link, we prevent it from following it, and instead use Backbone’s router to navigate to the new view.
Should you implement it?
There’s no magic bullet here, and this isn’t going to end the debate on hashbangs. We’re deciding today to support the latest pushstate navigation at the expense of a slower (but expected) browsing experience for our IE users. And unlike starting with support for hashbangs, we can always add them back later, but we can never take them away.
Photo Credit Rick Harris
Published: Tuesday, April 3 2012
Author: Mark Percival
Sadly, A brunch that doesn't involve bacon

How it starts
When Snip.it first launched, we had a fairly typical Rails stack, with the majority of view logic taking place on the server side. And like many web applications, as the application grew, we came to increasingly rely on Javascript for user interactions.
Whether it’s a simple ajaxy button or a complicated piece of form validation, if you’re not careful, your oh-so-DRY code on the Rails side soon becomes filled with duplicated client side functionality.
A move to Backbone.js
For us, the solution seemed to be the easy choice of moving to a more structured JS framework like Backbone.js. Backbone would allow us to move all the view rendering to the client side, and allow Rails to handle formatting and controlling the data coming from the database. But when the time came to get started on the implementation we soon found ourselves having to make even more decisions about directory structure, compilation, minification and deployment.
If you’re familiar with Backbone.js, then you’re probably also familiar with the amazing Addy Osmani and his book Backbone Fundementals. The advanced section has a great breakdown on ways to structure your app, as well as how to go about setting up tools like Require.js. And while this is a a great guide to handling some of the finer points of Backbone.js development, we weren’t in the position to make these decisions this early on in our development.
Brunch to the rescue
At it’s core, Brunch is just a Node.js based build tool for developing and deploying HTML5 apps. But like Rails, when you create a new Brunch project, you get a pretty awesome set of defaults for building your application.
Brunch handles our four main areas of concern. Compiling server side code (eg. Coffeescript/Roy), wrapping multiple files as common.js modules, building/minifying the final output, and allowing team members to quickly get started developing.
Rolling this out to the team is as simple as having each member ‘npm install’ the latest version of brunch, and then executing the brunch CLI tool. And since it’s based on npm, you can even explicitly list out your dependencies in package.json much as you would in a Gemfile.
What you get is a single compiled JS file which includes all the libraries you depend on, your backbone application code, and the common.js wrappers. And while you’re developing, Brunch will watch for changes and automatically recompile the code.
Where do we go from here
This is a big topic, and we’ve decided to publish a series of blog posts about Brunch and our development process. In the next few weeks, we’re going to touch on the following issues.
- Death of a hashbang
- Building on top of the Brunch API
- Migrating from Rails to Rails/Backbone.js
- Playing with alternate setups like Chaplin
Resources for your perusal
- Brunch on github
- Brunch Plugins
- Paul Miller’s Brunch with Chaplin
Photo courtesy of Martin Cathrae