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

@dmitriid Neither template instantiation or `lit-html` use `.innerHTML` to update the DOM. This seems to be some FUD around how template instantiation works but template instantiation and `lit-html` actually work *more* efficiently than a virtual DOM by holding references to part of the DOM that have template parts. In `lit-html`'s case, it *only* creates the initial template using `.innerHTML`, to actually update the DOM it [inserts nodes directly into the correct location (and similar for attributes)](https://github.com/Polymer/lit-html/blob/master/src/lib/parts.ts#L203).

For example consider this template:

```html
<template id="exampleTemplate">
  <span title="{{foo}}">This is a sample {{bar}} with instantiation</span>
  <span>Also {{foo}}</span>
</template>
```

when we create an instance of the template a set of references are created to the elements that have that name:

```
{
  foo: [
    AttributeTemplatePart {
      el: /* ref to <span title="{{foo}}"> element */
      attrName: 'title',
    },
    NodeTemplatePart {
      previousNode: /* The previous text node before {{foo}}: "Also" */
      nextNode: /* The text node after {{foo}} */
    },
  ],
  bar: [
    NodeTemplatePart {
      previousNode: /* The previous text node before {{bar}}: "This is a sample " */
      nextNode: /* The next text node after {{bar}}: " with instantiation"
    }
  ],
}
```

now when we call something like `instance.update({ foo: 'banana', bar: 'cabbage' })` all `.update` needs to do is something like this:

```js
function update(data) {
  for (const [key, value] of Object.entries(data)) {
    for (const templatePart of this._templateParts[key]) {
      templatePart.update(value)
    }
    this._templateParts[key].update(value)
  }
}
```

this is *way more efficient* than maintaining a virtual copy of the DOM as we simply implement `AttributeTemplatePart` and `NodeTemplatePart` so that they go directly to their location in the DOM and update the value.

e.g. `NodeTemplatePart` could be implemented like this:

```js
class NodeTemplatePart {
  constructor(previousNode, nextNode) {
    this._previousNode = previousNode
    this._nextNode = nextNode
  }

  // This is overly simplified and assumes there's a node both before and after
  // the {{curlies}}, a real implementation would hold a reference to the parent element
  // as well and if there's no previousNode/nextNode it'd just replace the whole contents
  update(values) {
    if (typeof values === 'string') {
      values = [new Text(values)]
    }
    while (this._previousNode.nextNode !== this._nextNode) {
      this._previousNode.nextNode.remove()
    }

    for (const value of values) {
      this._nextNode.parentNode.insertBefore(value, this._nextNode)
    }
  }
}
```

-- 
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-476025026

Received on Monday, 25 March 2019 01:31:07 UTC