Literally Useful

Andrea Giammarchi
4 min readAug 3, 2020
Photo by Martin Wilner on Unsplash

I’ve been dealing, and developing, with ES2015 template literals, since their first TC39 appearance, and I think it’s time to talk more about these.

JS Template Literals in a nutshell

Historically introduced as “yet another way to write strings in JavaScript”, there are still may developers not understanding where is the power of this relatively recent JS feature. Well, there are fundamentally two ways to use template literals, but many stops at the first one:

const str = `template literal with ${someValue} in it`;

That’s a string that allows multi-lines without ugly escape, and interpolated values, as someValue is, without needing any sort of concatenation: congratulations, you’ve learned 30% of JS template literals potentials!

Template Literals Tags

We gotta scroll a little bit more in MDN, but the most hidden, yet valuable, gem of template literals is represented by tags!

A template literal tag is any function we want, that will accept the template as first argument, and zero, one, or more extra arguments, as interpolated values:

const tag = (template, ...interpolations) => {
console.log(template);
console.log(interpolations);
// it can return anything, not just strings
};

A tag function is nothing special, in terms of being just a function, but its signature is extremely special, for these reasons:

  • the template first argument is a frozen array of string chunks, and it’s unique per each used template, within its own scope
  • the interpolations values are always a part from the template, so that we can use, analyze, combine, discard, wrap, or mutate, these values as we please
const content = value => tag`received ${value} 👍`;content(1);
content(2);

Above example, passing through the previous tag function, will log:

["received", " 👍"]
[1]
["received", " 👍"]
[2]

And while it’s obvious that the logged interpolations will produce [1] and [2], what’s usually less obvious is that the template, in any content(value) call, will be the exact same reference.

And “how is that relevant”, you might ask?

My Template Literals Libraries

You might have heard that nowadays innerHTML is still “forbidden” to create safe Web content, but fear not, uhtml, lighterhtml, or hyperHTML, got you covered, together with uland, neverland, heresy, ucontent, heresy-ssr, and you name it. Well, these are just scratching the surface of libraries based on template literals that work in an extremely smart way, so that only interpolations get updated per each repeated usage: simple, safe, performance guaranteed, what else?

Just plain tags

The plain-tag module provides the minimal abstraction to use any tagged template literal for tooling purpose: css tags, html tags, i18n tags, or anything you like, really, so that your IDE/tool of choice can highlight, change behaviors, or validate, whatever is within that specific string:

import css from 'plain-tag';export default selector => css`
${selector} {
color: green;
}
`;

This example would highlight CSS in any editor instrumented to do so with a css tag prefix, and so it is for html tags, as literally-html does!

plain-tag is also the smallest, and fastest, module out there, to deal with tags that are meaningless, so that using it should be a no-brainer.

String content as template literal

tag-params is a module that transforms static strings, either provided via SSR or through <template> tags, into parameters/arguments suitable for any kind of template literal tag:

import {params} from 'tag-params';tag(...params('Random: ${Math.random()}!'))

Any string containing ${...} parts, will be evaluated to be a unique template literal, with one or more interpolations.

Interpolations as static chunks

static-params goes one step forward, enabling parts of any template literal to become as if these were part of the unique template array, passed to any template literal tag function:

import {asStatic, asParams} from 'static-params';

const name = asStatic('tag');
const params = asParams`<${name}>${'content'}</${name}>`;

// params is now usable as template literal tag arguments
// [['<tag>', '</tag>'], 'content']

html(...params);

While its most common use case is to enable parts of any HTML template literal based library to be considered as if these were static, it’s been successfully used in both the following modules!

Database Safe Queries

Both pg-tag and sqlite-tag modules allows us to write SQL injection safe queries, through a unified interface that works across these DBs without changes:

const user = await pg.get`
SELECT
id, name, address
FROM
users
WHERE
email = ${email}
`;

const users = await pg.all`
SELECT *
FROM users
WHERE status = ${activeUser}
`;

await pg.query`
SELECT *
FROM users
WHERE status = ${activeUser}
`;

These tiny modules ensure that any interpolated value is never passed as part of the query, and used as drivers parameters instead, enabling SQL injection protection out of the box, for something extremely natural to read and write!

Next usage is on you!

As much as I’ve been using for both experiments and production template literals goodness, when it comes to their tag functions, I’d love to see more developers embracing their powerful ergonomics, and cross browser availability, including a proper Babel 7 transformation, form all developers that just learned how wonderful this feature is for modern client/server development … so please, do let me know what you created after realizing what template literals, and their tags, can do for your use cases 👋

--

--

Andrea Giammarchi

Web, Mobile, IoT, and all JS things since 00's. Formerly JS engineer at @nokia, @facebook, @twitter.