-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Description
Describe the bug
Originally posted as #10628, but now with a much more simplified demo.
I've ported over a demo of my virtual list from Svelte 4 to Svelte 5. There's an App.svelte
that renders items using VirtualList.svelte
. In the process I've noticed that when the App.svelte
uses runes but VirtualList.svelte
does not, performance tanks massively. Depending on the number of items in the virtual list, you can completely freeze the app. I assume this happens because a large proxied $state
array with items (e.g. 10k or even 100k) in App.svelte
is converted to vanilla array via deep_read
for the VirtualList.svelte
to consume.
The REPL should be self explanatory. For simulation I have 10k items and the virtual list renders the first 10 of them. A setTimeout
is used to simulate new data arriving every 100ms. In the interop version you'll see spikes every 100ms. With 100k items my fans become unbearably loud. The other two versions are chilling.
Non-runes
Runes / non-runes interop
Runes
Sure this is an edge case, but since Svelte 5 is meant to be backwards compatible, it's not unrealistic that you're using a Svelte 4 component in a Svelte 5 app.
In my app it doesn't matter, because the items in my virtual list come from a readable
store that abstracts WebSockets
, so the items aren't $state
.
Since VirtualList.svelte
never accesses the entire items
, maybe the deep_read
conversion should happen lazily when calling slice()
? Or alternatively all operations on the proxy, such as push
should be mirrored into a non-proxied version immediately. No idea if that's possible, right now I assume you convert all props via deep_read
and throw them at the other component.
Reproduction
See REPLs. In the "Runes / non-runes interop" REPL the checkbox conveniently acts as a checkbox for you PC fans as well.
Logs
No response
System Info
Likely irrelevant
Severity
blocking an upgrade