The Gilt technology organization. We make gilt.com work.

Handlebars.scala: A Handlebars for Scala

If you rely on SEO, which really means that you rely on robots, you still want client-side app experiences. Handlebars.scala can help you get there. Handlebars.scala—also known around Gilt Tech as Scandlebars, and sometimes Scandalbars—is a Scala implementation of Handlebars: an extension to and superset of the Mustache templating language. It began as an attempt to learn Scala and to experiment with Scala’s Parser Combinators in order to get Handlebars.js templates working in Scala. These days, it forms a critical part of our stack.

The Genesis of Handlebars.scala

At Gilt, we rely on SEO for a not-insignificant amount of revenue. This means that, at some point, a robot/crawler makes a request against Gilt’s server, and the server has to return HTML. This is how most web pages have been made. In recent years, the paradigm has shifted toward web applications that use client-side template rendering techniques—i.e., single-page apps. These applications are faster than the old technologies allowed, and offer a snappier user experience. The idea behind a single-page app is that you can offload much of the HTML rendering to the client—and you do that through a templating language. Handlebars is one of those templating languages.

At Gilt, we were trying to solve two problems: to render HTML pages server-side, but also get rich client-side rendering—a “best of both worlds” scenario to address the client-server disparity, and create a way to easily share UI pieces as a JVM library.

We had experience with server-side templating engines like Java Server Pages (JSP), which has its own nuances, as well as client-side, JavaScript templating engines like Handlebars. With both of these, you end up duplicating logic—and our goal was to economize on server-side rendering and reduce the duplication. Our question: How can we make server-side rendering low-barrier enough without duplicating too much of our efforts in client-side rendering?

We Tried Mustache

With this question in mind, we checked out Mustache. A logic-less templating language, Mustache offers a considerable benefit: It’s language-agnostic and offers several implementations for all programming languages, including Scala. After experimenting with Mustache, however, our UI Architecture team realized that it’s really terse. Because of its logic-lessness, Mustache is kind of a pain in the ass to write (or can be, for something as large as an ecommerce site with millions of members).

After playing around with Mustache, Eric and the team were drawn to Handlebars: a superset of Mustache created by Tilde co-founder Yehuda Katz. Handlebars is very similar to Mustache, but offers a variety of extras—namely, path lookups and helper functions. It also can be pre-compiled into JavaScript. Handlebars is a crucial component of Ember.js, which Yehuda also created.

Our issue with Handlebars was that we needed it to run on the JVM. When I shared this info with Yehuda’s colleague, Tilde co-founder Tom Dale, after a NYC.JS meetup, he suggested that we try out Rhino—a JavaScript interpreter written in Java. At the time, Gilt Senior Engineer Kevan Davis was trying to figure out how to run Handlebars and Rhino, and made some progress with it, but the setup was clumsy because Rhino is clumsy. “Maybe I’ll just write Handlebars in Scala,” I finally said to Tom. We were at a bar at the time, and I was a bit tipsy, but there was a “yeah, sure, do that” vibe to our conversation.

The Scandal of Scandlebars: I Didn’t Actually Know Scala Yet

The problem with “just writing Handlebars in Scala” was that I hadn’t messed around with Scala much. Handlebars.scala was my first Scala project. Developing it was something of an excuse to play with the language and learn it by doing. Whatever works, right?

The Scala standard library includes Parser Combinators: a functional programming method to describe grammars for language. I learned how to use Parser Combinators, and how to build parsers, by studying the source code of Scalate (a set of templating languages in Scala, including Mustache). This, plus help from the denizens of Gilt’s Scala 2.9.1 chat room, helped me to create Handlebars.scala.

Handlebars’ preference for JavaScript (a dynamically typed, prototype-based language with first-class functions) made writing it in Scala (a statically-typed, hybrid-oriented language) pretty interesting from a bridging-concepts perspective. There’s just all kinds of syntactic quirks with Scala—for example, [Option] and how to make Option—or any monad—work.

In developing Handlebars.scala I faced a number of philosophical questions:

  • How do you write idiomatic Scala and still have it make sense?
  • How should Options work?
  • How does the collection library work?
  • How can you leverage case and pattern matching so that you can achieve what you want in Handlebars by using Scala that you’re already familiar with (the idea being that any Scala object should be able to fit into a Handlebars template)?

How Handlebars.scala Works

I think the key thing that makes Handlebars.scala work is the idea of view models. On the Scala side, in our server, are intelligent, intermediary layers that we can use to render a Scala/Handlebars template or serialized into JSON in order to render them using Handlebars.js.

Here’s an example of the apply method of a Handlebars instance, which should be familiar to Scala fans. Apply takes an optional second argument: a Map of helper functions. The signature for apply looks like this:

def apply[T](context: T, helpers: Map[String,Helper[T]] = Map.empty[String,Helper[T]])

A few things to note when using Handlebars.scala:

  • Implicit conversions will not work in a template. Because Handlebars.scala makes heavy use of reflection. Bummer, I know. This leads me to…
  • …Handlebars.scala makes heavy use of reflection. This means that there could be unexpected behavior.
  • Method overloading will behave in bizarre ways.
  • There is likely a performance penalty. I’m not sophisticated enough in the arts of the JVM to know the implications of this.

How does Handlebars.scala perform?

We’ve been using Scandlebars in production, and it’s become a crucial part of our rendering stack. We use it wherever we have a user interface that needs to be represented both the server and the client. Handlebars.scala gives us this choice to render it immediately or at a later date.

Some specific examples of Handlebars.scala at Gilt:

  • Our new unified nav (built entirely with Handlebars.scala)
  • We have lots of small applications that don’t all use the same technologies, but we need them to be able to share a user interface as a library. Scandlebars enables us to make these HTML pieces as a library Our product detail pages Search

With those last two items, the idea was that the same template we use to render a product on a server can be used to render it on the client. This reduces duplication by a not-inconsequential amount. What the client can do is say, “I know how to render this thing. Now, I know I’m not a robot—I’m a user using JavaScript—so instead of going back to the server for an HTML roundtrip, I can just go to the JSON.”

The client-side app experience feels a lot faster with Handlebars.scala. We started to benchmark its performance and tried to find bottlenecks in rendering. Handlebars.scala uses a lot of reflection, so that can sometimes be a bit tricky in Scala or another statically-typed language. But overall, I think it performs pretty well. There’s always going to be an upper bound to its performance because it uses reflection.

One key question I haven’t answered yet is this: When you use futures in Scala and Akka, and a Handlebars.scala template resolves that future, how do you organize your code before putting it into Handlebars.scala and make your data easily accessible through Handlebars.scala? Until I have a sure answer to that question, I don’t advise resolving futures inside of a template.

Then we started trying to figure out, we have the ability to make an AST (abstract syntax stream) out of a template file. Now how do you take data and render a template. Need some way for the tree to be filled in. It raised a bunch of questions

The Future of Handlebars.scala

Gilt Software Engineer Chris “Chicks” Hicks and I have started working on the next version of Handlebars.scala—the idea being that Handlebars.js 1.0 has been released fairly recently, and now we want Handlebars.scala to meet it in terms of almost-compatibility. A key concern is how we can make using Handlebars.scala balance between feeling like the JavaScript-Handlebars but just as comfortable for Scala developers. If Handlebars.scala is too much like JavaScript, it won’t fit with the programming paradigm, but if it’s too much like Scala, then it will feel like it deviates too much from its original implementation.

I have a few ideas:

  • Make usability improvements, including the kinds of types helper functions can take
  • Resolve the bugs with nested conditionals
  • Make it clearer
  • Make the code prettier
  • Optimize for the use cases we’ve run into in production—then we might be more comfortable opening it up to larger use
  • Make sure the concept of sharing templates works and is really solid

If you use Handlebars.scala or have any additional ideas for improvements, I’d love to hear them—just contact me via GitHub.

Handlebars.Scala 3 Scandalbars 1 Handlebars.js 2 Ember.js 2 Tilde 1 Rhino 1 NYC.JS 1 parser combinators 1 Scala 79 Akka 20 open source 66 opensource 9