kit icon indicating copy to clipboard operation
kit copied to clipboard

Partial hydration

Open kevmodrome opened this issue 3 years ago • 35 comments

Unsure if this should go here or in an RFC. I'll start here, but write a proper RFC if the scope is too big for a regular issue.

With the somewhat recent feature of disabling JS completely on pages it would be nice to selectively add sprinkles of JS around the page for some progressive enhancement.

Describe the solution you'd like Svelte's action directive could work very well for this as. I briefly mentioned the idea to @pngwn and he mentioned that the life cycle hooks/methods wouldn't be usable (as we don't know when something is updated or destroyed. I think for a first version this would be fine - we would simply ignore the update and destroy functions. I don't this would be a big loss since you would lose the context of the page if you navigate away from it anyway, I think (or can you disabled JS but have the router still be enabled?).

Describe alternatives you've considered An alternative way of doing this would be how Elder.js does it - a preprocessor that looks through your pages and finds any that are marked with some prop (sveltekit:partial?) and bundles that separately, injects that in some intersectionObserver solution. This would allow the usage of full components.

How important is this feature to you? I can live without it, but partial hydration is 👌 and would give us a nice and easy way to enhance our static pages with whimsy and excitement! 👏

kevmodrome avatar May 09 '21 16:05 kevmodrome

or can you disabled JS but have the router still be enabled?

You can indeed do this. So we would at least need to do some cleanup. A router navigation event would probably be a good moment to clean up existing actions in the context of a static page.

I think this is an obvious request and one we are bound to get sooner or later. Very few people will want zero javascript but many would like just the tiniest amount.

The problem is that kit would have to parse the component to support something along these lines, a territory that firmly belongs to svelte.

I almost feel like this would make more sense as a 'mode' of the svelte compiler.

Obviously, the real solution to this is to support partial hydration. I don't know if this feature request would be a reasonable half measure or if efforts are better invested in exploring partial hydration in its entirety.

pngwn avatar May 09 '21 18:05 pngwn

Partial hydration is basically solving a performance issue by helping users get smaller bundles and faster code execution. There's several open issues around improving Svelte performance. I think it'd be interesting to see how far we can get without partial hydration as I expect we can get pretty phenomenal performance without having to decide on API changes which would take more effort to agree on.

Probably the most impactful would be to improve Svelte's hydration implementation to be more performant (https://github.com/sveltejs/svelte/issues/4308). There was an optimization added in Svelte 3.38.0 that was reverted in Svelte 3.38.2 due to a bug. I'd hope that there's a path to getting that optimization checked back in without the bug present since the original approach was agreed upon and there's been a unit test added for the bug. I just commented there suggesting a potential solution. The optimization moved the Google Page Speed score for my site from 92 to 99, so I think at least for some cases that would be a very meaningful improvement that wouldn't require any API changes.

Finally, while it's not related to hydration at all, there are a couple open performance-related PRs and Rich's SSR PR improves SSR performance by 2-3x and is pretty close to being able to be checked in.

benmccann avatar May 10 '21 22:05 benmccann

I'm all for the performance improvements in Svelte but if my content is mostly static Svelte will never come close to some selective enhancement with JS, regardless of how good the hydration performance gets because in those case it is doing unnecessary work.

I think since the static and router less options exist in svelte kit, this is a request we will get more and more. A blog, for example, is probably mostly static but users might want a pop out menu. And they might want to write that code in svelte, which is understandable. No performance improvement in svelte is going to make treating all of that static content as some thing to be hydrated even in cases where Svelte optimises the code by setting inner html, having static html as strings in JS when it is unnecessary is a bad idea.

I'm not saying this proposal is the correct way of doing it, but I don't think avoiding some kind of selective hydration is really a solution either.

pngwn avatar May 11 '21 00:05 pngwn

Just as a note for the use:action directive. This was the bug I hit with regards to implementing it on Elder.js. https://github.com/sveltejs/language-tools/issues/339

This could be solved if it was an official svelte directive though.

nickreese avatar May 11 '21 15:05 nickreese

I'm pleased to see a growing interest in partial Hydration for Progressively Enhanced SSG content. AstroJS and petite-vue are the newest 'frameworks' exploring this. The term 'island architecture' seem to be growing in usage for this; ie there's no top-level app component

I recently explored using 11ty and AlpineJS in an interactive music Journal.

I'd personally love a svelte PH solution for a project targetting users in parts of Africa where connectivity is poor and older devices are used.

SteveALee avatar Jul 15 '21 16:07 SteveALee

The term 'island architecture' seem to be growing in usage for this

nice, I like that term.

I have server rendered pages right now with a single very simple interactive component. Would love to be able to load only that specific tiny interactive JS in the client, instead of the entire page + metadata.

Madd0g avatar Nov 10 '21 06:11 Madd0g

I'm not saying this proposal is the correct way of doing it, but I don't think avoiding some kind of selective hydration is really a solution either.

Watching the developments in this space, it's pretty obvious that partial hydration/islands architecture is going to set the new standard in terms of performance.

Where as Astro starts with this as a foundation and is working their way up to a more comprehensive framework by developing dynamic component SSR, React is taking a retrofit approach with Server Components.

Shipping the least amount of JS possible to the client seems like a forgone conclusion. Which ever framework (whether existing or new) can best marry this with the declarative component architecture that's come to dominate developer's mental model, will win in the long run IMO—I hope it's obvious in what sense I mean "win".

Of all the frameworks I've worked with, I find Svelte to be the most intuitive and enjoyable, but I wouldn't hesitate to migrate to another framework for the not insignificant performance gains afforded by this. I'd say it's almost obligatory for competitive e-commerce sites to prioritize this over developer experience.

I'm curious if there are any priority updates, especially now that Svelte has backing from Vercel:

image

theurgi avatar Jan 24 '22 04:01 theurgi

Partial hydration would be a great improvement to have, but a lot of the other performance enhancements you get from SvelteKit are even more impactful. Put a site built with SvelteKit into Google's https://pagespeed.web.dev/. You'll get a perfect score or close to it. Now put in one built with the island architecture - I bet it won't beat SvelteKit. There's clearly room for Svelte to adopt these sorts of improvements, but before you choose something just because it has partial hydration, I'd recommend considering the overall performance. There's a lot more that affects performance and I rarely see anything beat out SvelteKit in the wild

Screenshot from 2022-01-23 20-45-16

benmccann avatar Jan 24 '22 04:01 benmccann

I suppose that answers my main question in regards to where Svelte is currently at, but...

Now put in one built with the island architecture - I bet it won't beat SvelteKit.

Well, most recently, I read this: SvelteKit vs. Astro

I fully agree with consulting actual metrics over buzzwords and in this particular case the performance gain of Astro is probably negligible for most applications. Based on this alone, I'd even prefer SvelteKit because Astro currently has some limitations where it's hard to determine whether or not they'd present a costly or even impassible challenge deeper into the development cycle.

But if I need to commit to a framework for a large scale application (and I do) and performance is a top priority, and to migrate frameworks down to road is not really an option—this remains a relevant question for me especially considering the way Svelte apps scale horizontally (you know, the whole inflection point thing: JavaScript Framework TodoMVC Size Comparison).

My assumption is that selective hydration would buy Svelte a significant amount of headroom with, if not completely solve, its horizontal scaling issue.

I was hoping that, now that Rich rubs shoulders with all the Vercel engineers who live on the bleeding edge of React, they would convince him of this magic. I wan't to choose Svelte, but all things considered I may have to take my chances with React/Preact.😔

theurgi avatar Jan 24 '22 05:01 theurgi

I was also hoping that svelte would support partial hydration.

I think now I would watch either Marko or Qwik

Sveltekit might be really fast, but when I am developing something which has lots of content, and little interactivity, I prefer a framework which will just send the html as is without also sending the code to render it and the data again in the js. I understand it is a subjective opinion, but I think the web would be a better place without all the unnecessary javascript being sent with everything.

amardeep avatar Jan 24 '22 14:01 amardeep

@amardeep I'm with you totally as the best approach. I recently used 11ty and alpine for such an approach (https://musicpracticetools.net/)

The advantage about being explicit is it keeps Progressive Enhancement in mind.

However, last time I looked at the code Svelte generated (probably back when v3.0 launched) it generates the minimum dynamic content through javascript and deploys a minimal 'framework' runtime payload.

In other words, Svelte is very close to an implicit automatic island architecture. I assume Sveltekit builds on this; it does let you specify completely staic on a per route basis.

I may be wrong though.

SteveALee avatar Jan 24 '22 14:01 SteveALee

@SteveALee

However, last time I looked at the code Svelte generated (probably back when v3.0 launched) it generates the minimum dynamic content through javascript and deploys a minimal 'framework' runtime payload.

I was also curious about whether Svelte compiler could optimize static components but unfortunately it seems that the entire DOM is still present in the JavaScript bundle.

I spun up a new SvelteKit site with the following index component:

<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation!</p>

I then built it via @sveltejs/adapter-node and ran the resulting build.

An index.svelte-xxx.js chunk was served that contained this:

import {S as K, i as y, s as V, e as v, t as c, k as W, c as u, a as _, h, d as l, m as b, b as j, g as k, J as o, K as x} from "../chunks/vendor-f0095a1c.js";
function q(E) {
    let e, d, r, a, m, s, f, p;
    return {
        c() {
            e = v("h1"),
            d = c("Welcome to SvelteKit"),
            r = W(),
            a = v("p"),
            m = c("Visit "),
            s = v("a"),
            f = c("kit.svelte.dev"),
            p = c(" to read the documentation!"),
            this.h()
        },
        l(t) {
            e = u(t, "H1", {});
            var i = _(e);
            d = h(i, "Welcome to SvelteKit"),
            i.forEach(l),
            r = b(t),
            a = u(t, "P", {});
            var n = _(a);
            m = h(n, "Visit "),
            s = u(n, "A", {
                href: !0
            });
            var S = _(s);
            f = h(S, "kit.svelte.dev"),
            S.forEach(l),
            p = h(n, " to read the documentation!"),
            n.forEach(l),
            this.h()
        },
        h() {
            j(s, "href", "https://kit.svelte.dev")
        },

So unfortunately, Svelte can't currently optimize away even simple cases like this where there is no interactivity - everything gets sent twice over the wire, first as HTML and then as JS.

khromov avatar Jan 24 '22 16:01 khromov

So unfortunately, Svelte can't currently optimize away even simple cases like this where there is no interactivity - everything gets sent twice over the wire, first as HTML and then as JS.

Not true. If you set both hydrate and router to false, no JavaScript will be created for that page. See the docs for more info.

dummdidumm avatar Jan 24 '22 16:01 dummdidumm

The TodoMVC and Vue articles are both extremely misleading and inaccurate because they ignore code splitting. E.g. the TodoMVC article says when you have an application five times the size of TodoMVC then you'll start to get worse performance with Svelte. But SvelteKit loads only the JS necessary for a page - not the entire application's JS. So really you would need a single page that is larger than five applications. I've never seen a real application get anywhere even close to that. Those articles were both written by people promoting other frameworks and, while I respect the authors, they lead to such wildly inaccurate and biased conclusions

I do agree partial hydration would be a nice enhancement and it's something we'll add one day, but having it will probably add about one point to your Google Page Speed Score (it'd be hard for it to do better since most apps are already scoring around 99-100). Meanwhile, nearly every virtual DOM application I've seen scores in the 60s or 70s. If you added partial hydration to these apps most of them would be nowhere close to performing as well as a SvelteKit app, so it really is important to look at the whole picture

Svelte absolutely does send unnecessary JS over the wire today. But in practice, it still sends far less unnecessary code than almost everything else out there including most island architectures. We would like to improve hydration, but we also want to take our time to do it right because this is a feature that will probably be implemented at least partially in Svelte core and won't be easy to change once it's been released. We'll likely consider it post SvelteKit 1.0 as focus shifts back to Svelte core. And if you're already on SvelteKit you will one day get those improvements for very little additional work

benmccann avatar Jan 24 '22 16:01 benmccann

@benmccann

Meanwhile, nearly every virtual DOM application I've seen scores in the 60s or 70s.

All of the popular frameworks use VDOMs. Inexperienced devs gravitate to them and bloat their code with npm-based-development. It's not hard to find performant VDOM apps. For example, despite using one of the more bloated VDOM libraries (React), this Remix demo is far above 60s and 70s.

Now put in one built with the island architecture - I bet it won't beat SvelteKit.

The TodoMVC and Vue articles are both extremely misleading and inaccurate because they ignore code splitting. E.g. the TodoMVC article says when you have an application five times the size of TodoMVC then you'll start to get worse performance with Svelte. But SvelteKit loads only the JS necessary for a page - not the entire application's JS.

I've been investigating frameworks for making a blog. Making a blog with small interactive elements changes this performance calculus.

As a quick and dirty benchmark I made a long blogpost with a single interactive Counter component with Sveltekit + MDSveX, Astro, and Iles. (Slinkity would also be nice to test, but I didn't). These sites aren't purely identical but it should be good enough. Lmk if I made any mistakes.

Result: they all get 100 in performance with Lighthouse. Great! Let's look closer. For the Counter component, Iles loads the Vue runtime and Astro loads the Preact runtime. Let's see how much JS is sent by each of these. For reference, in all these cases the HTML file is approx 70KB uncompressed, 10KB gzipped.

Framework uncompressed JS (KB) gzipped JS (KB)
Sveltekit+MDSveX 268KB 54KB
Astro 12KB 6KB
Iles 53KB 22KB

Sveltekit+MDSveX is sending 22x more JS than Astro. With gzip it's fortunately only 9x as much. That Sveltekit+MDSveX is on par here is impressive. The work done on optimizing the SSR has paid off, apparently https://github.com/sveltejs/svelte/pull/6204, https://github.com/sveltejs/svelte/pull/6395 But, well-optimized waste is still waste. I think this is what @pngwn was expressing above. Note, this only gets worse the longer the blogpost. I would like to test this further with longer posts, but because of long-outstanding bugs https://github.com/pngwn/MDsveX/issues/358 https://github.com/sveltejs/svelte/issues/4694 Svelte doesn't afford blogposts any longer.

How realistic is the benchmark? Well, IME most dev blog posts are a few paragraphs long. So, maybe this won't be a problem for most users. What about people who do write long posts?

Let's see

Article Word count # DOM elements uncompressed HTML (KB) gzipped HTML (KB)
Benchmark 7893 899 70 10
Gwern article 69.3k 17.5k 1300 321
SSC article (removed comments*) 33k 3.3k 331 97
SSC article (comments in-tact) 135k 15.5k 1600 340

*I remove the eagerly-loaded comments. They comprise most of the page, so removing them simulates 'just blogpost'.

Should these authors just "code split" their longer blog posts? Maybe. If that Gwern article were ported over to Sveltekit+MDSveX I estimate the JS to hydrate would be around 2MB-4MB, uncompressed. In that case, how much would performance degrade as a result of downloading, parsing, and executing all of that JS versus downloading, parsing, and painting all of that HTML? I'm not sure. How would it fare versus Iles and Astro? If it weren't for the aforementioned bugs I would try to estimate that.

Since these performance issues only come up at very long post length, and I would like to use clientside routing with animated transitions, I'll probably move forward with Sveltekit+MDSveX. But, just wanted to lay out my findings here. I agree with the assessment that partial hydration can be considered a future "nice to have", but it's not because Svelte is blowing out the competition already.

deklanw avatar Jan 28 '22 19:01 deklanw

Thanks these are useful stats! To be clear, I agree that we should add partial hydration. I just want to be upfront that I don't know that there's a whole lot that will change how it's prioritized because our current thinking is that it'd depend on changes to Svelte core and we want to get Kit 1.0 out the door before shifting focus back to the Svelte internals. For anyone who's interested in seeing partial hydration, probably the best way to help make that happen is to help with Kit 1.0 :wink:

this Remix demo is far above 60s and 70s.

I got 72, 90, 89, 84, 66 when I tested it: https://pagespeed.web.dev/report?url=https%3A%2F%2Fremix-ecommerce.fly.dev%2Fen%2Fsearch%3Fcategory%3Dcharacters

That averages out a 80. Certainly an improvement over most React sites, but still quite a bit below most SvelteKit sites I've seen - though obviously we don't have a 1:1 comparison

because of long-outstanding bugs pngwn/MDsveX#358 sveltejs/svelte#4694 Svelte doesn't afford blogposts any longer.

Oof. This seems like the first thing we should fix. It looks like there's a PR open for it: https://github.com/Rich-Harris/code-red/pull/64

benmccann avatar Jan 29 '22 00:01 benmccann

Thanks these are useful stats! To be clear, I agree that we should add partial hydration. I just want to be upfront that I don't know that there's a whole lot that will change how it's prioritized because our current thinking is that it'd depend on changes to Svelte core and we want to get Kit 1.0 out the door before shifting focus back to the Svelte internals. For anyone who's interested in seeing partial hydration, probably the best way to help make that happen is to help with Kit 1.0 😉

Fair. Partial hydration is non-trivial for full SPAs. Just wanted to share my findings and make the case for real-world relevance. Hope to see Kit 1.0 soon! I may try to contribute 🙂

I got 72, 90, 89, 84, 66 when I tested it: https://pagespeed.web.dev/report?url=https%3A%2F%2Fremix-ecommerce.fly.dev%2Fen%2Fsearch%3Fcategory%3Dcharacters

That's curious. Ran using the site you gave five times and got: 94, 92, 94, 91, 89. I'm never getting anything as low as you got. And, when I run Lighthouse locally I get 99 everytime. That site seems to be a frontend for Lighthouse, so 🤷‍♂️

Oof. This seems like the first thing we should fix. It looks like there's a PR open for it:

Yeah, I saw. Also outstanding for months, unfortunately. Hope it's fixed soon so I can do some more testing

deklanw avatar Jan 29 '22 00:01 deklanw

@deklanw that issue is hopefully fixed now with the release of Svelte 3.46.4. Would you be able to give it another try and check if it works now? Thanks for alerting us to it. code-red rarely needs any changes, so it's easy to overlook PRs in that repo.

benmccann avatar Feb 03 '22 18:02 benmccann

@benmccann Yep, works now! Nice work.

Scaled up the benchmark I did above and put the code and results in a repo. I found out the answer to the question I posed above: no, the performance degradation caused by large HTML files doesn't drown out the performance degradation of SvelteKit's hydration. For the longest blogpost in my testing (with Lighthouse) SvelteKit gets 53, Astro gets 80, and Iles gets 78. The TTI degrades in SvelteKit's case.

deklanw avatar Feb 04 '22 19:02 deklanw

Thanks for sharing your findings @deklanw.

The actual page load as a user seeing contents isn't much different for me between the three implementations. Some people I shared this with are reporting SvelteKit actually looks faster for them

Rich pointed out the preload directive is broken on the SvelteKit example (https://github.com/deklanw/interactive-blogs-benchmark/pull/1), so fixing that might improve things in SvelteKit's favor a fair amount. It won't help the Lighthouse score, but will make things look a lot faster to users, which is the more important thing

https://github.com/sveltejs/svelte/issues/3898 would also improve performance a fair amount in this example, but the draft branch a community member made for it is probably too complicated to get into Svelte 3. https://github.com/sveltejs/svelte/issues/2374 and https://github.com/sveltejs/svelte/issues/3760 are similar suggestions

benmccann avatar Feb 04 '22 23:02 benmccann

The actual page load as a user seeing contents isn't much different for me between the three implementations. Some people I shared this with are reporting SvelteKit actually looks faster for them

That's true. I agreed in the README that TTI for an interactive blogpost probably doesn't matter. As long as FP/LCP are on par (they are) then it's fine. By the time the user scrolls down to the data viz or whatever it should be interactive.

Thanks for the PR correction. I was focusing on top-level loads because those seem appropriate for blog posts. Haven't tested hydrated page transitioning at all.

I'll check out those optimization PRs you linked. Thanks! I hope the benchmark can be useful in the future if some of those optimizations (or full partial hydration) are implemented.

deklanw avatar Feb 05 '22 01:02 deklanw

Yeah, the benchmark is helpful. I've been looking deeper and it seems that, with or without partial hydration, there's another opportunity for improvement that the benchmark has uncovered. I filed a new issue for it. Unfortunately, I'm not that familiar with the internals of Svelte core, so I wouldn't be able to look at it myself. My initial thought is that it seems like something relatively fixable in Svelte 3 if anyone is interested in taking a look at it. I imagine that the time-to-interactive should be able to be made way faster for this example

benmccann avatar Feb 05 '22 03:02 benmccann

@benmccann

The TodoMVC and Vue articles are both extremely misleading and inaccurate because they ignore code splitting. E.g. the TodoMVC article says when you have an application five times the size of TodoMVC then you'll start to get worse performance with Svelte. But SvelteKit loads only the JS necessary for a page - not the entire application's JS. So really you would need a single page that is larger than five applications. I've never seen a real application get anywhere even close to that. Those articles were both written by people promoting other frameworks and, while I respect the authors, they lead to such wildly inaccurate and biased conclusions

The testing method is limited as multiplying an already zipped output reduces the effectiveness of compression and not all code is created equal, not all things are components etc... So there is truth in your concerns, but the scale isn't quite right. What's 5 TodoMVCs + single vendor bundle? ~10kb of js min-zipped. I'm sure you've encountered larger initial page loads. I mean Svelte's Hackernews Demo is initial page load is larger than that and it does basically nothing. When put in that perspective the article covers a mostly reasonable range even considering code splitting.

It's up to you how you want to spin it. But the suggestion this is about promotion is too convenient. I did work to make sure that Preact and React were properly depicted because their official TodoMVCs were bloated. And Preact was the "winner" if there was one. I'm never afraid to include things that would make my framework not look the best, that's how we grow.

Put a site built with SvelteKit into Google's https://pagespeed.web.dev/. You'll get a perfect score or close to it. Now put in one built with the island architecture - I bet it won't beat SvelteKit.

Also, since I'm here. I take this bet. It isn't hard to make examples that showcase this. Again I'm not trying to push some feature Solid has. We don't. But I don't gain anything from not being upfront with it. Better than seen as misleading later.

But to be fair I am not as familiar with SvelteKit as I should be. Can't ever say anything with certainty. So I will remedy this. I think this project will be my next source of focus. Thanks for the inspiration.

ryansolid avatar Mar 06 '22 05:03 ryansolid

Benchmarks

I don't think that you can ignore code splitting and other performance nuances and get a realworld understanding of performance. Looking at performance on a per-page basis is a lot more meaningful in my opinion. I really like @deklanw's demo project as one to focus on because it's the first one I've seen that demonstrates Svelte having meaningfully worse performance on a single page. With that demo we have a good example that's enough for us to make measurable progress, so I don't know if we need to get bogged down on discussing the merits of other performance benchmarks

Hydration background

Svelte does hydration differently than React and other frameworks. Svelte "repairs" the DOM to ensure that the client-side DOM matches what is expected. E.g. if you rendered a date with a timezone, in Svelte it will update that date on the client whereas React won't. However, this also introduces a large performance overhead. In the example that @deklanw's shared we have to create a lot of hydration code to check that every piece of text matches what is expected on the client and repair it if it doesn't. This extra code is where the performance impact is coming from in the Svelte case. Even ignoring the runtime impact of running this code, it increases the size of the JS that has to be sent over the wire

Here's the REPL for @deklanw's example: https://svelte.dev/repl/c91e3cef3fe94b859e26e573f052ef42. The JS output is 4,000 lines. If you turn on hydration it grows to 100,000 lines because of all the repair code.

Ways we can improve performance on @deklanw's demo

  • Static text repair optimizations (https://github.com/sveltejs/svelte/issues/7226#issuecomment-1052775033)
  • Introduce an option to disable repair mode and do React-like hydration
  • Partial hydration

Prioritizing

Performance is a high priority. I do think it's helpful to have some conversation around what would be most impactful in terms of improving performance further for a few reasons. E.g. I and other maintainers may be overlooking realworld use cases that we don't see in our own projects and we all may have different estimates of the impact of certain performance changes. I certainly am not dismissing any of the issues raised here, but do want to ensure we have the same understanding to help prioritize. I had no idea that very large Svelte pages were previously crashing, so this thread has already helped improve things by getting https://github.com/sveltejs/svelte/issues/4694 fixed and that wouldn't have happened without all the discussion here!

In terms of this specific issue and the three options:

  • Repair optimizations require no code changes to the user code and would be the easiest to get a PR accepted for because there would be the least debate over what the API should be, etc. It'd probably give only 30-40% of the impact of other changes
  • An option to disable repair mode would require a fair amount of discussion from the maintainers before it could be agreed to. It would not necessarily solve the data serialization issue on its own but would shrink the JS bundle just as much as partial hydration
    • we'd want to consider it in the context of other changes we'd like to make to the Svelte internals
    • we'd want to introduce dev mode warnings to let people know if their client-side and server-side HTML differ and a repair is not happening
    • it might be somewhat difficult to implement as it requires a lot of knowledge of the Svelte internals. There was a prior PR that implemented it without an option (https://github.com/sveltejs/svelte/pull/4309) and could be used as a starting basis. It's possible that an initial implementation could be a partial implementation that only turns off repairing static HTML to get most of the win and potentially make the implementation easier
  • Partial hydration is the hardest to use from a user standpoint and would probably require the most discussion from the maintainers as it's the most user impacting change
    • e.g. Astro has users annotate anything you want to hydrate with client:visible
    • it may require new Svelte core features as prerequisites (e.g. https://github.com/sveltejs/svelte/issues/5572#issuecomment-1063238044) though it depends on what API we'd want to pursue

benmccann avatar Mar 08 '22 20:03 benmccann

@benmccann Sounds good. Not that you are asking my opinion, but as I said I'm here, so I will give it.

I think repair comes with the territory as the default when you don't have a VDOM and you are wiring up reactive execution. I haven't witnessed it being that detrimental compared to React but I've only looked at large examples that have been bottlenecked elsewhere. I didn't realize others didn't do that. I feel that they may have at some point in the past?

I think in general that is an interesting question and is something to discuss. I think it is particularly interesting where things are heading because it is sort of discussion because it serves as a basis for other decisions, especially if you look along partial/resumable hydration patterns. We actually talked about this at length when working on Marko 6, because I was very much originally in the camp that the client should be the source of truth. However, the more you move pieces to the server that don't update the more likely you are to have inconsistency. Once you start making decisions, like don't run this expression in the browser because you already did on the server you can no longer rely on the behavior that the client is going to fix it in all places. Ultimately the only option was to treat the server as the initial source of truth, the more you offload (which is inevitable) the more this becomes the case. So I think this is good thinking.

As for Partial Hydration, there are different ways to attack this for Svelte. Compiler gives you lots of options. As far as I can tell the proposal is basically as a way to enrich static pages and that is fair. People already revel at reduction of 50-80% of JS component code size, but I do think there is a benefit beyond the JS hydration that come here.

Data serialization savings. Something fetched on the server that can not be re-fetched doesn't need to be serialized on whole if it would be rendered into the HTML only on the server. Any data interacting with client components would need to be present for hydration but what is also interesting about partial hydration is the potential of partial data serialization. Not an all or nothing thing. This actually can reduce page size, server rendering, and hydration time in one swoop.

Beyond that if there is an interest, I believe there are other ways to attack this without the DX concerns. Svelte is a compiler after all. It comes down to the fact partial hydration and progressive hydration don't necessarily need to be conflated. However, it is a very large investment for something probably tertiary to the main goals.

ryansolid avatar Mar 08 '22 23:03 ryansolid

Personally I would love (something like) the partial hydration being described here.

For reference here are some other frameworks that do various forms of "partial hydration" or "resumability" or "islands of execution"

I'm not proposing that any of these approaches is the right one, or that Svelte should follow any of them. I'm just listing some examples for reference. Anyone looking to understand the concept more can read the various perspectives on it, and Svelte can potentially learn the pros/cons from the different approaches already happening.


EDIT: added another framework

JordanShurmer avatar Jun 29 '22 15:06 JordanShurmer

I would like to add to this discussion a non-performance reason to add partial hydration.

Reducing the need to spend resources on API calls for static content that is only updated at build time. Static blogs/encyclopedia/dictionary/etc, for example. The API doesn’t need to be a secret or hidden, but as you can see, there’s a lot of reduction in traffic we can achieve if the API is only hit during build-time. This would empower small creators like myself to bootstrap new startups or large-audience hobby projects without much or any hosting costs.

Svelte is by far the most ergnomic and intuitive framework I’ve ever used, and at least for what I need, partial hydration is the last big piece.

I’ve tried the trick where you import browser from $app/env and short circuit load() when in the browser. While it works as I expect, it throws errors into console as the page attempts to hydrate and is missing that data it would have fetched in the load() call.

Right now, my solution is to run a python script that is executed before sveltekit build which will pull all the JSON files from the API. These files get put in the static directory. In essence these files serve as the API “server” so visitors will never actually hit my API services. This is working well for now, but I would like to see if I can skip this middle step.

The only other way I can imagine implementing this is by utilizing something like jinja2 or another “code generation” tool that would read the API and actually generate Svelte code which then would be built by Svelte.

Both of these solutions fall far from the tree of what I would consider a good, long-term solution. SvelteKit and pre-rendering already does everything I want except for that “hydrate everything again in the browser”.

Thank you for your time.

keehun avatar Jul 10 '22 12:07 keehun

Disclaimer: I'm fully ignorant on the challenges involved in releasing this feature, let alone the viability of what I'm going to propose next.

AFAIK, this feature requires figuring out two parts:

  • The syntax: figuring out how to indicate what components should keep hydrated, how should they be hydrated and what data sources if any should be fetched for the remaining components that don't require hydration (i.e: a simle image list).
  • The processing: grabing this input with said syntax and effectively rendering the output HTML+CSS+JS files.

What I thought would be a good idea in order to speed up the release of this feature is to take on the syntax part first and release that ASAP, before the processing part.

That is, in contrast to waiting for the full feature to be developed, aim to release the frontend part of it so:

  1. As soon as we have this not-so challenging feature syntax, the community can start building right off the "partial-hydration-able server-side renderer" on the side . Speeding-up the time we can start using this.
  2. We would no longer tie developers to a Node.js server, and instead let every SvelteKit user use a custom backend solution in a microservice fashion.
  3. SvelteKit maintainers can still take their time to work on a fully opinionated backend for SvelteKit without tying us users to wait for it.

Lucasmiguelmac avatar Jul 12 '22 21:07 Lucasmiguelmac

My site is having an issue with the drop-down nav not being usable for quite some time while waiting for the page to hydrate. On a fast connection, usually by the time the user clicks the nav, it works fine, but on a slow connection it can take up to over 1 minute while the page is loading / hydrating.

I feel like this would be a great use-case for partial hydration. If anyone else has any suggestions about how to remedy the issue without partial hydration please let me know.

vettloffah avatar Feb 15 '23 16:02 vettloffah

I am no compiler expert, but I have a question. Obviously elements with browser apis or onMount or anything like these cannot be left out of interactivity. Would it be possible to (somehow) infer the hydration/non-hydration components? Perhaps by looking for event listeners, or anything really that SvelteKit cannot leave out of interactivity like stuff that call "window", have onMount / onDestroy or others. It would eliminate the need for a seperate API or something like that. Although this could cause sometimes the application to break, there could be a seperate compile-step-only prop/action/any-idiomatic-svelte that can force a component or an entire page to hydrate regardless & vice versa. Honestly, I don't really see how this approach can be incorporated, or really if its even possible or not to implemented without ginormous compile times. But still, it just came to my mind for the simplest of all APIs for a lighter app by default.

Dev-Siri avatar Sep 08 '23 18:09 Dev-Siri