undom + preact headless active rendering
by amindunited
HTML
<script src="https://npmcdn.com/undom@latest"></script>
<script src="https://npmcdn.com/preact"></script>
<h2>HTML Serialization</h2>
<pre id="html"></pre>
<h2>JSON Serialization</h2>
<pre id="json"></pre>
CSS
pre {
tab-size: 2;
}
Babel + JSX
/** @jsx preact.h */
// set up _global_ mock document:
var document = undom();
window.document.createElement = document.createElement;
window.document.createTextNode = document.createTextNode;
window.Text = document.Text;
window.Element = document.Element;
console.log('window', window);
// DEMO: active rendering of preact components into an undom document:
/* class Demo extends preact.Component {
state = { time:Date.now() };
componentDidMount() {
setInterval(() => this.setState({ time:Date.now() }), 1000);
}
render({ }, { time }) {
return <div class="clock">{new Date(time).toTimeString()}</div>;
}
}
preact.render(<Demo />, document.body);
// every half second, show the current document tree:
setInterval( () => {
console.log(document.body);
window.document.getElementById('html').textContent = serializeHtml(document.body);
window.document.getElementById('json').textContent = JSON.stringify(serializeJson(document.body), null, ' ');
}, 500);
// serialize tree to pretty html
function serializeHtml(el) {
if (el.nodeType===3) return el.nodeValue;
var name = String(el.nodeName).toLowerCase(),
str = '<'+name,
hits = {},
c, i;
for (i=0; i<el.attributes.length; i++) {
hits[el.attributes[i].name] = true;
str += ' '+el.attributes[i].name+'="'+el.attributes[i].value+'"';
}
if (el.className && !hits.class) str += ' class="'+el.className+'"';
str += '>';
for (i=0; i<el.childNodes.length; i++) {
c = serializeHtml(el.childNodes[i]);
if (c) str += '\n\t'+c.replace(/\n/g,'\n\t');
}
return str + (c?'\n':'') + '</'+name+'>';
}
function enc(s) {
return s.replace(/[&'"<>]/g, function(a){ return `&#${a};` });
}
// serialize tree to json (objects)
function serializeJson(el) {
if (el.nodeType===3) return el.nodeValue;
var attributes = {},
a = el.attributes;
if (el.className) attributes.class = el.className;
for (let i=0; i<a.length; i++)...