Template Literal Engine

Justin Rubin
Walmart Global Tech Blog
5 min readDec 18, 2020

This blog was co-authored with the help of Jean Pan

Building string templates in JavaScript was greatly improved with the introduction of Template Literals in ES6. But building templates the right way can take some thought and even present challenges.

When building our A/B experimentation platform at Walmart Global Tech one of the critical features was identifying when a user qualifies for an experiment. A qualified user is defined as someone who was assigned to the experiment and who saw (as best we can tell) the part of the site being experimented on. In order to determine if a user qualified, we need to query data from our site (Walmart.com) or our native app by a set of predetermined criteria. This predetermined criteria is built during the experiment setup phase and is in the form of a query expression (similar to SQL). These expressions can get pretty complex, as anyone who is familiar with building SQL queries or scalar functions can attest. Additionally, the attributes in the expression are defined by an external system, ie. the site/native app, and therefore are subject to change outside of our application’s control.

This presents us with two challenges to address. First, we need to templatize the query expressions in a way that values can be substituted in. And second, we need these templates stored outside code base in a configuration file.

Con+cat+enation

String concatenation in JavaScript was never great. This is especially true when trying to build templates using string concatenation.

const adjective = “great”;

“String concatenation is not a “ + adjective + “ way to build a template.”

If you ever tried to build out a string template and you did one of these, “SELECT ” + fields + “ FROM ” + table, you quickly realized how poorly the design scaled. It turns out JavaScript has an awesome syntax that can help us address our first problem using Template Literals.

Template Literal

Template literal is an awesome construct within JavaScript, especially when building complex strings such as query strings or multiline strings. Template literals in JavaScript are interpolated strings, meaning they allow for having variables in the string which the JavaScript engine will substitute with values. The end results of the interpolation is a string.

`Template literal is a ${adjective} way to build a template.`

Template literals themselves are not type String and therefore are not supported outside the context of JavaScript, for example in a JSON file. Why does this last part matter?

Configurations

Nearly all applications use configuration files to store data outside of the runtime code. Whether it be for initializing the application, securing API tokens or storing runtime flags. If our application used a JavaScript configuration file “.js” then our story would end here, since we could put our configurable template literal directly into the file. However, many applications utilize JSON files for storing configurations, as is the case for our A/B experimentation tool.

Tip: don’t let the JS in JSON fool you, it’s language independent.

JSON is a widely used data structure in many programming languages and architectures. Because it is language agnostic, it only supports the data type, text.

TempLitSON?

Which brings us to our second problem. If template literal is a construct of JavaScript and JSON only supports text, how can we store a template literal configuration within a JSON?

Obvious Answer: store it as a string

JavaScript again has a couple methods for evaluating strings to objects or functions or even… template literals! So what are these magic options and how do we choose the best one?

  • eval — dangerous because it opens security vulnerabilities, poor performance, and highly discouraged
  • function constructor — minor security concerns depending on how it’s used, a bit better performance over eval, globally scoped, ie. not lexical to the function where it was constructed

The function constructor in JavaScript lets us create a new function object passing a string to be evaluated as the function body. More on this later.

new Function(‘a’, ‘b’, ‘return a + b;’);

The Engine

Because the function body is evaluated, it can be a string, object, or a template literal. By utilizing this feature of the function constructor we created the Template Literal Engine. We solve both of our challenges above by letting us build complex queries using template literals and letting us store the templates as strings in our configuration JSON.

We utilize the power of template literals while abstracting the external logic out to a config.

Let’s see it in action

Following walkthrough and code examples courtesy of Jean Pan

First Try: String concatenation

string concatenation example

The above code obviously works but if the string is very long it will become clumsy with single quotes and double quotes wrap the string literal, you need to escape the quotes. It’s very error prone especially when there are more complicated and lengthy strings.

Can we do better?

Second Try: string interpolation

Template Literal provides a clean way to allow us to manipulate string literal and it’s easy to read. To use template literals simply wrap the string literal in back-ticks. With that we can refactor our function like this:

string interpolation example

When this function is called with url = “www.walmart.com”, it will substitute the ${url} with the parameter url which is “www.walmart.com’’ and return the result as:

Page attribute “url” should match “www.walmart.com”

This process of replacing a placeholder ${url} with value “www.walmart.com” in the string literal is called string interpolation.

Since it’s wrapped with back-ticks, you can use either single or double quotes in the template literal, no more ugly escaping back slashes!

Third Try: template literal with dynamic function

The above code works but it lacks in flexibility. What if the query depends on external variables as in our problem statement above?

The solution we want is to define the query in a JSON configuration file and load the query at runtime. Now the problem is when the query is loaded it’s a string. How do we convert a string into a template literal and also do the string interpolation?

The solution is the dynamic function generation using the function constructor.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

The above example can be refactored to:

Let’s take a closer look at how it works

Syntax:

new Function([args], functionDefinition);

Calling this newly generated function:

new Function([args], functionDefinition)(…value);

Dev Tools console showing evaluated function

As you can see, the new function generated takes two parameters called url and loggedIn and returns a template literal.

Notice how we call the newly generated function with (…value). This syntax is referred as ‘rest parameters’ which allows variable number of arguments to be passed into a function. A function’s last parameter can be prefixed with ... which will cause all remaining (user supplied) arguments to be placed within a "standard" JavaScript array.

See the documentation for details.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters

Conclusion

On a daily basis at Walmart Global Tech we work to find elegant solutions that make complex problems simple. With our new Template Literal Engine we used a combination of JavaScript capabilities (string interpolation, function constructor, rest parameters) to solve our problem. We use dynamic function generation built complex queries out of template literals stored as strings in a JSON configuration. Or to state in simpler terms, we’ve made our templates configurable.

--

--

Justin Rubin
Walmart Global Tech Blog

Father/Runner/Developer/Early Riser. Staff Software Engineer