How Replacing JavaScript Templating Engines with ES6 Template Literals May Cost You Your Job


The article ES6 Strings and Template Literals introduced you to the syntax of ES6 strings and template literals. However, if you wanted to use ES6 template literals for microtemplating, the article itself does not help you. In this article, you will find out more about the relationship between ES6 template literals and JavaScript templating engines.

Storing templates

In large projects, templates are stored in their own template file and are imported using ES6 modules.

In smaller projects, we can get away with storing templates in the DOM usint scripts the browser does not understand, and therefore does not interpret. These templates are typically marked with type text/template:

You can access this template using

This was the old way of handling templates before RequireJs and later ES6 modules with Webpack came around. With ES6 modules, you just import the templates, and get access to their text in a string variable.

Either way, you get a JavaScript string that contains your template. This template has some inserted code snippets of form ${ value }. The problem is that these snippets are inside a string and not inside a template literal. Therefore, unlike in Underscore Templating or Handlebars, these snippets will not be evaluated. We will address the problem of evaluating templates in this article.

Evaluating templates

Suppose a JavaScript string containing code snippets of form ${ value } is given, where value is an arbitrary JavaScript value. Our task is to evaluate these code snippets and return a string containing the evaluated template.

To get a feel for the task, check out my article on Underscore Templating. We did the following steps to render our application:

We care about the process of assembling the template. Therefore, let’s examine steps 2 and 4 a bit more closely:

If we combine the two lines, we get the following chain of function applications:

So, in order to get the fully evaluated string that we can insert into the DOM, we need the following: use a templating engine, in this case _.template, to transform templateString into a function. This function accepts template data, and returns the evaluated templateString with data values inserted into it.

In this example, the templating engine _.template was given. However, chances are, you have considered not including Underscore, LoDash, or any other templating engines in your code base just for the sake of performing a simple task. What options do we have to implement templating using template literals?

Possible solutions

After reading my article on ES6 Strings and Template Literals, the following three solutions seem logical:

  1. define the templates as JavaScript functions,
  2. write your own helper,
  3. use a tagged template function as the templating engine.

Before continuing reading, I encourage you to think the three approaches through. Which approaches are feasible in your opinion? What problems would you encounter with each approach?

Let’s see them one by one.

Defining templates as JavaScript functions

All you need is to create a file for each of your templates. In this example, we will use name.template.js:

If you want to render the template, you need to import the templating function:

The templating engine is provided by a simple function wrapping the template literal. After all, we can make a partially evaluated template from a template literal by using the format

This solution is so simple that many people may consider using it. However, before you start ditching your templating engine in favor of simple functions, stay with this article, because near the end, you will find a twist. This twist will make this solution a lot less attractive because of the underlying dangers of not being careful enough.

But first, let’s move on to the next suggestion.

Write your own helper?

Suppose the string nameTemplate is given, and its value is retrieved from the HTML code:

Suppose our data is

We want to render the template with a helper.

If we can write an evaluateTemplate function that evaluates template by inserting data into it, we will solve the problem:

would then return the same result as

We could use eval or the Function constructor:

If I sold you this as the ultimate templating solution, you may consider not taking me seriously. I mean, with, eval? None of these language constructs have much to do with writing maintainable software.

Mind you, eval is not secure in JavaScript, and its performance is not that great either. However, without dynamic evaluation, we can only write our own helper with some restrictions.

Let’s make the following assumption:

  • In ${ value }, value has to be an identifier for which data[ value ] exists
  • You can add any number of whitespaces before or after value.

We can then write a regular expression that captures value inside ${ and }. I will break it down for you in extended syntax:

The regular expression is global, because we will want to replace all occurrences of ${ value } patterns, and extract each and every value in capture groups.

As a side note, this syntax is not available in JavaScript by default, because a whitespace character matches itself. You can use a library like XRegExp to enrich the regular expression dialect implemented in JavaScript. If you sign up below, you will be notified about updates on how to master JavaScript regular expressions. You can even download a free regex cheat sheet that you can print for yourself:

Let’s get back to work. In JavaScript, we have to write our regular expression without whitespaces and comments. Let’s write our evaluateTemplate function:

Notice that the replace function of the String API accepts a function in the second argument returning the string you want to replace the original value with. The first argument of this function contains the original string. We don’t need this value, so I indicated it with the throw-away value _. The second argument is the value that was captured in-between the parentheses of the regular expression. This string is called the value of capture group 1. In the function passed to replace, the value of capture group i is accessible via arguments[i].

Let’s summarize the solution:

The result is correct:

Would you use my code in production? Because I would not.

Why? Let me ask you a few questions: is this code harmless against injecting some suspicious values that could

  • get your cookies;
  • submit an AJAX request and even fire some unwanted SQL statements.

This code is not prepared for all cases. We would have to continue adding more logic into our templating engine. What happens once we add more logic? We get a templating engine like HandleBars, Moustache, Underscore or LoDash templating, Jade etc.

Conclusion: don’t write your own templating engine, use one instead that’s supported by the open source community.

What about tagged templates?

I know, we haven’t talked about tagged templates. But do you know what the main problem with tagged templates is? Their format is

and not

Unfortunately, we have a regular JavaScript string. This means, we are back to square one. In order to use tagged templates for template evaluation, we have one of the following two choices:

  • convert the string into a template literal using e.g. eval,
  • restrict our templating activities so that we can use tagged templates.

As the first option is a no-go for us, we will do the latter.

Unsurprisingly, the values are:

  • substringArray: ["", "", raw: ["", ""] ]
  • dataArray: ["${ a } text"]

This just does not add up. Why would we use tagged templates to transform a string into a template literal if we don’t use any of the capabilities of template literals?

You see, there are so many questions circulating around template rendering and template literals. Just because ES6 template literals have the word template in them, people think, they replace a JavaScript templating engine. No, they don’t. It’s like asking a mongoose to behave like a monsoon. They both start with mon, but their purpose is different.

Tagged templates still have a use case

Let’s recall our first solution:

This code snippet seems to serve its purpose, even the newline characters are there:

What can go wrong in this example? Let’s see…

We can insert some evil code into our HTML:

Try it out:

By inserting the above code to the end of the document body, you are supposed to see an alert once you scroll to the end of the document and move your mouse cursor over the text Nagy to see the alert appear.

As the cops in Need for Speed would say, you got away with a warning this time. However, some attacks will not be this gentle.

This is why we have to sanitize the input. For instance, not allowing any tag names is a great start. We will simply replace the greater than and the less than symbols with their entity names. This is where tagged template functions come handy:

Once again, replace is a string prototype function. Its first argument is a regular expression. If we add the global modifier to the regular expression, we replace all matches with the second argument. This time the second argument is a simple value.

Let’s see the result in action:

The result is:

Better luck next time, evil attacker! By not inserting any HTML, you failed to insert JavaScript too.

As you can see, tagged templates came handy. However, let me ask you the question: why bother writing it at all? There are great templating engines available. They have done a lot more than just input sanitization for replacing the greater than and less than signs.

If you want to write your own templating engine, sure, go ahead, you could be the thousandth person open sourcing one online. Otherwise, I would just default to a simple templating engine.

Conclusion

How can you get fired? Easy.

First, listen to my disclaimer: I do not bear any responsibility for the damages caused. This is an ironic, hypothetical scenario.

Second, ask for refactoring time during your next sprint. Tell your managers that ES6 template literals are the new shit on the block, and you want to replace your current templating engine with it. If your manager is dumb enough, or (s)he trusts you enough, you will get the go ahead. I am sure you will forget something. If not, you just wasted your valuable time with reinventing the wheel.

Third, wait until someone discovers the errors and finds out that ES6 template literals are not to be used as template rendering engines.

This is the recipe. For freelancers, you may have to limit your liability in your contract. Or, if you prefer meeting your needs in a more meaningful way, you could just consider omitting the idea of using ES6 template literals instead of template rendering.

This is because ES6 template literals have not much to do with templating engines. You can experiment with creating some templates with them, but once you start testing the limits of your application, you will soon conclude that you need the capabilities of a real templating engine to handle your templates.

In a small hobby-application, everything files. Once you start playing with hundreds of thousands of dollars of your employer’s money, start thinking about whether you want to write your templating engine yourself, or you prefer using a well tested one.

If you liked this article, and you are interested in extending your ES6 knowledge, sign up in the form below:

Learn ES6 in Practice

Sign up below to access an ES6 course with many exercises and reference solutions.