ES6 templates are very powerful and can serve as a complete replacement of any template engine.

In the last post about ES6 templates, we saw its usage and customizability. Today we will take a look at a bit more complex usage; which is to execute JavaScript code inside ES6 templates.

To accomplish this, we need to create IIFE i.e. Immediately Invoked Function Expression inside template which will add the additional info to the supplied data (let's say it is scope)

Consider following es6 code for the article template:

const articleTemplate = (scope) => `<article>
  <header>
    <h1><a href="${scope.link}">${scope.heading}</a></h1>
  </header>
  <div class="tags">
    ${scope.tags.map(tag => `
      <a href="${tag.link}" class="tag">${tag.name}</a>
    `).join('')}
  </div>
  <div>
    ${scope.body}
  </div>
</article>`

In above code, every tag link has class tag with it. We want to apply specific class to tags which have js attached to them.

There are certain ways to achieve that, but; let's say, for example, we do it with IIFE inside templates.

Here is how it will transform:

const articleTemplate = (scope) => `<article>
  <header>
    <h1><a href="${scope.link}">${scope.heading}</a></h1>
  </header>
  <div class="tags">
    ${scope.tags.map(tag => `
      ${(() => {
      tag.classes = (tag.classes || [])
          .push(tag.name.matches('js') ? 'tag-blue' : '')
      })()}
      <a href="${tag.link}" class="${tag.classes.join(' ')}">${tag.name}</a>
    `).join('')}
  </div>
  <div>
    ${scope.body}
  </div>
</article>`

In above code, following piece of code:

${scope.tags.map(tag => `
  ${(() => {
    tag.classes = (tag.classes || [])
      .push(tag.name.matches('js') ? 'tag-blue' : '')
  })()}
  <a href="${tag.link}" class="${tag.classes.join(' ')}">${tag.name}</a>
`).join('')}

is responsible to enrich the passed scope with more information and then use for classes.

This way some small calculations can be executed inside a ES6 template.

If you wanna go more complex, following example may help you understand it. Suppose we have different types of post in a blog like article (text), video, audio, link, etc. And with one template will unify the way to include the different posts.

Following template post.html.js will be the primary one used by the index.html.js:

module.exports = (scope) => `${scope.type ?
  require(`./${scope.type}.html.js`)(scope) : `
    <h1>${scope.title || '---'}</h1>
    <div>${scope.body || '...')</div>
`}`;

And the sub-templates for the various types of post can go as follows; along with the tag template that we created in the code sample created earlier:

module.exports = (scope) => `<div class="tags">
  ${scope.tags.map(tag => `
    ${(() => {
    tag.classes = (tag.classes || [])
        .push(tag.name.matches('js') ? 'tag-blue' : '')
    })()}
    <a href="${tag.link}" class="${tag.classes.join(' ')}">${tag.name}</a>
  `).join('')}
</div>`;
module.exports = (scope) => `<article>
  <header>
    <h1><a href="${scope.link}">${scope.title}</a></h1>
  </header>
  ${require(`./tags.html.js`)(scope)}
  <div>
    ${scope.body}
  </div>
</article>`
module.exports = (scope) => `<article>
  <header>
    <h1><a href="${scope.link}">${scope.title}</a></h1>
  </header>
  ${require(`./tags.html.js`)(scope)}
  <div>
    <video src=${scope.video.src} autoplay="off"></video>
  </div>
  <div>${scope.video.description}</div>
  <div>${scope.body}</div>
</article>`

And similarly we can create templates like link.html.js, audio.html.js, etc.


Let us know what you think about the ES6 templates via comments. Share the article with friends, colleagues and everyone who can be benefited from it.

If you are stuck somewhere while utilizing above concept, reach out through comments below and we will try to help.