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 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).
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.
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
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
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.