Lit-html: Request to clarify DOM-updating feature

Created on 21 Jun 2019  ยท  36Comments  ยท  Source: Polymer/lit-html

(Semi-quoting from https://news.ycombinator.com/item?id=20246407)

So lit-html has the incremental DOM update feature built-in? It's a full-fledged replacement for the VDOM? I thought it was just a syntax parser like HTM.

I see where I got mixed up: in your README, the only part where I can find mention of this feature is in the very last part of this line:

lit-html templates are plain JavaScript and combine the familiarity of writing HTML with the power of JavaScript. lit-html takes care of efficiently rendering templates to DOM, including efficiently updating the DOM with new values.

Specifically the "including efficiently updating the DOM with new values" part, that's the only mention on this page, and it's literally right after where I started to skim due to (incorrectly) assuming the rest of the sentence was just a continuation of the first part.

That feature should probably be mentioned more prominently.

Also, if it has the ability to re-render based on state updates (e.g. from onclick callbacks), an example would be really important to know how to make use of that feature.

All 36 comments

So lit-html has the incremental DOM update feature built-in? It's a full-fledged replacement for the VDOM? I thought it was just a syntax parser like HTM.

I'm not 100% sure what you mean by this. The return value (TemplateResults) from html tagged templates is not vDOM, and can't be used in places that expect vDOM. Instead, you have to use the render function to take these TemplateResults and update the container element.

including efficiently updating the DOM with new values

The efficient updates are better explained at https://youtu.be/Io6JjgckHbg?t=1012. It's talking about how we can update the DOM without comparing every node in your template, we only have to check the things that _can change_.

It's good feedback that we could explain this better. I've definitely heard that before. I'm open to ideas here, including new wording, a name for the concept, comparisons, GIFs that show the minimal DOM updates, etc...

cc @arthurevans

I think something that would help a lot in educating people on how lit-html works and what it does is find some kind of nomenclature for the underlying algorithm, like how React has VirtualDOM. We have several implementations of the same general algorithm now; HyperHTML, lit-html, lite-html; but there is no common way to describe what they are doing.

I find that users are much more open to learning/understanding an idea or concept like "VirtualDOM" than something like "How React works internally". A term like 'VDOM' or 'VirtualDOM' is also portable between different implementations of it, and once users grasp the concept, they will understand what React, Preact, Vue, and all these frameworks do, without having to understand their specific implementation.

Instead of explaining how lit-html works, can we find a common nomenclature for this type of updating DOM, and focus on explaining that? That way we can combine educational efforts from multiple projects, and it also opens up things like speaking about the concept at general JavaScript conferences without being focused on one project.

Paging @WebReflection

All my libs are based on domdiff, but also other libraries use it (see latest riot.js).

Domdiff is based on petit dom diffing algo https://github.com/yelouafi/petit-dom/blob/master/README.md#petit-dom

I call it dom diffing and usually people understand what is it about

I think using (nested) tagged template string literals to construct a tree of dynamic and static parts of DOM is the key differentiating idea. The method used to update the dynamic parts (either using domdiff or previous-value-comparisons like what lit-html does) seems like a detail that is not necessarily novel or relevant to create understanding of how the system works (You can even call that part 'dom diffing' and leverage the user's existing knowledge).

It would be nice if we could find a name for the concept of constructing a tree of dynamic and static parts, and using that information to render and propagate updates.

Would MDOM work? As in Meomized DOM, since each unique template literal is
created and scanned once, hence the resulting DOM is meomized once too ๐Ÿค”

On Sat, Jun 22, 2019, 14:21 Goffert van Gool notifications@github.com
wrote:

I think using (nested) tagged template string literals to construct a tree
of dynamic and static parts of DOM is the key differentiating idea. The
method used to update the dynamic parts (either using domdiff or
previous-value-comparisons like what lit-html seems like a detail that is
not necessarily novel or relevant to create understanding of how the system
works (You can even call that part 'dom diffing' and leverage on the user's
existing knowledge).

It would be nice if we could find a name for the concept of constructing a
tree of dynamic and static parts, and using that information to render and
propagate updates.

โ€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Polymer/lit-html/issues/950?email_source=notifications&email_token=AAAU55IE5MAVAM7E5VLGNL3P3YKL5A5CNFSM4H2U6UTKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYKIKQQ#issuecomment-504661314,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAU55IH6NCHPFKOYJBUNRDP3YKL5ANCNFSM4H2U6UTA
.

Also, I think what HyperHTML does well is communicate directly that it is a "VirtualDOM replacement" which immediately sets the user's expectation, which seems to be the main source of confusion for the OP. I think lit-html could do much better in that sense, because it's current description of "HTML templating library" is rather vague and doesn't leverage the user's existing knowledge.

MDOM or MemDOM is a good suggestion, I like it.

how about "Adaptive DOM" e.g. only needed changes are "adapted"

I think memorized Dom is already a thing? I remember reading about it's while back. https://www.google.com/amp/s/www.freecodecamp.org/news/the-virtual-dom-is-slow-meet-the-memoized-dom-bb19f546cc52/amp/

Perhaps I could give an outsider's perspective on how to phrase it, but first I would need to understand how this feature works. Can you give an example of it in action? Can it change state via an onclick handler and update the DOM accordingly? What would be a minimal functioning example of this in action using lit-html?

Differential Dom

Oh I think I finally understand: this library doesn't actually re-call render(...) for you, but when the user calls render a second time, this library updates the DOM more efficiently. Okay that clarifies things.

So then it's just kind of an efficient DOM updating. Neat. Not sure it really needs a name in this case.

But it does seem confusing that this library handles both things. HTM does the same string transformation as lit-html, but lit-html also has a DOM-updating function (render). Seems like two unrelated functionalities rolled into one. I could see there being a convenience reason for it, but it doesn't even go all the way with convenience, either: the user still has to write the plumbing to connect render up to actual DOM events (onclick, etc). So it seems like lit-html should go in either one direction or the other: either split functionality into other libraries, or add more conveniences to this one. Just my 2ยข.

@sdegutis - have you by chance seen https://lit-element.polymer-project.org/ ? It might be one of those "split out" libraries you were looking for.

@ZempTime Thanks for suggesting LitElement. I looked it over with a lot of interest the other day, and it seems like a self-contained miniature version of React, which is overall a really good idea. But the fact that it uses class syntax and class features, especially decorators and class-fields syntax, really puts me off. I've converted every single one of my class-based React components into hooks-based functions. I'm still not convinced React is the way forward, I think it was a good innovation but it has a lot of drawbacks which is why I'm still looking for something better. LitElement looks like it's closer to what React should be in terms of how it works. I just can't get past its class-based interface. That's what drew me to lit-html.

@sdegutis I have an old gist called hyperHTML the nitty gritty, where you can travel how things work inside.

What you need to understand is that template literals are unique per scope, so that:

function tag(chunks, ...values) {
  return chunks;
}

function tpl(unique) {
  return tag`this is ${unique}!`;
}

tpl(1) === tpl(2); // true, same template literal

and that acordingly, you can map the chunks once, through a WeakMap, so that one template literal correspond to a specific DOM tree, which could be imported or clone any time its needed.

Such DOM tree will be parsed only when a new template literal is encountered, so that it's slow on cold parsing, but it gets instantly hot on every update, but once all holes to update with either attribute values, children, or text content, will be performed as specific callback.

TL;DR

The first time a template is used, having function html(chunks, ...values) { ... }

html`<div class=${'holy'}>A ${'hole'} and ${'another'}</div>`;
  • create a DOM tree representation of such template, filling holes in a discoverable way
  • traverse the whole tree looking for holes, map each hole to each interpolation update (attribute, content, text)
  • create a list of updates that matches the amount of interpolation

From that time on, updating the class or the content inside hole or another would be as simple as:

function html(chunks, ...values) {
  let info = known.get(chunks);
  if (!info) // unknown template, perform all the tasks once
    known.set(chunks, info = doAllTheParsing(chunks));
  // use updates to pass new data to the node
  info.updates.forEach((callback, i) => {
    callback(values[i]);
  });
}

Updates can be attributes, including special attributes, nodes with just a textContent to change if different, in this case the hole and another content within those two specific text nodes, or anything else really, when you have directives/plugins included.

The summary of all this is:

  • convert template literals chinks into a DOM tree with a map of holes to address per each update
  • use these updates to set new values to anything they are referred too

I hope this explanation, even if not directly related to how lit-html works, helps understanding the overall idea of what these libraries do.

@blikblum "Haunted" looks really cool, thanks for sharing it. I'm closer to the opinion of @Rich-Harris about Hooks. I think they're great as a React-specific feature, but very coupled to the specific implementation of React, which deals with and relies on render-cycles. I'm not of the same opinion as Rich that a compiler is the way to go by hiding the updates, but I do think there's still a need for a library that does what React does but in more of a surgical way, something closer to Svelte and LitElement. (Maybe LitElement but without the class-based interface? I need to look into LitElement's implementation more.)

@WebReflection Yes that is very informative, thank you. I do believe that this approach is probably an improvement over the VDOM approach that React takes, which is why I think a library that builds on this approach can actually compete with React. I really think lit-html is a good first step, but it seems like the plumbing to a dev-facing library rather than a dev-facing library itself. I see that LitElement builds on it, but I'm not convinced it builds in the right direction by providing the best dev-facing interface it can, mostly because it uses classes, decorators, and class-field syntax, which are in my experience less than ideal in many small ways that add up.

I think my question has been sufficiently answered as to how this feature works. I think the README is probably good enough at explaining it, and it was probably just that I tried reading it at 4:30pm when my mind was starting to slow down. So I'm not sure any clarification in the README is necessary.

@sdegutis - what kind of component model are you searching for? I share the same instinct you've expressed here. A big reason lit-element uses the class-based syntax is because then you can directly register a custom element:

customElements.define('popup-info', PopUpInfo);

it uses classes, decorators, and class-field syntax, which are in my experience less than ideal in many small ways that add up.

What other directions would you ideally go with this (existing or not)?

@sdegutis my alternatives in a nutshell:

  • neverland, which is currently problematic in some case, but you can have an idea of how hooks look with lighterhtml. Please note, it's not maintained, but one day it might move further
  • heresy, which offers SSR and also compose with objects literals, like in this TwitterShare case

The _heresy_ approach is that you define components like TwitterShare and then you write your content as such:

render(document.body, html`
  <TwitterShare
    text="A Twitter share button with progressive enhancement"
    url="https://github.com/WebReflection/heresy#readme"
    via="webreflection"
  />`
);

It offers nested custom elements too, so there's never name clashing issue (beside what lands globally on the document), and you can compose like:

import {html} from 'heresy';

import List from './list.js';
import Item from './item.js';

const MyComponent = {
  extends: 'div',
  includes: {List, Item},
  render() {
    this.html`
    <h3>This is the list</h3>
    <List>${[1, 2, 3].map(i => html`<Item value=${i}/>`)}</List>`;
  }
};

Maybe not exactly a hooks based experience, but it gives you custom elements builtin extends and everything else I've personally ever dreamed about composing Web Components.

Hopefully worth a shot ๐Ÿ‘

@ZempTime Honestly I'm not sure, which is why I'm still searching and finding these kind of conversations very valuable.

So far I'm not convinced that custom-elements are really necessary, especially since we can declare our element hierarchy in a string which doesn't have to literally match up with the actual DOM. Artificial tag-names could be stored in data-tag-name to keep them in sync.

I think that React's render-cycle feels a bit clumsy and over-hyped, and I like the idea of surgical on-demand updating of the DOM that Svelte and lit-html use. I have to look into lit-html a little more, but I think a better API could be built on top of it than LitElement.

All of this reminds me of one little trick that @lhorie mentioned somewhere on mithril.js.org a few years ago: create a function that acts as both a setter and a getter, which can then take action on either set-or-get. This convinced me that we can have truly declarative UIs, but I ran into confusion when trying to put this into action using mithril.js.

I'm too uneducated on the implementation of these kinds of frameworks to know if this would be useful, but I always look back to that as an example of the kind of power we could get without sacrificing simplicity of API. It's also why I think the Svelte compiler is kind of going overboard, and the same concepts could be done with a simpler non-compiler API.

@sdegutis if you are referring to the recent Rich rant on Web Components, you should probably read answers here and there, including mine https://gist.github.com/WebReflection/71aed0c811e2e88e3cd3c647213f0e6c ๐Ÿ‘‹

@WebReflection I didn't know Rich made such a rant. The first time I heard of Rich was yesterday when I was reading about Svelte for the first time.

My opinions on web-components was formed by looking into them and seeing if their features would fit my use-cases. Overall it seems very much like the wrong solution. In fact, and this is just my opinion, it seems like an answer to a question nobody was asking.

I know there's a complex history around web components, and they actually came out even before React. But web components feels like a solution that's only a genuine benefit in a very small set of niche situations.

Looking at your examples in your counter-rant, I don't see any situations where web-components has any legitimate advantage over alternatives like React for regular web development, where the developer has complete control over the DOM, over all JavaScript and HTML and CSS on the page, and where it's loaded from. In this situation, web components seems like it's simply an alternative, with its own pros and cons, and no clear advantage.

@sdegutis Custom Elements alone are a great primitive, IMO. All these libraries here are trying in a way or another to show their potentials, once simplified to the extreme.

The heresy latest idea lets you create components like in Svelte, or even React, and have automatic SSR with even cleaner outcome as result, and fully asynchronous auto re-hydration on the client once the component definition reaches the client too.

The best part of it, is that components could be used within Svelte or React, and these will likely just work in there too.

Vice-versa requires tooling, and tooling is not always straight forward to add/change, these libraries work out of the box without needing special environments to develop, or even work.

I consider these points already an advantage of using Custom Elements (no need to use Shadow DOM and other things from WC umbrella, Custom Elements with builtins are already pretty awesome)

Thanks @WebReflection for the perspective and insight.

@WebReflection I can't believe you would come in here after falsely accusing me of stealing your code and ideas. It's incredibly inappropriate to show up and promote your own projects. You can do that in your own spaces.

@ruphin and everyone else. I'm very done interacting with people who make such baseless and false claims against me. As long as I'm associated with the project, please don't tag him in here. Thanks.

As I said before, my question has been sufficiently answered and I don't think there's any need to change the README at all. I think I just goofed in misreading it. But it's up to you if you want to close this issue or continue to discuss clarifying the incremental-updates feature in the README, I'll leave it open just in case.

If the original author thinks this issue can be closed, we can probably close it. I will find a new appropriate space to continue the naming discussion.

In retrospect I think that using a phrase like DOM diffing, or incremental DOM updates, would clarify this. And specifically, bringing that point higher (to make it less obscure) in the README would be helpful. (Clarifying that this is what the example does, might also help, but it might already be clear enough and I just didn't get it that one day.)

incremental DOM is bad choice given its history (BTW another google project)
https://github.com/google/incremental-dom

I'm not suggesting that as a name, but "incremental DOM updates" as a clarifying phrase somewhere at the top of the README. I'm not sure a new name is even necessary.

Closing my thoughts: I-DOM with an Interactive prefix sounds great ๐Ÿ˜‚ (just
kidding, but good to know devs are looking for better understanding on how
these libraries work underneath) ๐Ÿ‘

On Mon, Jun 24, 2019, 20:14 Steven Degutis notifications@github.com wrote:

I'm not suggesting that as a name, but "incremental DOM updates" as a
clarifying phrase somewhere at the top of the README. I'm not sure a new
name is even necessary.

โ€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Polymer/lit-html/issues/950?email_source=notifications&email_token=AAAU55K6WYOYFE7E5GRCY5TP4EFJTA5CNFSM4H2U6UTKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYNYR6A#issuecomment-505121016,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAU55MBXDJ23R4HF4OHSP3P4EFJTANCNFSM4H2U6UTA
.

Looking at the README, we mention that lit-html only updates the parts of the DOM that changes, right up front.

I think I'll close this for now and chat with @arthurevans about how to phrase this more clearly in both places.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AndyOGo picture AndyOGo  ยท  3Comments

pjtatlow picture pjtatlow  ยท  3Comments

Christian24 picture Christian24  ยท  4Comments

pmkroeker picture pmkroeker  ยท  5Comments

pietmichal picture pietmichal  ยท  4Comments