Mustache vs. Handlebars scoping
Mustache and Handlebars deal with scoping differently and this doesn’t seem to be explicitly picked up in any comparisons I’ve found of the two libraries.
Mustache and Handlebars
Both Mustache and Handlebars are well-documented templating libraries and you can find more on the specifics of their usage here and here respectively. I have been trying out the JavaScript version of Mustache for direct comparison with Handlebars, which is natively JavaScript. You can also try both libraries out without any installation at http://trymustache.com and http://tryhandlebarsjs.com respectively.
A quick summary of how both work would be to say that you create an HTML template with variables in it placed in double curly braces like this:
{{variable}}
In context it might look like this:
<span>{{variable}}</span>
For each of these variables, you create a property within a context object (in JSON format) which looks like this.
{
"variable": "Some value."
}
When the template is interpreted or compiled, the variables are subjected with the corresponding variable from the context object. If a particular variable is missing, it usually returns blank.
Here’s how the result of combining the HTML above with the context-object above would come out:
<span>Some text.</span>
Pretty simple stuff.
Hash, or pound, signs
When writing a template with either Mustache or Handlebars, you can prefix a variable name with a #
in order to create a wrapper. One closes the wrapper with the same variable prefixed with /
, a bit like closing an HTML tag. For example:
{{#wrapper}}<b>Hello World!</b>{{/wrapper}}
How this is interpreted by either library depends on the variable’s type and value in the context object. I’ve listed each type below, with example context code and results.
Type | Truthiness | Example Value | HTML Output |
---|---|---|---|
Boolean | Truthy | true | <b>Hello World!</b> |
Boolean | Falsy | false | |
String | Truthy | "Wrapper" | <b>Hello World!</b> |
String | Falsy | "" | |
Number | Truthy | 5 | <b>Hello World!</b> |
Number | Falsy | 0 | |
Object | Truthy | {} | <b>Hello World!</b> |
Object | Truthy | { "property": "value" } | <b>Hello World!</b> |
Object | Truthy | { "property": "value", "property2": "value2" } | <b>Hello World!</b> |
Array | Truthy | [ "hello world" ] | <b>Hello World!</b> |
Array | Truthy | [ "hello", "world" ] | <b>Hello World!</b><b>Hello World!</b> |
Array | Truthy | [ { "property": "value" } ] | <b>Hello World!</b> |
Array | Truthy | [ { "property": "value" }, { "property": "value" } ] | <b>Hello World!</b><b>Hello World!</b> |
Array | Truthy | [] |
For most types, if the value is truthy, then everything in the wrapper is printed. In this way the {{#wrapper}}
acts as a conditional.
For arrays, behaviour is slightly different. Whereas an empty object is still truthy and will therefore print whatever is in the wrapper, an empty array is treated as if it were falsy, and will print nothing. Furthermore, if there are two elements inside the array, it will print the content within the wrapper twice. In short, with an array, the content is printed as many times as there are elements in the array, even if those elements themselves happen to be falsy.
The use of an array means the wrapper is treated like a block, rather than a straightforward conditional.
Nested variables
Where the two libraries differ is in the handling of variables inside a wrapper.
Take the following line which might appear in a template:
{{#wrapper}}<b>Hello {{name}}!</b>{{/wrapper}}
In either library, if name
is not defined at all, then the HTML return would reflect that.
Here’s an object structure where that’s the case:
{
"wrapper": true
}
And here’s the result with either library:
<b>Hello !</b>
There is no name
property in the context variable, ergo it does not display.
However, the differences arise in where the variable can be defined for each library.
Your object structure might look like this:
{
"wrapper": true,
"name": "Guy"
}
We already know that wrapper
has to be true, in order for any HTML to be printed. However, the placement of name
as a property within the same parent object as wrapper
has different results depending on which library you use.
In Mustache, you get this:
<b>Hello Guy!</b>
In Handlebars, you get this:
<b>Hello !</b>
Handlebars acts as if the name
property did not exist at all. We could say that, for Handlebars, name
is out of scope.
Handlebars’ scope limitations
In Handlebars, once you are inside a wrapper, only variables defined within that block can be accessed. So the following object in Handlebars …
{
"wrapper": { "name": "Guy" }
}
… would give us:
<b>Hello Guy!</b>
This object, where wrapper
is an array containing an object with the name
property…
{
"wrapper": [
{ "name": "Guy" }
]
}
… produces the same result:
And of course if the array consists
This would also work in Mustache. But whereas Handlebars will not automatically look for name
outside the wrapper
context (more on that “automatically” remark later), Mustache will.
Mustache’s scope availability
What Mustache also does is checks outside the wrapping context for the variable.
We have already seen that, in Mustache, this template…
{{#wrapper}}<b>Hello {{name}}!</b>{{/wrapper}}
… with this object …
{
"wrapper": true,
"name": "Guy"
}
… produces this:
<b>Hello Guy!</b>
If we also define, a name
property inside the wrapper
, like this …
{
"wrapper": { "name": "Rosie" },
"name": "Guy"
}
… then the inner variable (the one most local) takes precedence over the outer.
Therefore the result in this case will be:
<b>Hello Rosie!</b>
The outer name
property will be ignored, but can act as a fallback, should the inner variable prove to be nonexistent.
This is somewhat reminiscent of JavaScript behaviour around variables and scoping. If a local variable cannot be found, JavaScript will check the outer scope to see if one exists there and then the scope around that, all the way back to the global scope.
Yet the only mention I could find of this difference in any of the documentation or any of the comparative posts I’ve read around it is one line a section of the Handlebars GitHub README file on compatability, namely:
Handlebars deviates from Mustache slightly in that it does not perform recursive lookup by default.
There is a flag for enabling recursive lookup (i.e., bubbling out of local scope for variable fallback) but, by default Handlebars has different methods for accessing variables beyond scope.
Referencing the wrapper from within
This has consequences for the way the conditional pound sign can be used in each library.
Take the following context object:
{
"value": "Some text."
}
Then take the following templating code:
{{#value}}<span class="text">{{value}}</span>{{/value}}
We know that value
is truthy and not an empty array. Therefore we know that the <span>
tags will be printed, whichever library we use. However, how the value
in the middle is printed depends on the library.
In Mustache, we will get:
<span class="text">Some text.</span>
This is because Mustache reaches out to find value
outside of the context of value
.
In Handlebars, however we get:
<span class="text"></span>
The HTML tags are printed because value
is truthy and not an empty array. But once inside the value
wrapper, Handlebars does not automatically go back out of it to get value
. It can see no value
in the value
context and so does not print.
If you wanted to the wrapper to self-reference in Handlebars you could use a reserved variable called this
to print value
which conditionally checking it exists.
{{#value}}<span class="text">{{this}}</span>{{/value}}
Another way to access the value
variable from within the wrapper is by using paths.
Handlebars paths
Handlebars can access variables outside a wrapper scope or context but only if you manually specify that it should.
One way to do this with the “self-referencing” example above is to write
{{#value}}<span class="text">{{../value}}</span>{{/value}}
The ../
tells Handlebars to go up one context. It takes us outside the wrapper for the one variable and back into the parent object. One can use several of these to go up as many contexts.
In this way it’s possible to first check that value
exists, then write the HTML code for it, include the value
itself, and then the rest of the HTML code before closing the wrapper.
Paths aren’t just a way of getting around the Mustache automatic fallback technique. They give you a lot for control over where you get the variables from.
Which is better?
In my opinion, Handlebars’ paths and self-referencing variables are more powerful. Besides Handlebars’ other advantages over Mustache, these features allow for more control and should make for easier debugging. I’ll keep playing around with both, particularly as Scriptogram (my current blogging platform) seems to use Mustache, but right now for me Handlebars wins out.