DEV Community

Nick | OneThingWell.dev
Nick | OneThingWell.dev

Posted on • Originally published at betterways.dev

5

Simple JavaScript template engine by (ab)using template literals

Templating inline strings is simple using ES6 template literals:

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

console.log(`${a} ${b}`)
//hello world
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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

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

Example:

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

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);
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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.




Note: This is a snapshot of the wiki page from the BetterWays.dev wiki, you can find the latest (better formatted) version here: betterways.dev/simple-javascript-template-engine-by-ab-using-template-literals.

Tiugo image

Modular, Fast, and Built for Developers

CKEditor 5 gives you full control over your editing experience. A modular architecture means you get high performance, fewer re-renders and a setup that scales with your needs.

Start now

Top comments (0)

Neon image

Next.js applications: Set up a Neon project in seconds

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Get started →

👋 Kindness is contagious

Please show some love ❤️ or share a kind word in the comments if you found this useful!

Got it!