The hyperHTML strength & experience without its complexity
npm install lighterhtmlSocial Media Photo by Kristine Weilert on Unsplash
!WebReflection status   !Blazing Fast
Please ask questions in the dedicated discussions repository, to help the community around this project grow ♥
---
The _hyperHTML_ strength & experience without its complexity 🎉
* faster than hyperHTML ⚡️
* simpler than lit-html 💡
* fueling both neverland and heresy 🔥
#### Looking for something even smaller?
If you want 90% of functionalities offered by lightetrhtml for 2/3rd of its size, check µhtml, which is also used in "micro custom elements" µce library, hence µce-template too, plus "micro land" µland 🦄
---
the new ?boolean=${value} syntax from µhtml has landed in lighterhtml too. Feel free to read this long discussion to better understand why* this syntax is better, or necessary.
---
Even if sharing 90% of _hyperHTML_'s code, this utility removed all the not strictly necessary parts from it, including:
* no Component, no define and/or intents, no connect or disconnect, and no promises (possibly in later on), everything these days can be easily handled by hooks, as example using the dom-augmentor utility
* html content is never implicit, since all you have to do is to write html before any template when you need it. However, the {html: string} is still accepted for extreme cases.
Removing these parts made the output smaller in size (less than 6K) but it also simplified some underlying logic.
Accordingly, _lighterhtml_ delivers raw domdiff and domtagger performance in an optimized way.
If you don't believe it, check the DBMonster benchmark 😉
In _lit-html_, the html function tag is worthless, if used without its render.
In _lighterhtml_ though, the html.node or svg.node tag, can be used in the wild to create any, one-off, real DOM, as shown in this pen.
``jshtml
// lighterhtml: import the tag and use it right away
import {html} from '//unpkg.com/lighterhtml?module';
// a one off, safe, runtime list 👍
const list = ['some', 'nasty', 'list'];
document.body.appendChild(html.node
- ${text}
)});
`Strawberry on top, when the
html or svg tag is used through _lighterhtml_ render, it automatically creates all the keyed performance you'd expect from _hyperHTML_ wires, without needing to manually address any reference: pain point? defeated! 🍾$3
If you are looking for Custom Elements like events out of the box, lighterhtml-plus is your next stop 👍
$3
Following, the usual multi import pattern behind every project of mine:
* via global
lighterhtml CDN utility: , and const {render, html, svg} = lighterhtml
* via ESM CDN module: import {render, html, svg} from 'https://unpkg.com/lighterhtml?module'
* via ESM bundler: import {render, html, svg} from 'lighterhtml'
* via CJS module: const {render, html, svg} = require('lighterhtml')
$3
The module exports the following:
*
html tag function to create any sort of HTML content when used within a render call. It carries two extra utilities, html.for(ref[, id]), to hard-reference a specific node, and html.node to create one-off dom nodes in the wild without using the render.
* svg tag function to create any sort of SVG content when used within a render call. It carries two extra utilities, svg.for(ref[, id]), to hard-reference a specific node, and svg.node to create one-off dom nodes in the wild without using the render.
* render(node, fn|Hole) to pollute a node with whatever is returned from the fn parameters, including html or svg tagged layout
* Hole class for 3rd parts (internal use)You can test live a
hook example in this Code Pen.
$3
* the wired content is not strongly referenced as it is for
hyperHTML.wire(ref[, type:id]) unless you explicitly ask for it via html.for(ref[, id]) or svg.for(ref[, id]), where in both cases, the id doesn't need any colon to be unique. This creates content hard wired whenever it's needed.
* the ref=${object} attribute works same as React, you pass an object via const obj = useRef(null) and you'll have obj.current on any effect. If a callback is passed instead, the callback will receive the node right away, same way React ref does.
* if the attribute name is aria, as in aria=${object}, aria attributes are applied to the node, including the role one.
* _deprecated_: if the attribute name is data, as in data=${object}, the node.dataset gets populated with all values.
* if the attribute name is .dataset, as in .dataset=${object}, the node.dataset gets populated with all values.
* intents, hence define, are not implemented. Most tasks can be achieved via hooks.
* promises are not in neither. You can update asynchronously anything via hooks or via custom element forced updates.
* the onconnected and ondisconnected special events are available only in _lighterhtml-plus_. These might come back in the future but right now _dom-augmentor_ replaces these via useEffect(callback, []). Please note the empty array as second argument.
* an array of functions will be called automatically, like functions are already called when found in the wild
* the Component can be easily replaced with hooks or automatic keyed renders
* if a listener is an Array such as [listener, {once: true}], the second entry of the array will be used as option.`js
const {render, html} = lighterhtml;// all it takes to have components with lighterhtml
const Comp = name => html
Hello ${name}!
;// for demo purpose, check in console keyed updates
// meaning you won't see a single change per second
setInterval(
greetings,
1000,
[
'Arianna',
'Luca',
'Isa'
]
);
function greetings(users) {
render(document.body, html
${users.map(Comp)});
}
`$3
Excluding the already mentioned removed parts, everything else within the template literal works as described in hyperHTML documentation.
$3
Live on Code Pen.
`js
import {render, html} from '//unpkg.com/lighterhtml?module';document.body.appendChild(
// as unkeyed one-off content, right away 🎉
html.node
any one-off content!
);// as automatically rendered wired content 🤯
todo(document.body.lastChild);
function todo(node, items = []) {
render(node, html
- ${what}
));
function add() {
items.push(prompt('do'));
todo(node, items);
}
function remove(e) {
items.splice(e.currentTarget.dataset.i, 1);
todo(node, items);
}
}
`
$3
You got 'em, just bind
render arguments once and update the element content whenever you feel like.Compatible with the node itself, or its shadow root, either opened or closed.
`js
const {render, html} = lighterhtml;customElements.define('my-ce', class extends HTMLElement {
constructor() {
super();
this.state = {yup: 0, nope: 0};
this.render = render.bind(
null,
// used as target node
// it could either be the node itself
// or its shadow root, even a closed one
this.attachShadow({mode: 'closed'}),
// the update callback
this.render.bind(this)
);
// first render
this.render();
}
render() {
const {yup, nope} = this.state;
return html
;
}
handleEvent(event) {
thison${event.type};
}
onclick(event) {
event.preventDefault();
const {key} = event.currentTarget.dataset;
this.state[key]++;
this.render();
}
});
`
$3
Born at the beginning of 2017, _hyperHTML_ matured so much that no crucial bugs have appeared for a very long time.
It has also been used in production to deliver HyperHTMLElement components to ~100M users, or to show W3C specifications, so that in case of bugs, _hyperHTML_ will most likely be on the fast lane for bug fixes, and _lighterhtml_ will eventually follow, whenever it's needed.
On top of this, most modules used in _lighterhtml_ are also part of _hyperHTML_ core, and the ./tagger.js file is mostly a copy and paste of the _hyperHTML_ ./objects/Update.js one.
However, as tech and software evolve, I wanted to see if squashing together everything I know about template literals, thanks to _hyperHTML_ development, and everything I've recently learned about hooks, could've been merged together to deliver the easiest way ever to declare any non-virtual DOM view on the Web.
And this is what _lighterhtml_ is about, an attempt to simplify to the extreme the
.bind(...) and .wire(...) concept of _hyperHTML_, through a package that requires pretty much zero knowledge about those internals._lighterhtml_ is also relatively new, so that some disabled functionality might come back, or slightly change, but if you like the idea, and you have tested it works for your project, feel free to ditch _hyperHTML_ in favor of _lighterhtml_, so that you can help maturing this project too.
$3
_µhtml_ is a great way to start playing around with most _lighterhtml_ features. As it's simply a subset, you can eventually switch to lighterhtml later on, whenever you miss, or need, some extra feature.
For a complete comparison of features and libraries around my repositories, please have a look at this gist.
- - -
History and changes
This session covers all major breaking changes and added features.
$3
I am afraid this major was necessary due recent bugs/discoveries that made me rethink some practice and patch.
* the recently introduced
data helper could conflict with some node such as