-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Hydration #649
[WIP] Hydration #649
Conversation
I'm very interested in this feature, anything I can help with? |
@PaulBGD testing 😀 Everything is quite dynamic at the moment so we'll probably just trip over each other if we're both working on the implementation in its current form, but we should have a reasonable first draft soon, at which point trying it out on existing apps will be very helpful |
Alright, I think this is basically ready. It's quite a big PR, and the code generation code is getting increasingly unkempt, but if anyone fancies giving it a once over I'd be grateful. I have hydration working on my local build of https://svelte.technology — it seems to render the guide a decent amount quicker (~55ms down from ~80ms, though these are very rough averages as there's a bit of variance and I couldn't be bothered to take notes and get the calculator out), but actually renders the REPL slightly slower (~12ms up from ~10ms). On balance I think this is probably a good change — am sure we can identify and remove that minor slowdown. A couple of caveats:
To use hydration, components must be compiled with As an aside, I'm more anxious than ever to come up with a neater approach to code generation, as it really is getting quite tricky to understand what's going on. All thoughts welcome as ever. |
@Rich-Harris extremely excited for this feature, thanks for all your work on it. I had a couple things I was thinking.
claim: function ( nodes ) {
h1 = nodes[0] || createElement( 'H1' );
var h1_nodes = children( h1 )
text = h1_nodes[0] || createText( "Hello world!" );
}, Would be a bit faster and perhaps more compact? Just a thought. |
The answers to 1 & 2 are linked — basically, we need to be able to handle cases where the DOM isn't in the state we expect. If we do this... h1 = nodes[0] || createElement( 'H1' ); ...and the HTML looks like this... <!-- here comes the h1! -->
<h1>Hello world!</h1> ...then {{#if loading}}
<p>loading, please wait</p>
{{else}}
<p>loaded, woo!</p>
{{/if}} // server
res.write(app.render({ loading: true }));
// client
new App({
target: document.body,
hydrate: true,
data: { loading: false }
}); So, to the first question —
— it depends what you mean by fail. If you had something like this... <h1>this is the wrong element</h1>
<h1>this is the right element</h1> ...then yes, it would claim the wrong element. But then it would repair the text node inside it and discard the second |
Ah yes, makes sense to me. Thanks for clearing both of those questions up. |
You're a wizard, Harris ✨ |
This is far, far, far from done, but I thought I may as well put it up here and try to articulate the approach I'm taking.
Essentially, each block gets
twothree new methods —create
,claim
andhydrate
.create
contains most of the stuff that previously went at the top of the block, whileclaim
contains basically the same code but 'claiming' chunks of existing DOM rather than creating new stuff:The
hydrate
method (if necessary) adds attributes, event listeners and so on.There are three new helper functions referenced here —
children
,claimElement
andclaimText
:So we begin as before, calling
create_main_fragment
, but then wehydrate
it with the array of nodes that comprise the children ofoptions.target
:Notice that we're not diffing in the conventional sense — we're simply grabbing the first node that seems like it might be the right one. This ought to handle most cases (DOM is empty, DOM is already in exactly the right state, DOM needs minor repairs, whether that means adding or removing nodes) pretty well, and only have negative performance implications in pathological situations that are easily avoided.
TODO:
hydrate
methods and associated helpers unless, say, the component is compiled withoptions.hydratable === true
)