Re: [w3c/webcomponents] [templates] Ensure that template instantiation actually improves the platform (#704)

@bahrus 

I do apologise if I sound terse or rude in the text below, as I'm writing this rather quickly in a spare moment (I wanted to acknowledge your response quickly, and not have you wait for a day or two).

> I don't follow why template instantiation could only be used inside a web component. It would be useful anytime there's repetitive markup that needs customizing in each instance.

The whole discussion is mostly in the context of Custom Elements and Shadow DOM (see [2. Use Cases](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Template-Instantiation.md)). The proposal itself is only limited to `<template>` elements. 

That's why in my mind it was only limited to custom elements.

However, true, you can use them elsewhere:

```
rniwa = {name: "R. Niwa", email: "rniwa@webkit.org"};
document.body.appendChild(contactTemplate.createInstance(rniwa));
```

This does still leave the question of how to more complex/nested templates where parts of a template are defined in other templates etc.

> but you can evaluate any function you want during the processing, which could have unexpected side effects.

That is, side effects that are desired by the developer using it ;). There's no way to use a template that has this:

```
{{foreach items}}
   <li class={{class}} data-value={{value}}>{{label}}</li>
{{/foreach}}
```

without first calling arbitrary functions to create these items and binding them to the template. And since the proposed way of creating such things is the same old DOM API with hardly any improvements, I fail to see the improvement.

And as you correctly mentioned, templates will need to be able to call arbitrary functions.

>  I fail to see how it is easier to use than tagged template literals. Could you elaborate? The performance numbers I've seen comparing lit-html and hyperHTML, compared to react (and even preact) make me wonder what your objections are?

The only reason lit-html works as it does is that dozens (hundreds?) of engineers spent hundreds of hours optimising to things that are frequently used and abused in JS:

- string processing and RegExps
- `.innerHtml`

More or less the only thing that lit-html does is parse a string at runtime, with regexps, concatenate it into an opaque string blob, and dump it into browser via `.innerHtml`, and let browser deal with it. (I have a separate rant on tagged template literals [elsewhere](https://dmitriid.com/blog/2019/03/tagged-template-literals/)).

It's not a good thing. It's a very bad thing, it only happens to work fast enough because browsers have had decades to optimise this (and ten years ago using `.innerHtml` was considered extremely bad practice see e.g. [this StackOverflow comment](https://stackoverflow.com/a/11854965/445049), and even now `.innerHtml` is not optimised enough for [certain cases](https://coderwall.com/p/nygghw/don-t-use-innerhtml-to-empty-dom-elements), _and_ there are [security considerations](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)).

Meanwhile declarative DOM/virtual DOM libraries have to recreate the entire DOM model in memory, and manually diff it against the browser DOM.

The solution to all that (and to template instantiation) is definitely not, in my opinion:

-  a limited templating language that can only be used in `<template>` elements, and whose actual API is only marginally better than the rest of DOM APIs (and introduces a host of other problems, some of which
- concatenating strings at runtime and dumping them into the DOM via `.innerHTML`

A declarative API (with, hopefully, browser-native DOM-diffing) solves a lot of the problems:

- data binding (it just becomes function calls with your data/parameters)
- efficient DOM updates (you only regenerate parts of the tree that change)
- instantiation (it's just a function call, and many lifecycle methods to trigger it that are already there)

It may/will still be awkward to use, obviously. The next best thing, IMO, would be a standard/declarative way to create a DOM AST that you can pass to the browser. Virtual DOM libs, in essence, do that already. To quote [Dan Abramov](https://overreacted.io/react-as-a-ui-runtime/):

```js
// JSX is a syntax sugar for these objects.
// <dialog>
//   <button className="blue" />
//   <button className="red" />
// </dialog>
{
  type: 'dialog',
  props: {
    children: [{
      type: 'button',
      props: { className: 'blue' }
    }, {
      type: 'button',
      props: { className: 'red' }
    }]
  }
}
```

Unfortunately, we cannot generate this AST for the browser and let it deal with it efficiently. We have to fall back to `.innerHtml` or hundreds of lines of tedious imperative code (or use libs/frameworks/wrappers).

With a natively supported declarative description of the DOM/AST you still have a low-level primitive that libs/frameworks can make even easier to use, but you can also trivially use it in vanilla JS code.

I do hope I made sense in the ramblings above :)

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/704#issuecomment-475232043

Received on Thursday, 21 March 2019 13:40:12 UTC