Simple JavaScript template engine by (ab)using template literals

📄 BetterWays.dev wiki page | 🕑 Last updated: Sep 12, 2022

Templating inline strings is simple using ES6 template literals:

const a = "hello"
const b = "world"

console.log(`${a} ${b}`)
//hello world

But what if you have a string that can't be inlined (i.e. it comes from an external source)?

Here's the gist of the function I recently used for this purpose:

function tpl(str, props) {
    let names = Object.keys(props);
    let vals = Object.values(props);
    return new Function(...names, `return \`${str}\`;`)(...vals);
}

Or, (a slightly less readable) one-liner version:

const tpl = (str, props) => new Function(...Object.keys(props), `return \`${str}\`;`)(...Object.values(props))

Example:

console.log(tpl('${a} ${b}', {a: 'hello', b: 'world'}))
//hello world

Explanation

So, we are defining a function called tpl:

function tpl(str, props) {
    let names = Object.keys(props);
    let vals = Object.values(props);
    return new Function(...names, `return \`${str}\`;`)(...vals);
}

The first two lines are self-explanatory - we are just extracting keys and values from the passed-in props object.

In the last line, we are dynamically creating a function from a string. Instead of doing eval, we are using the Function constructor, which is a much safer alternative.

Our new (dynamically generated) function receives a list of names of our props keys, and returns the same passed-in str string but delimited with backtick characters (basically, we are turning our "external" string into an inline template string).

After that, we just need to call our new function with a list of values.

Function.call alternative

We could simplify things by doing something like this instead of extracting names and values:

new Function(`return \`${str}\`;`).call(props)

But then we would need to use ${this.a} instead of just ${a}.

Caching

Each time you're calling the Function constructor, the function body needs to be parsed (some overhead), but it would be very easy to do some caching based on the value of str.


Comments and suggestions

You can use this form to submit a suggestion or a comment.

If you find this site useful, please consider supporting it. Supporters also get access to some extras.