0.0.0 • Published 4 years ago

h2o-transformation v0.0.0

Weekly downloads
1
License
MIT
Repository
github
Last release
4 years ago

h2o-transformation

h2o-tf

h20-transformation stands for HTML to Object Transformation.

For performance-oriented sites, where content is primarily, but not exclusively, HTML-based, it's useful to be able to take incoming HTML, and, preferably off the main thread, "hydrate" the UI.

Various approaches have been adopted to "hydrate" the HTML sent to the browser:

JQuery popularized this technique.

Many JQuery UI components add JS functionality on top of the primitive HTML sent to the browser by the server.

However, the further the functionality strays from what is natively supported in the browser, the less likely it will be that the library simply "enhances" the HTML.

The way React apparently does this is described here.. Kind of requires node (or a node plugin working inside another web server framework.)

When progressive enhancement of web components is combined with the PRPL pattern, the results seem to outperform SSR solutions, in a seemingly simpler and less confining way. Such techniques are compatible with all web server technologies. (Stencil may follow a slightly different approach, with very good results.)

But an interesting use case is when the light children of the web component can't practically be slotted in to the Shadow DOM of the Web Component.

The light children can still provide the initial, pertinent information to devices where JS is disabled, including some search engines. As the light children streams in, the browser can render the HTML.

But when we upgrade / enhance the unknown element to a known element, we want to extract out the data, and allow the upgraded element to access that data, in order to generate the rich UI experience.

If this is done in the slotchange event, it will typically require using the main thread to convert the HTML into a JS Object, that can form (part of) the "state" or the "view model".

This library endeavors to provide the opportunity to do the conversion from HTML to JS Objects, optionally outside the main thread in a (service) worker, and to store that state in IndexedDB rather than RAM memory (again optionally). And it strives to provide that support not only for the initial "index.html" load, where applicable, but also on subsequent loading of HTML fragments. The two disadvantages of doing the processing outside the main thread, is the HTML will need to be parsed twice -- once by the live DOM tree, once inside the service worker, and there's also a (small) cost marshalling the message across thread broundaries.

Outline of Solution

Service Worker: h2o-sw.js

If you have a main service worker that takes care of traditional PWA functionality, you can import this service (and other) service worker(s) using:

importScripts('./h2o-sw.js');

Listens for postMessages in one of two forms:

Initial, "server-rendered" Light Children Conversion Request

{
    "command": "h2o-transform",
    "message":{
        "html": "[ugly JSON-ified html]",
        "storageLocation": "IndexedDB", // or Session Storage or "Self"
        "storageDB": "myDB",
        "storageKey":"a.b.c",
        "rootType": "array",
        "transform":{
            "li": {
                "Type": "object",
                "Prop": "item",
                "div[data-type='whatever']":{
                    "Type": "object",
                    "Prop": "whatever"
                } 
            }
        } 
    } 
}

Message sent via web component:

<ul>
    <li data-my-prop="something">
        <div data-type="whatever">Hello</div>
</ul>
<h2o-lilies transform previousElementSibling storage-location=IndexedDB db=myDB storage-key=a.b.c ></h2o-lilies>

Subsequent HTML Fragment Fetch Requests

{
    "command": "h2o-intercept",
    "message":{
        "requestUrl": "https://mydomain.com/myResource/",
        "storage-location": "IndexedDB",
        "storageKey":"a.b.c",
        "rootType": "array",
        "transform":{
            "li": {
                "Type": "object",
                "Prop": "item",
                "div[data-type='whatever']":{
                    "Type": "object",
                    "Prop": "whatever"
                } 
            }
        } 
    } 
}

Message sent via web component:

<h2o-lilies transform href="..." storage-location=IndexedDB storage-key=a.b.c ></h2o-lilies>

The web component only posts messages to the service worker if the storage-location is either "IndexedDB" or "WorkerSelf". The possible values of storage-location are:

  1. IndexedDB
  2. WorkerSelf
  3. SessionStorage
  4. Local (ie stored as a property of the web component)