Search code examples
hyperhtml

How do you get around Cloned Templates losing Element References?


I noticed that hyperHTML preserves references I make to elements:

let div = document.createElement("div");
div.textContent = "Before Update";
hyperHTML.bind(document.body)`static1 - ${div} - static2`;
div.textContent = "After Update";

Above will produce a page that says:

static1 - After Update - static2

It is my understanding that hyperHTML ultimately clones an HTML <tempate> element to render the final output. However, don't you typical lose references when cloning an HTML template (like the variable "div" in the example above)?

Therefore, on the initial render, does hyperHTML somehow replace cloned elements with their originals after cloning the HTML template?

Here's how I think it works:

  1. Create an HTML Template of the original template literal while replacing all interpolations with comments.
  2. Clone the html template with comments left in.
  3. Make elements or document fragments out of each interpolation originally recieved
  4. Replace each comment in the clone with its processed interpolation.

Is this correct?


Solution

  • I am not sure what is the question here, but there is a documentation page, and various examples too to understand how to use hyperHTML, which is not exactly in the way you are using it.

    In fact, there's no need to have any reference there because hyperHTML is declarative, so you'd rather write:

    function update(text) {
      var render = hyperHTML.bind(document.body);
      render`static1 - <div>${text}</div> - static2`;
    }
    

    and call update("any text") any time you need.

    Here's how I think it works ... Is this correct?

    No, it's not. hyperHTML doesn't clone anything the way you described, it associates once per unique template tag a sanitized version to the output and finds out all interpolated holes in it.

    The part of the library that does this is called domtagger, and the mapping per template literal is based on the standard fact that these are unique per scope:

    const templates = [];
    function addTemplate(template, value) {
      templates.push(template);
      return template.join(value);
    }
    function asTemplate(value) {
      return addTemplate`number ${value}!`;
    }
    asTemplate(1);
    asTemplate(2);
    asTemplate(Math.random());
    templates[0] === templates[1]; // true
    templates[1] === templates[2]; // true
    // it is always the same template object!
    

    After that, any other element using once that very same tag template will have a clone of that fragment with a map to find holes once and some complex logic to avoid replacing anything that's already known, being that text, attributes, events, or any other kind of node.

    hyperHTML never removes comments, it uses these as pin and then uses domdiff to eventually update nodes related to these pins whenever there's a need to update anything.

    Domdiff is a vDOM-less implementation of the petit-dom algorithm, which in turns is based on E.W Myers' "An O(ND) Difference Algorithm and Its Variations" paper.

    Whenever you have DOM nodes in the holes, hyperHTML understand that and fill these holes with those nodes. If you pass repeatedly the same node, hyperHTML won't do anything 'cause it's full of algorithm and smart decisions, all described in the documentation, to obtain best performance out of its abstraction.

    All these things, and much more, normalized for any browser out there, makes hyperHTML weight roughly 7K once minified and gzipped, bit it also offers:

    • Custom Elements like hooks through onconnected/disconnected listeners
    • lightweight components through hyperHTML.Component
    • SVG manipulation as content or via wire
    • easy Custom Elements definition through HyperHTMLElement class

    As summary, if you need these simplifications and you don't want to reinvent the wheel, I suggest you give it a better try.

    If you instead are just trying to understand how it works, there's no need to assume anything because the project is fully open source.

    So far, all I've read from your questions here and there, is that you just believe to understand how it works so I hope in this reply I've put together all the missing pieces you need to fully understand it.

    Do you want to write your own lit/hyperHTML library? Go ahead, feel free to use the domtagger or the domdiff library too, few others are already doing the same.