Open jridgewell opened 9 years ago
Isn't the element returned on close
not open?
I like the basic concept here, it'd be cool to explore
Isn't the element returned on close not open?
The Element is returned from both.
How far is this from reality?
Maybe a weekend's worth of hacking. We already have a lot of information about what is constant and what changes from JSX's own semantics.
I'm working on static hosting first, though.
Edit: see https://github.com/babel-plugins/babel-plugin-incremental-dom/issues/11#issuecomment-155489607.
Hmm, blocked until https://github.com/google/incremental-dom/pull/132 is merged. If any element in the top-level of the render isn't constant, I won't have a reference node to patch up:
function render(data) {
return <div id={data.id} />;
};
// - - -
// Would have to translate to something like
function render(data) {
var elements = render.elements = [];
elements.push(elementVoid("div", null, null, "id", data.id));
return elements[0];
}
render.secondRender = function(data) {
// We can't already be in a `patch`, since that would wipe out everything.
// So we have to call patch a bunch of times.
patch(getCurrentElement(), render, data);
return render.elements[0];
};
Specifically with top-level elements, I won't have the current container (or be able to generate one with an elementOpen
), so I'll need iDOM to give it to me.
iDOM just added skip
, which allows you to skip the clearing of unvisited child nodes. Tied together with getCurrentElement
, this works pretty handily to solve a second problem with my example. Namely, even if I were to get the top-level container element and patch it, it would still have it's children cleared by the original patch.
// Top level change
function render(data) {
return <div id={data.id} />;
};
// - - -
function render(data) {
return elementVoid("div", null, null, "id", data.id);
}
render.secondRender = function(data) {
return render(data);
};
patch(container, render, data);
// Later, repatch
patch(container, render.secondRender, data);
Patching a subelement:
function render(data) {
return <div>
<div id={data.id} />
</div>;
};
// - - -
// Translates to something like
function render(data) {
var elements = render.elements = [];
elements.push(elementOpen("div"));
elementVoid("div", null, null, "id", data.id);
elementClose('div');
return elements[0];
}
render.secondRender = function(data) {
patch(render.elements[0], (data) => {
elementVoid("div", null, null, "id", data.id);
}, data);
// Use skip to prevent clearing from outer patch context,
// since `secondRender` was called like so:
// patch(container, render.secondRender, data)
skip();
return render.elements[0];
};
patch(container, render, data);
// Later, repatch
patch(container, render.secondRender, data);
Is this still in the plans?
I so... I've been experimenting with this transform with web components, and this kind of optimization would be very useful where shadow roots often have large <style>
tags amongst other static beginning and end sections, as well as often having nested static sections around <slot>
s.
Still stuck waiting for better iDOM support. I had a working implementation of this, but it was actually slower than doing the total diff due to multiple patch
calls.
ok, thanks for the update!
After https://github.com/babel-plugins/babel-plugin-incremental-dom/pull/10 lands, we can shamelessly rip off Glimmer's rendering engine.
First, the naive approach (that we're currently doing) is to diff everything:
In essence, we'll diff the
<div>
, the<span>
, the span's content, the<ul>
and the ul's content. But, we can do a bit better using Glimmer's approach.Essentially, we only ever need to patch the
<span>
and<ul>
on second renders:This can pay off immensely for static renders or deeply nested views: