sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.52k stars 4.12k forks source link

Svelte 5: Significant increase in Javascript execution time with many components in relation to Svelte 4 #11576

Closed mheinzerling closed 3 months ago

mheinzerling commented 4 months ago

Describe the bug

By accident I created a document in Svelte 4 with 130000 DOM Elements. Essentially I'm converting a large JSON test report into a HTML structure, mapping the data to ~20 components for the test classes, with each having ~5 methods and each having again ~3 steps and finally each having a grid with up to 4100 Divs. So there are in general 4 different Svelte components. I'm totally aware that this is just wrong, and they should not be rendered all on initial load. Nevertheless, out of curiosity, I converted this project to Svelte 5 and for reference also to Vue.

Lighthouse results - original

in seconds Total Blocking Time SpeedIndex First Contentful Paint Largest Contentful Paint Script Evaluation Parse HTML & CSS
Svelte 4 - Build 4.3 5.6 0.3 16.6 1.025 1.516
Svelte 5 - Build 12.15 14.2 0.3 16.6 1.942 8.163
Vue - Build 11.22 12.5 0.3 17.4 2.247 7.050

The script execution time doubles in Svelte 5 and the HTML parsing and CSS is even worst.

At least for the script execution, I see a similar factor in my minimal reproducable example. I just used the initial template projects and added the counter 50000. I guess for reproducing the HTML performance the example needs to be extended by more complex templates. Due the simplicity I might have also lost other details that add the to execution time, but as the factor is pretty close to my original performance the examples seems to be good enough.

Lighthouse results - sample

in seconds Total Blocking Time SpeedIndex First Contentful Paint Largest Contentful Paint Script Evaluation Parse HTML & CSS
Svelte 4 - Build 0 1.9 1.3 1.3 0.208 0.004
Svelte 5 - Build 0.810 1.7 0.3 0.7 0.358 0.004
Vue - Build 0.960 1.9 0.3 0.9 0.487 0.003
Svelte 4 - Dev 9.92 12.1 0.8 5.8 9.242
Svelte 5 - Dev 1.450 2.6 0.8 1.5 0.644
Vue - Dev 3.110 4.4 0.7 2.4 1.528

Reproduction

https://github.com/mheinzerling/svelte11576

Logs

No response

System Info

System:
    OS: Windows 10 10.0.19045
    CPU: (8) x64 Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
    Memory: 3.92 GB / 31.89 GB
  Binaries:
    Node: 20.11.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.18 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 10.2.4 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Chrome: 124.0.6367.118
    Edge: Chromium (123.0.2420.65)
    Internet Explorer: 11.0.19041.3636

Severity

blocking an upgrade

trueadm commented 4 months ago

I think the first thing to do here is to isolate SSR + hydration from just purely client side rendering, i.e. disabling SSR entirely. Also Lighthouse doesn't really do any justice here as it's just giving scores, it would be far more helpful to use the dev tools in Chrome to record a startup trace in the performance tab – as this can also indicate where the time is being spent.

Also are you testing DEV or prod here?

mheinzerling commented 4 months ago

Also are you testing DEV or prod here?

Both. Build is PROD and Dev ist DEV. I added dev just for reference.

I think the first thing to do here is to isolate SSR + hydration from just purely client side rendering, i.e. disabling SSR entirely.

This is plain Svelte, not SvelteKit. I was under the impression that there is no SSR. Otherwise, how can I disable it?

Also Lighthouse doesn't really do any justice here as it's just giving scores, it would be far more helpful to use the dev tools in Chrome to record a startup trace in the performance tab – as this can also indicate where the time is being spent.

The numbers are actually not the scores, but the details some clicks deeper :) Nevertheless they are obviously just a starting point, but they are a reliable way the get reproducible numbers between the different runs and versions.

I guess you are faster if you just check the linked sample at your own? But I could also export some profiles - the tabs are still open.

trueadm commented 4 months ago

Ah thanks for that. I checked out your github repo and see these results from the perf trace on DEV:

Svelte 4: Screenshot 2024-05-13 at 14 49 44

Svelte 5: Screenshot 2024-05-13 at 14 49 07

I'm using Chrome v124 on an M2 MacBook Pro.

mheinzerling commented 4 months ago

Yes, as I mention, DEV is only for reference and Svelte 4 is really slow for me, too.

trueadm commented 4 months ago

For prod:

Svelte 5:

Screenshot 2024-05-13 at 15 09 29

Svelte 4:

Screenshot 2024-05-13 at 15 09 46

I don't see anything here that stands out as problematic?

trueadm commented 4 months ago

I do see this in Svelte 5, which doesn't look like something Svelte 5 has in its runtime:

Screenshot 2024-05-13 at 15 10 49

This is what is adding the majority of the overhead vs Svelte 4 by the looks of it.

gtm-nayan commented 4 months ago

That is from vite's "modulepreload" helper afaik, it should be in both if you're using the same bundler unless the css modes are different maybe.

trueadm commented 4 months ago

@gtm-nayan It is in both, it just seems to majorly affect Svelte 5 compared to Svelte 4. Not sure why.

trueadm commented 4 months ago

Interestingly, avoiding using document fragments internally from doing this:

  <div class="card">
    {#each {length: 50000} as _}
      <div>
        <Counter/>
      </div>
    {/each}
  </div>

Has a noticeable impact on performance for Svelte 5.

gtm-nayan commented 4 months ago

Hmm could it be the templates are triggering MutationObserver or making it do some unnecessary checks somehow?

trueadm commented 4 months ago

@gtm-nayan You're on to something:

Svelte 5 logs of DOM mutations:

(2) [MutationRecord, MutationRecord]

Svelte 4 logs of DOM mutations:

(200019) [MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, MutationRecord, …]
trueadm commented 4 months ago

Ah maybe it's not that on reflection. It seems we early return and don't add the mutation observer at all.

trueadm commented 4 months ago

Can you update to the latest version of Svelte 5? This should include some improvements.

mheinzerling commented 4 months ago

The sample seems to get slightly faster in DEV mode between next.131 and next.132: 575ms vs. 644ms. In PROD mode this is similar 308ms vs 358ms. Although this looks like a 10% improvement, we should take it with a grain of salt, as this is from my work PC and no isolated environment.

For my original code I started recreating my measurements, as this was still next.123 and the results are not that impressive.

version run parse html/css script evaluation
next.123 PROD 1 8.862 2.217
next.123 PROD 2 8.222 2.020
next.123 PROD 3 8.689 2.189
next.131 PROD 1 8.525 2.220
next.131 PROD 2 8.576 2.182
next.131 PROD 3 8.431 2.165
next.132 PROD 1 8.398 2.136
next.132 PROD 2 8.403 2.140
next.132 PROD 3 8.403 2.153

I guess my sample was not good/specific enough. I will try to create a new one later this week. In the meantime please find attached a profile from my original page load.

Trace-20240514T082854.zip

trueadm commented 4 months ago

@mheinzerling Yeah I think we need a better example. For me Svelte 5 is faster in script time and parse html/css time than Svelte 4.

dummdidumm commented 4 months ago

Which browsers (including version) are you both testing on? Is this a possible cause for the difference?

trueadm commented 4 months ago

I'm running on Chrome v124.

mheinzerling commented 4 months ago

Chrome Version 124.0.6367.118

trueadm commented 3 months ago

@mheinzerling I'm not sure what more we can action in regard to this without more information or data.

mheinzerling commented 3 months ago

Sorry, currently I have no time to continue here. Feel free to close the ticket, and I might create a follow-up later.