HTMLBars - A Feature-by-Feature Review

A Feature-by-Feature review on the awesomeness of HTMLBars and why it excites me as an EmberJS developer.
December 25, 2014

Handlebars is the template engine for EmberJS. It is a natural choice, given that both are created by the same person, Yehuda Katz. Handlebars templates are characterised by the distinctive braces, {{....}}, also known as 'mustache'.

EmberJS extends the Handlebars library with many cool features such as the ability to embed binding-aware expression in the view. I had always taken the data-binding feature in EmberJS for granted. It was only after I done my research for this article, did I found out more about EmberJS's data-binding mechanics.

Early Years of EmberJS's rendering pipeline

Before version 1.8.0, EmberJS's handlebar compiler used string concatenation to render the view.

  1. The compiler takes in a string template and generates out an abstract syntax tree(AST).
  2. This AST is passed off to the render tree to assemble the dynamic parts (marking section with script tags etc.).
  3. The render tree will emits a string which will be inserted into the DOM via the innerHTML function.
  4. The browser will then parse the string into DOM objects.

My explanation might be too convulated. voidCanvas did a much better job in defining this process.

Colin Toh Handlebars' role in rendering the view

Why is this bad?

After the generated string enters the DOM, you have no control on its context/reference after they are parsed as DOM objects. So how does EmberJS do data-binding?

EmberJS uses a library,metamorph.js, which wraps script tags around regions of data-bound content. This allows EmberJS to have context for manipulation later on. This seems clever because script tags have cross-browser support and it doesn't affects layout. However, in hindsight, this was a frustrating issue for frontend developers. I will touch more on that later.

Handlebars's only responsibility is to turn mustache into strings. It doesn't understand markup. So it will not understand if the expression is in a tag or inside an attribute.

Handlebars doesn't know the difference between these three

Hence we need to use Handlebars helpers such as bind-attr. This creates an additional verboseness to the syntax.

Handlebars understand this with the help of bind-attr

The Birth of HTMLBars

It understands your markup.
It can be smart about how it does its job.
- Erik Bryn, co-founder of HTMLBars

HTMLBars intends to solve these problems with a better data-binding approach.

Instead of generating string for insertion, HTMLBars generates DOM fragments for insertion. This allows us to hold reference to the fragments later on. Thus, this reduces the needs for pesky script tags and additional handlebar helpers.

Once again, I will use voidCanvas's visual example of how HTMLBars handle the render process:

Colin Toh All DOM elements and no strings!

I will now bring you guys through several new features promised by HTMLBars that excites me personally as an EmberJS Developer.


Concise Syntax

Use Case: Bind class attribute

Use Case: Bind style attribtue

Demo: http://emberjs.jsbin.com/xogozo/2/edit

Use Case: String Interpolation

Demo: http://emberjs.jsbin.com/kuwowa/2/edit

Use Case: Inline If Helper

Demo: http://emberjs.jsbin.com/guneko/2/edit


Cleaner Compiled HTML

With metamorph.js:

Colin Toh Oh my! The horror!

The additional script tags in the markup breaks CSS selectors such as :first-child among many others.

With HTMLBars:

Colin Toh ahh... Much clean!

Compared this with the example with metamorph.js, you can see the markup is cleansed of script tags.

Note: Both images from http://talks.erikbryn.com/htmlbars-emberconf/#/18


Performance Gain for Long List Rendering

EmberJS is known to perform badly when rendering long list of dynamic contents, especially on mobile.

With HTMLBars, they managed to shave off a significant amount of rendering time with a different approach.

Let's say you want to create a long list:

Instead of creating and populating the document fragment for each node(<li>), the fragment is first created and cached once without the dynamic parts filled in.

Next, each node is deep-cloned from the cached fragment before populating them individually. This process is call 'hydration'.

As cloning is a faster process than manual creation of document fragments, this will dramatically increase the rendering performance for EmberJS.


Correct Binding Update Hierarchy

Handlebars does not understand view hierarchy for data-binding. So if we update photo to null, {{photo.thumbUrl}} will be triggered for updates too. This will result in a invalid request. HTMLBars makes sure the view understand the hierarchy such that it will only trigger valid updates.


Animations

One of the features that I really need from EmberJS is animation. This is a glaring shortcoming of EmberJS when compared to AngularJS.

willInsertElement is actually quite a useless function right now because you have no access to the view's DOM fragments. Once EmberJS is fully integrated with HTMLBars, the view's fragments is accessible before it is inserted into the DOM.

With this, you can manipulate the fragments such as adding animation classes and removing them when the fragments enter the DOM, triggering the animated transition.

Additional Animation Goodies

HTMLBars also pauses data-binding for views that are in the midst of animation. When the animations are done, the binding will resume. This will aid in smooth animated transitions.


Optional jQuery dependency

Together with its dependencies - Handlebars(44kb) and jQuery(96kb), EmberJS(337KB) is considered to be a bulky library in comparison with other competing frameworks. Shedding off the jQuery dependency helps as every bytes counts for mobile web development.


Journey to HTMLBars

EmberJS is intending to merge HTMLBars into their latest build via several phases. With EmberJS 1.8, they had refactored the rendering layer, calling it "metal-view". This removed the need for metamorph.js. However, it is still using a mixture of string + DOM based approach in rendering views.

.... In Ember.js 1.8, fragments of a page are still created (via Handlebars) as strings, but are then parsed into DOM and assembled as a DOM tree. - EmberJS's blog

At this point of writing, EmberJS released 1.10 beta which had totally migrated the rendering pipeline from a string approach to a DOM-based one.

I have been using the Ember 1.8+ for a couple of projects and is very pleased with it so far. Although I still can't really sense the performance upgrade, I am still optimistic with future releases of EmberJS.

The future looks bright for EmberJS and I can't wait.

Big shoutout to Erik Bryn and Kris Selden for all the hard work in HTMLBars.

More Info

RSS