SailsJS with Handlebars



Update: Sails 0.12+ ships with Handlebars support out of the box. You just need to pass in the --viewEngine option when generating a new Sails App. So don’t worry about anything written below. Just do something like this:

sails new myApp --viewEngine handlebars

The information below is just for posterity. 🙂

The Problem

I like SailsJS. I’ve been using it for a pet project recently and it’s a great way to create all the boilerplate for a webserver. I definitely prefer it over starting an ExpressJS server from scratch.

Sails has a lot of pros. I love the model/controller scaffolding, Waterline, using middleware as policies, and enforcing API-driven development. However, I’m a big fan of Handlebars and I really don’t like EJS so I thought that was going to be a blocker for me.

Fortunately, I have a little hack which lets me use Handlebars with Sails. Before starting down this path, I took a look at the StackOverflow answers on how to get SailsJS working with Handlebars. None of the replies seemed suitable to me. Most require you to pass in your layout and partials properties to every res.view() call. There isn’t much information on using Handlebars Helpers either. What I wanted was to just do this:


res.view();

And I want it to pull the correct layout and all the available partials. I also want it to be able to read in the correct Handlebars Helpers. All the benefits that Sails + EJS gives you, except using Handlebars instead.

The Solution

The solution was hidden inside Christopher Pappas’ closed pull request. I used his code to modify Sails Core to use express3-handlebars. If you want to use Handlebars as your view engine, modify your config/views.js to this:


module.exports = {
  engine: 'handlebars',
  layout: 'main.handlebars', //whatever your default layout is
  helpers: require('./helpers') //pull in your helpers (I store it in config/helpers.js)
}

Here’s how you should structure your views/ directory:


views/
  layouts/
    main.handlebars

  partials/
    partial1.handlebars
    partial2.handlebars

  controller1/
    action1.handlebars
    action2.handlebars

All the partials within the root partials/ directory will be available for use in any view.

Installation

Remember that this is a hack that has only been tested in Sails 0.9.9. Sails 0.10+ introduces some changes to how view engines are created, so this code won’t work there as-is, but it shouldn’t be hard to port over.

In terms of installation, I am pulling in Sails from my Handlebars branch. Here’s what my package.json looks like:


//within package.json
"sails": "git://github.com/tilomitra/sails.git#handlebars"

Then, instead of installing Sails globally via npm -g install sails, I install it locally via npm install sails. This pulls in my Handlebars-enabled version of Sails from GitHub.

I know this isn’t acceptable for a lot of people, but it did the job for me. One notable flaw is the inability to update as Sails updates. However, the only file that I modified was hooks/views/index.js, so it’s not hard to port it over. I will be trying out Sails 0.10.x eventually because it has support for model associations (something which I badly need), so I’ll post an update to this post if I am able to get Handlebars working with Sails 0.10.x.

Happy Coding!


Credit to Christopher Pappas who wrote the original code that made this possible, and to Balderdash for creating Sails.