Front-end Series 3: Templating syntax review

  1. Template syntax families
  2. Binding simple values
  3. Binding values using Scope Blocks
  4. Grammars
  5. Parsing
  6. Consistency leads to Predictability
  7. Comparison of popular templating syntaxes
    1. String Insertion
    2. Iteration
    3. If

Templating syntax (and language syntax in general) is very interesting. How a template is written somewhat informs mental-model of how it behaves, and how the data should be structured.

The following is a syntax review of common features in front-end templating systems. This is an initial pass! If you see any errors or optimizations, please correct me in the comments and I’ll quickly correct them. Also, this isn’t a review of the (sometimes very extensive) templating engines themselves — just the template syntax.

Template syntax families

At a very high-level, template syntax falls generally into two families: element-attribute renderers, and inline-token renderers.

Element-attribute style syntax binds data, logic, and state to a template by attributes on an individual node:  <element directive="property" /> . These templates are often parsed using traditional DOM parsing techniques, looking for element attributes that match a set of defined directives for that framework.

In inline-token renderers, binding is performed by code (or expressions) in-place, using special tokens to set it apart from the markup: like  {{ , <@ , or  <% . These templates are parsed using string or pattern matching techniques on the tokens, then evaluating their contents.

These are general distinctions, and some templating frameworks use both syntax styles.

Binding simple values

Inline-token style syntax really shines when binding single values to a template:

Because the templates are parsed as strings, using pattern matching regular expressions to find tokens, the binding can occur anywhere within the template, making them very powerful:

Element-attribute syntax expressions bind simple data easily, but quickly become verbose and unwieldy when replacing complex content:

 Binding values using Scope Blocks

Many templates also include some logic expressions, such as  if, foreach, and  using. Inline-token expressions can be limited when working with logic blocks — one reason is scope management. Element-attribute syntax declares expressions on the elements themselves, which have a natural scope within the DOM tree: they start, end, and have children. This makes data binding when scope is required simple:

Inline-token expressions are parsed with pattern-matching and could occur anywhere, so the parser must maintain the scope of any logic blocks used in a template. Additionally, the template syntax must contain closing tags for each opening logic block.

Grammars

handlebars-grammarEach templating syntax comes with its own grammar — or structure. A study of language grammar is a post on its own (or a degree of its own!), but a brief look at grammar is useful to understand the different syntax of each templating framework.

A grammar is a logical structure that defines what is acceptable in a language. Although templating frameworks can have a grammar, they aren’t necessarily languages on their own.

Lets look at the handlebars templating framework:

A handlebars expression starts with the tokens  {{ , and contains three sections:

  • An optional additional  { token
  • An optional logic expression :  #with , #using , #if , #else , #unless
  • A variable or object

Once defined, a basic grammar can be represented as a regular expression. Regular expressions can be represented differently in different languages, but this one should be generic enough:

{{{?(#[a-z]+ )?[a-z]+.[a-z]*}?}}

Meaning:

  • Match the string  {{ (opening token)
  • followed by zero or one  { (unescape token)
  • followed by zero or one  #[a-z]  strings (logic directives)
  • followed by an  [a-z]  string (variable or expression)
  • Followed by zero or more  .[a-z] strings (dot-operator variables)
  • followed by zero or one  } (closing unescape token)
  • followed by the string  }} (closing token)

Grammars can be wildly complex, but these simple principles can be applied to any of the templating frameworks to get a better understanding of how they work.

Parsing

Regular expressions are not only useful for understanding how a templates syntax is structured, but are also used in parsing inline-token syntax templates.

Handlebars’ parser uses a technique which involves searching a template for the  {{ token, then “looking ahead” for the closing  }}, and saving everything between the two in a buffer. When the end token is found, the buffer contents are then parsed and types are returned based on their content.

The contents of those blocks are then passed again into the same parser, to look for further operators:

After the parser has finished iterating on the template string, it is left with a stack of logical operations and functions which are then supplied the data for rendering.

Consistency leads to Predictability

One of the keys to a language’s (and templating engine’s) success and adoption is consistency in syntax. Based on previous experience with a given syntax, a programmer should be able to successfully create new code without diving into the documentation. “If that similar structure took a key-value-pair before, I bet this one here does too.”

Inline-token syntax parsers self-enforce consistency of the language, due to the nature of the parser. It must find a specific token, followed by a set of allowable expressions, which themselves might contain expressions. It’s easy to remember that an underscore block always looks like this  <@= ... @>, because it must per the parser.

Element-attribute syntaxes have a harder time enforcing consistency, and it must be created through the framework creators insistence on following a pattern for their “language.”

A generic element-attribute syntax could consist of

Framework creators must choose a pattern for their element-attributes and insist that the pattern is followed for new directives that are added to the language.

Let’s create a pretend framework, called Bob. Bob’s starts simply, and only binds strings:

We continue to use Bob, and need to add some logic:

And later, repeating sections. Since repeat doesn’t really need a value, let’s write it like so:

Now we need to replace multiple attributes:

And finally, replace specific strings within attributes:

The moment a second programmer tries to implement Bob, it becomes clear that we’ve implemented a totally unpredictable syntax! Is a directive part of the attribute name ( bob-string="name"), or in the value ( bob="repeat")? What is the valid syntax for a  bob-bind attribute? A single value or a key-value pair? The  bob-replace value is JSON apparently?

Regardless of the frameworks speed or other technical features, a syntax implemented in this way will kill adoption.

Comparison of popular framework syntaxes

String insertion

angular
closure
handlebars
knockout
pure
underscore

Iteration

angular
closure
handlebars
knockout
pure
underscore

If

angular
closure
handlebars
knockout
pure
underscore

That’s all folks!

Templating frameworks are very useful, and their syntax is one of the main way which a programmer interacts with them. Understanding the differences that syntaxes and template philosophies can help you choose the right one for your use-case!

Author: Michael Jasper

Michael is a Web Developer located in Northern Utah. When not programming, he enjoys spending time with his family, exploring the great-outdoors, and hit-and-miss cooking experiments.