-
-
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
Inefficient code created for hydration of static components #7226
Comments
I opened #2152 for this ages ago but it got closed at some point. |
Ah. And from there I see that @tanhauhau even had a PR at one point to implement the performance improvement: #4297 |
Yeah, which was opening the can of worms about hydration trusting that is starting HTML was accurate, which isn't something we can assume generally. There's definitely work to do here, but there's planning first. Will this be done in a compatible, opt-in way? Will it be a Svelte 4 thing? Will there be a way to tell the compiler to not trust certain bits of the DOM when hydrating? |
Recap of discussion earlier today: we could do this by changing the output of this... <div>
<p>some HTML</p>
</div> ...like so: /* App.svelte generated by Svelte v3.46.4 */
import {
SvelteComponent,
append_hydration,
children,
claim_element,
claim_text,
detach,
element,
init,
insert_hydration,
noop,
safe_not_equal,
text
} from "svelte/internal";
function create_fragment(ctx) {
let div;
let p;
let t;
const innerHTML = "some HTML";
return {
c() {
div = element("div");
- p = element("p");
- t = text("some HTML");
+ div.innerHTML = innerHTML;
},
l(nodes) {
div = claim_element(nodes, "DIV", {});
- var div_nodes = children(div);
- p = claim_element(div_nodes, "P", {});
- var p_nodes = children(p);
- t = claim_text(p_nodes, "some HTML");
- p_nodes.forEach(detach);
- div_nodes.forEach(detach);
},
m(target, anchor) {
insert_hydration(target, div, anchor);
append_hydration(div, p);
append_hydration(p, t);
},
p: noop,
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(div);
}
};
}
class App extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment, safe_not_equal, {});
}
}
export default App; (Note that the This assumes that the server and client renders match. In order for this to be a non-breaking change (and more generally, to deal with the possibility that they don't match), we could add a hash of the HTML during SSR so that it looks something like this... <div svelte:hash="xyz123">
<p>some HTML</p>
</div> ...and update the compiler output accordingly: l(nodes) {
div = claim_element(nodes, "DIV", {});
+ if (div.getAttribute('svelte:hash') !== 'xyz123') div.innerHTML = innerHTML;
|
The biggest impact I've seen is actually shipping the hydration code over the wire. We could simply check if the contents are equal directly and then do |
…nstead of deopt to claiming every nodes (#7426) Related: #7341, #7226 For purely static HTML, instead of walking the node tree and claiming every node/text etc, hydration now uses the same innerHTML optimization technique for hydration compared to normal create. It uses a new data-svelte-h attribute which is added upon server side rendering containing a hash (computed at build time), and then comparing that hash in the client to ensure it's the same node. If the hash is the same, the whole child content is expected to be the same. If the hash is different, the whole child content is replaced with innerHTML. --------- Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
In Svelte 5 we assume that the data is the same between SSR and hydration, and just skip over these. (We may eventually need a way to opt out of that, but for now it's filed under YAGNI.) In code size terms, hydration is a one-time cost in Svelte 5 (it doesn't add code per-component), and so I'm going to treat this as resolved |
Describe the bug
If there's a big block of static HTML or even the entire component is static, the Svelte compiler still creates a separate variable for every element when
hydratable: true
. Compare to whenhydratable: false
and it will just set the entire block withinnerHTML
. This results in worse time-to-interactive on blogs with large posts using MDSveX, which is a fairly common use case - though this example is a particularly large one.This is yet another reason we would benefit from something like
repair: false
: #780 (comment)Reproduction
https://svelte.dev/repl/a197647b669249f0a1d7a249b7c00044?version=3.46.4
Turn the
hydratable
flag totrue
and the output JS will have 10x as many lines. It both takes longer to transfer over the network and longer to run after it's been transferredLogs
No response
System Info
Severity
annoyance
The text was updated successfully, but these errors were encountered: