Closed kristianmandrup closed 4 months ago
Hello @kristianmandrup , I'm not very familiar with Svelte 5 and I plan to wait until it's actually released to do any work specific to it.
That being said, in Svelte 4 you would just have to do this
<script>
import { source } from 'sveltekit-sse'
import { messageStore } from 'message-store'
const connection = source('/events/app')
const message = connection.select('message')
$: messageStore.addMessage($message)
</script>
// Your markup goes here.
Because .select()
gives you a store itself, hence the $message
in the code above.
I'm assuming the equivalent in Svelte 5 is something like this
<script>
import { source } from 'sveltekit-sse'
import { messageStore } from 'message-store'
const connection = source('/events/app')
const message = connection.select('message')
$effect(function run() {
messageStore.addMessage($message)
})
</script>
// Your markup goes here.
I haven't tested it though. I do remember the Svelte team saying at some point that stores will interact with runes as they normally interact with the current reactive system in Svelte 4, so it would be a breaking change on their part if this doesn't work.
Edit: from a quick search I found this https://svelte-5-preview.vercel.app/docs/faq#breaking-changes-and-migration
Let me know if this answers your question.
Thanks a lot for your answer. For now I seem to have it working using the following pattern:
const transformed = channel.transform(function run(data) {
if (data === '') return;
// TODO: parse json
return `${data}`;
});
let projects = $state<ProjectPayload[]>([]);
let lastMessage = $state<string>('');
transformed.subscribe((value: string) => {
if (!value) return;
lastMessage = value;
// TODO: move to transform function
const json = JSON.parse(value);
const { source, model, action, data } = json;
if (model !== 'project') {
console.log('not a project event');
return;
}
const project = data;
// TODO: depending on the event, add, remove or update the project
projects = [...projects, project];
});
import { getToastState } from '$lib/toast-state.svelte';
const toastState = getToastState();
const toastMap = new Map<string, unknown>();
$effect(() => {
const message = lastMessage;
if (!message) return;
const json = JSON.parse(message);
const { data } = json;
if (!data) {
console.error('missing data', json);
}
const { name, description } = data;
if (!name) {
console.log('missing name', data);
return;
}
// already processed
if (toastMap.get(name)) {
console.log('already made toast for', name);
return;
}
toastMap.set(name, data);
toastState.add(name, description);
});
Currently overly verbose and complicated, but it gets the job done. The key was to simply subscribe to the readvalue store returned by transform
transformed.subscribe((value: string) => { ... })
Then from there I could set a $state
with the value and work from there. I'm sure there is a much simpler way.
Btw, I had an issue with the first message received from SSE always being an empty string for some reason, but it might well be an issue with my internal logic, such as undefined
being sent as empty string?
Btw, I had an issue with the first message received from SSE always being an empty string for some reason, but it might well be an issue with my internal logic, such as undefined being sent as empty string?
That is expected behavior, the first value is always empty because it takes time to actually open the connection to the server.
It's either that or force userland to deal with a Promise<Readable<string>>
and {#await}
in the markup.
A third solution would be initializing the value in SSR but that would mean your server would have to open a connection to itself to read the value, which is a waste of resources and will probably slow down the SSR itself by a lot, especially in a cloud environment where you're not 100% the node doing the SSR will actually connect to itself. It could connect to a different twin node and slow down things even more.
I would like aggregate the SSE events in a messages state/store. Would I run the source in an onMount or $effect? It is unclear how to use it with stores