melte
melte copied to clipboard
Svelte 5
Thanks for making this package!
Any preliminary thoughts on support for Svelte 5? My guess is that it won't release until early next year but the fine grained reactivity by default with proxies looks pretty good: https://github.com/sveltejs/svelte/pull/9739
I'm not entirely sure how that plays with Meteor's reactive cursors though. Was wondering if you've already given this some thought.
@zodern I think something like this might work. What do you think?
// tracker.svelte.js inside zodern:melte
import { Tracker } from 'meteor/tracker';
import { onDestroy } from 'svelte';
export const track = (reactive) => { // reactive is a reactive data source, e.g. a cursor or a value like Meteor.user()
const isCursor = reactive instanceof Meteor.Collection.Cursor;
let data = isCursor ? $state([]) : $state(undefined);
let handle;
if (isCursor) { // allows for fine-grained updates
handle = reactive.observe({
added: (document) => data.push(document),
changed: (newDocument, oldDocument) => data[data.findIndex((item) => item._id === oldDocument._id)] = newDocument,
removed: (oldDocument) => data.splice(data.findIndex((item) => item._id === oldDocument._id), 1)
});
} else {
handle = Tracker.autorun(() => {
data = reactive
})
}
onDestroy(() => handle.stop());
return data;
};
export const subscribe = (subscriptionName, ...args) => {
let sub = $state({ ready: false })
const handle = Meteor.subscribe(subscriptionName, …args, onReady(() => {
sub.ready = true
});
onDestroy(() => handle.stop());
return sub;
};
// store.js
import { track } from 'meteor/zodern:melte'
export const currentUser = track(Meteor.user())
// App.svelte
<script>
import { track, subscribe } from 'meteor/zodern:melte'
const sub = subscribe('todos');
const todos = track(Todos.find());
async function createTodo(event) {
event.preventDefault();
// call your Meteor method
}
</script>
{#if !sub.ready}
<p>loading…</p>
{/if}
{#if currentUser}
<form onsubmit={createTodo}>
<input type=‘text’ placeholder=‘Type to add new todos’ />
</form>
{/if}
{#each todos as todo (todo._id)}
<p>{todo.text}</p>
{/each}
I haven’t tried it yet so there might be issues with the above. When I attempted previously, I wasn’t able to get Svelte and Meteor 3 to play nicely together.
Maybe there’s an even better way to do it but this feels pretty nice given the direction Svelte 5 is taking.
We'll want a solution that allows the reactive code to re-run, for example if the Todos query needs to change depending on another variable.
I was considering adding a $tracker
method, and having the compiler rewrite it into svelte 5 code like we currently do for $m:
statements. One challenge is svelte 5 has 3 different api's for reactive code that run code at different times ($derived, $effect, $effect.pre), and I currently am not sure which ones we need a tracker equivalent for.
We’ll want a solution that allows the reactive code to re-run
Ah yes, good point. Will do some more thinking here.
I was considering adding a $tracker method
Nice! That could be really nice if it was treated like the other runes in that it wouldn’t need to be imported.
One challenge is svelte 5 has 3 different api's for reactive code that run code at different times ($derived, $effect, $effect.pre), and I currently am not sure which ones we need a tracker equivalent for.
Yeah my understanding is that $:
got split into $derived
and $effect
. $effect.pre
is akin to beforeUpdate
.