WebReflection / lighterhtml

The hyperHTML strength & experience without its complexity 🎉
https://medium.com/@WebReflection/lit-html-vs-hyperhtml-vs-lighterhtml-c084abfe1285
ISC License
735 stars 20 forks source link

template from string #56

Closed Punk-UnDeaD closed 5 years ago

Punk-UnDeaD commented 5 years ago

What about simple string interpolation?

<template is="d-app-bind">
      <li hidden=${!user.isAuthenticated}>
             <a href=${user.logoutLink()}>Exit</a>
      </li>
</template>

I want something like this. So my template in string, not in js.

Look my solution for this

(() => {
  const {render, html} = lighterhtml;
  customElements.define('d-app-bind', class extends HTMLTemplateElement {
    constructor() {
      super();
    }
    processItems(items) {
      const context = {user: this.user};
      for (let i = 0; i < items.length; i++) {
        let v = items[i].substr(2, items[i].length - 3).split('.');
        let value = context;
        let not = false;
        let notnot = false;
        if (v[0][0] === '!') {
          not = true;
          v[0] = v[0].substr(1);
        }
        if (v[0][0] === '!') {
          notnot = true;
          v[0] = v[0].substr(1);
        }
        for (let j = 0; value && j < v.length; j++) {
          let ar = v[j].match(/(.+)\((.*)\)/);
          if (ar) {
            ar[2] = ar[2].split(/\s*,\s*/);
            value = value[ar[1]](...ar[2]);
          }
          else {
            value = value[v[j]];
          }
        }
        items[i] = value;
        if (not) {
          items[i] = !items[i];
        }
        if (notnot) {
          items[i] = !items[i];
        }
      }
      return items;
    }

    connectedCallback() {
      const dUser = document.querySelector('d-user');
      this.user = dUser.user;
      const re = /\$\{[^\}]+\}/g;
      this._chunks = this.innerHTML.split(re);
      let items = this.processItems(this.innerHTML.match(re));
      this._child = document.createDocumentFragment();
      render(this._child, () => html(this._chunks, ...items));
      this.parentElement.insertBefore(this._child, this);
      dUser.addEventListener('user.update', () => {
        this.user = dUser.user;
        let items = this.processItems(this.innerHTML.match(re));
        render(this._child, () => html(this._chunks, ...items));
      })
    }

  }, {extends: 'template'});

})
WebReflection commented 5 years ago

using templates as string literals trash bins is not really in the spirit of this library + your solution is both slow, not efficient (lighterhtml parses template literals once, not per each usage, thanks to the template literal uniqueness per scope), and easily error prone when string contains ${ or other chars.

accordingly, I don't think this library will ever have anything like that, but feel free to find your own solution to this.


P.S. your code is also unreadable compared to natural lighterhtml usage, and I honestly believe if you need to avoid template literals you are better off with any other library, not this one.