Skip to content

Export symbol STATE_SYMBOL or register it globally #15908

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

Open
threema-andre opened this issue May 13, 2025 · 7 comments
Open

Export symbol STATE_SYMBOL or register it globally #15908

threema-andre opened this issue May 13, 2025 · 7 comments
Labels
awaiting submitter needs a reproduction, or clarification

Comments

@threema-andre
Copy link

Describe the problem

In our application, we use MessageChannels to communicate with workers. Svelte 5 in rune mode proxies variables declared with $state. Such proxied variables cannot be sent through the message passing system without unpacking them with snapshot. However, there is no way to figure out programatically whether or not a value given to the message passing system is such a proxy. The only way is trial and error, to see whether or not the message passing system fails at runtime.

Describe the proposed solution

We saw that you use a special symbol for such Proxies, i.e STATE_SYMBOL. We would like to have it exported or registered globally (using Symbol.for), so that we have a way of checking whether or not a variable was proxied by svelte, so we may unpack it before sending it through the Channels.

If this is not a viable solution for you, could you explain how it is possible to detect such proxies programatically?

Importance

i cannot use svelte without it

@Prinzhorn
Copy link
Contributor

It's safe to use $state.snapshot on everything. So you can do for all data before you pass it to the channel.

Other than that this is a duplicate of #15345

But it should probably be documented that $state.snapshot will internally check if it's state.

@threema-andre
Copy link
Author

threema-andre commented May 13, 2025

Yes, but we would like to determine this outside of the svelte world, since our message passing logic happens in pure typescript and we don't have (and don't want) access to svelte there.

@Prinzhorn
Copy link
Contributor

But why leak Svelte logic into the outside world at all? Why not make the Svelte part responsible for passing proper data to the outside world?

@Prinzhorn
Copy link
Contributor

It's safe to use $state.snapshot on everything.

I want to revoke that sentence. Svelte will clone anything, even if it's not a $state. Was assuming it would just return anything that it's doesn't control as-is.

@dummdidumm dummdidumm added the awaiting submitter needs a reproduction, or clarification label May 13, 2025
@dummdidumm
Copy link
Member

I also would like to understand the problem better. You're saying your outside-TS logic should have no knowledge of Svelte at all, but using something like Symbol.for(STATE_PROXY) would mean you leak knowledge about Svelte into it.
What is stopping you from always using $state.snapshot before passing it to the message channel?

@threema-andre
Copy link
Author

threema-andre commented May 13, 2025

It kind of seems like a brittle approach to me to expect the developers to always call $state.snapshot before sending something through the channel.

svelte5 proxies objects without letting the programmer know about it. We believe that there should be a way for programmers to find out whether or not an object was proxied by svelte. This would allow us to write wrappers in the transfer logic that implements special logic for svelte state. In that case, we would only need to implement this handler and then the frontend developers using svelte do not need to take care of special handling whether or not something may or may not be proxied.

Additionally, $state.snapshot does not work on every object. For example, we have special transfer logic for stores but we encountered places where $state.snapshot did not work on transferable objects.

@threema-gian
Copy link

To add to the previous comment: Let's say we have an object with the following interface:

interface Foo {
    type: "foo" | "bar";
    blob: Promise<Blob | undefined>;
    baz: Writable<boolean>; 
}

If an instance of such an object is used in a $state, the blob and baz props will not be serializable AFAIK and we get an error state_snapshot_uncloneable. Of course it's debatable whether the example above makes sense, but I think it's fair to assume that cases where $state.snapshot does not work can definitely occur in some codebases (such as in our case).

We would like to have the possibility to control the snapshot logic ourselves, so that we can ensure that it matches the one we use for the transfer logic. STATE_SYMBOL would allow us to achieve this.

Side note: We currently just use $state.snapshot on a case-by-case basis, which means we need to be careful to add it whenever the respective state needs to be sent to a worker. Because this is not type-safe, it opens up tremendous potential for errors, which is why we want to implement a way that handles this automatically to reduce the cognitive load and improve safety.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting submitter needs a reproduction, or clarification
Projects
None yet
Development

No branches or pull requests

4 participants