Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork4.6k
Asynchronous Svelte#15845
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
This is a long document; get yourself a cup of tea. tl;drYou can now use the npm i https://pkg.pr.new/svelte@async ...and adding the // svelte.config.jsexportdefault{compilerOptions:{experimental:{async:true}},kit:{// ...}}; You can also try things out in theasync playground. You will find bugs! This is in no way production-ready. The PR that accompanies this discussion is at#15844. BackgroundIn olden times, we did asynchronous work like fetching data inside Frameworks like SvelteKit (or Remix or pre-App-Router Next.js, etc) offer an alternative: instead of fetching inside the component, we do our asynchronous workoutside the component, for example in In recent years component frameworks have explored a third way: putting asynchronous work back inside components, but in a way that is coordinated:
We believe Svelte's compiler-centric nature offers us a way to have component-level async work with significantly better ergonomics and fewer drawbacks than existing approaches. Requirements
We also want this to have minimal impact on performance and memory for existing codebases, and to cause little or no breakage for existing apps. DesignIn a nutshell: you can now use
We also introduce a If state is read inside a <h1>Weather forecast for {city}</h1><p>{awaitgetWeatherForecast(city)}</p> ...the To know if an update is currently pending, you can use {#if$effect.pending()} <p>loading new data...</p>{/if} Ifunrelated state changes while an update is pending, it will be visible immediately (assuming it doesn't separately cause asynchronous updates). Use casesThe most obvious use case is loading data (which could be as simple as
Avoiding waterfallsAs much as framework authors like to witter on about rendering performance, the thing that really slows apps down islatency. In some cases you can reduce latency by speeding up your back end, or prefetching content you expect to need, or serving content from somewhere close to the user, but those things aren't always possible. What youcan do is mitigate the effect of latency by minimising the number of round trips between the browser and the server. Svelte helps by doing as much work as possible in parallel. For example here... <li>apples {awaitgetPrice('apple')} each</li><li>bananas {awaitgetPrice('banana')} each</li><li>canteloupes {awaitgetPrice('canteloupe')} each</li> ...the three calls to <WiseMonkeyverb="see" /><WiseMonkeyverb="hear" /><WiseMonkeyverb="speak" /> Not all work can be parallelized. Any // `a` will be calculated and _then_ `b` will be calculatedleta=$derived(awaitfoo(x));letb=$derived(awaitbar(x)); ...though note that if letaPromise=$derived(foo(x));letbPromise=$derived(bar(x));leta=$derived(awaitaPromise);letb=$derived(awaitbPromise); A brief digression on 'necessary' waterfalls and server componentsWhileunnecessary waterfalls can generally be prevented by pushing async work as far into the 'leaves' of your application as possible, there are alsonecessary waterfalls to contend with. For example, you can't use letartist=$derived(awaitsearch(query));lettracks=$derived(awaitgetTrackListing(artist.id)); It's better if you can do both fetches on the server, near your database. There are two ways to solve this: either anticipate the need for the track listing when you do the search... let[artist,tracks]=$derived(awaitsearchAndGetTrackListing(query)); ...or use a mechanism like React Server Components, where the rendering happens on the server. Option 1 has less-than-ideal ergonomics, though it's basically equivalent to SvelteKit's We anticipate that opinionated data-fetching patterns will emerge over time, along with new approaches inspired by RSCs, to solve this problem. Future workThe work presented so far is the first step of a multi-stage process. While it's useful in its current form, more value will be unlocked with later stages: Async SSRToday,server-side rendering is fully synchronous. Because of this, if a It would be better to render the content instead, but this requires that SSR become an asynchronous operation. In an ideal world we would also be able to stream the result where appropriate. This is complicated by the fact that you ideally need to know what's in the Once we get to this part, it's likely that the requirement for ForkingIn SvelteKit we preload the code and data necessary for a navigation before it even occurs: when you hover over a link, or tap it, we import any modules needed by the route and begin running whichever To make this work in a world where asynchronous work happens inside components, we need to be able topretend that a state change occurred, and do the resulting updates 'off-screen'. The result can either be applied or discarded. Colloquially, we've been describing this as a 'fork'. You could imagine several unresolved forks coexisting simultaneously until one reality is chosen (by the user clicking on one of several links they've been close to interacting with, for example). Most likely, we'll add an API to Svelte that allows frameworks like SvelteKit (but also particularly ambitious application authors) to enter the multiverse. This all sounds very complicated, but in reality it's not all that different to how asynchronous updates already work. Nevertheless, it will take some finagling to get right, and in the interests of shipping we haven't included this work in the current PR. Client-server utilitiesUnless we want to createserver endpoints for everything we want to We're at the early stages of figuring out what this all looks like, but we're very confident that the foundation we're laying here will allow us to design something really good. Improving SvelteKitAnticipating everyone's reaction: no, we're not going to suddenly make you rewrite all your SvelteKit apps. But taking all the other stuff together, a picture starts to emerge: a version of SvelteKit that's athinner layer on top of Svelte. For example, as proud as we are of ourzero-effort type safety, it's something you no longer need if you're fetching data directly inside your component. Meanwhile the framework internals could potentially get simpler, because we'd be able to rely on common primitives inside Svelte itself. (Today, we can't reuse that much code between the server and client portions of SvelteKit, and we rely a lot on virtual modules and generated code. Some of that is for historical reasons, but some is necessary because anything asynchronous has to happen outside Svelte.) It seems likely that a lot of interesting new possibilities will open up as a result of this work, and it seems at leastplausible that we'll collectively find ourselves drifting away from primitives like NuancesNo |
BetaWas this translation helpful?Give feedback.
All reactions
👍 260😄 3🎉 13❤️ 187🚀 165👀 42
Replies: 44 comments 166 replies
-
so exciting!! |
BetaWas this translation helpful?Give feedback.
All reactions
😕 1
-
Love it's a discussion introduction for such an awaited feature! |
BetaWas this translation helpful?Give feedback.
All reactions
😄 29
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
This is really cool! I've been observing the
|
BetaWas this translation helpful?Give feedback.
All reactions
-
Doubled is updated..you can |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
-
In that code, it is, but inmy code, it isn't. |
BetaWas this translation helpful?Give feedback.
All reactions
-
|
BetaWas this translation helpful?Give feedback.
All reactions
-
The value is the value. The UI may display a previous value in order to maintain consistency, but it wouldn't make sense to have stale values elsewhere such as in event handlers
We just... don't run them? I haven't seen the stream so I'm not sure why it should be impossible.
No idea! Soon hopefully.
Because otherwise you'd see things like
Because you're reading the state inside a
There's an 'Async SSR' section above that addresses this
We researched prior art but didn't see anything we liked to be honest. We reached this design from first principles. |
BetaWas this translation helpful?Give feedback.
All reactions
👍 15
-
When I read the document I was filled with excitement, fear and confusion |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Unfortunately, by manually orchestrating this state machine you lose the advantages of suspense
I'm hopeful for the integration of abort signals, I believe it may be the right abstraction I tried to makemy own integration, but it seems that the proposal is not yet prepared for rejected promises (the app simply crashes and the boundary does not capture any errors) Edit: The issue was not the rejected promise, but an infinite loop for some reason |
BetaWas this translation helpful?Give feedback.
All reactions
-
@Rich-Harris, It looks like you saved this example over the default example provided at the beginning of the discussion. |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Ah whoops! Fixed. Also made the devbox public. I also added a import{getAbortSignal}from'svelte';constresponse=$derived(awaitfetch(`/blah/${foo}`,{signal:getAbortSignal()}));constdata=$derived(awaitresponse.json()); |
BetaWas this translation helpful?Give feedback.
All reactions
👍 5
-
Now it is a broken version of the getAbortSignal demo 😁 |
BetaWas this translation helpful?Give feedback.
All reactions
-
dammit! fixed again. not sure why |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Not sure if I missed something, but -- there is some error handling in this demo:https://svelte.dev/playground/24eec2a85770402eae633d06aec412a6?version=pr-15844 but, how do you do error handling generically for any await'd thing? for example, in this parallel-promise template: <li>apples {awaitgetPrice('apple')} each</li><li>bananas {awaitgetPrice('banana')} each</li><li>canteloupes {awaitgetPrice('canteloupe')} each</li> what do I do if I want to render errors if |
BetaWas this translation helpful?Give feedback.
All reactions
-
I would assume that you should wrap apples and bananas in a <svelte:bondary><li>apples {awaitgetPrice('apple')} each</li><li>bananas {awaitgetPrice('banana')} each</li>{#snippetfailed(error,reset)}whoops, apples or bananas failed.{/snippet}</svelte:boundary><li>canteloupes {awaitgetPrice('canteloupe')} each</li> |
BetaWas this translation helpful?Give feedback.
All reactions
👍 6
-
Exactly — just the same as if there was no |
BetaWas this translation helpful?Give feedback.
All reactions
❤️ 3
-
thanks! |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Solid user here. Never used constdata=createAsync(()=>promiseFn(args)); |
BetaWas this translation helpful?Give feedback.
All reactions
-
Ok. But The approach has its merits though I'm not personally sold on the programming model |
BetaWas this translation helpful?Give feedback.
All reactions
-
What is "programming model" in that case? |
BetaWas this translation helpful?Give feedback.
All reactions
-
Nothing in the current It's not in core as we're focusing on the next major. More features will be included once 2.0 lands, but these aren't implemented nor restrict the current |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
@madaxen86 Currently Solid's There are 2 shortcomings of the approach. Neither of them related to performance or architecture but to ergonomics. First, our async isn't completely colorless in the sense that async values can be null, so people need to null check stuff is there until it is even with mechanisms like Suspense. So while you don't have to worry about passing promises around or the whole "where you fetch" dilemma client (non-RSC) uses of data-loading with Suspense have with React you introduce nullability into the tree. The second is Suspense being too eager to bail out. It is really easy to trigger Suspense on some small async update on the page causing return to fallback. Using Transitions is one way to avoid this, but most of the time people would probably rather just tear. This has lead to stuff like Of course, sitting with these issues over the years these are things we are already working on remedying in the next major version. But it is worth noting the proposal above for Svelte doesn't have these issues. The async holding along the graph + |
BetaWas this translation helpful?Give feedback.
All reactions
👍 31
-
@ryansolid happy to see you here! Thanks for reading the proposal.
Just the fact that I'm not dealing with promises in a way that feels JavaScript-native, but rather via a framework's abstraction. I totally understand why it is the way it is, and it's very much a matter of taste, but I don't think it would be the right design for Svelte. Ido like how aggressively The 'JavaScript-native' thing is obviously a minefield. Svelte is transforming your async code and doing all sorts of behind-the-scenes scheduling, but React and (IIUC) Solid are throwing to trigger Suspense; to me these feel equivalently magical. YMMV! |
BetaWas this translation helpful?Give feedback.
All reactions
👍 16
-
We have a neat little super-lightweight RPC (lighter than tRPC) setup that
This basically turns anything that we put into the API object into an async function callable from the client, with the same signature as the original server-side function. Also, since we're working with plain functions, things can be trivially wrapped with HOF et al both on the server and the client to implement concerns like authentication, validation, caching, etc. This has been really fun to use, and I'm happy to share more if there's interest in this. |
BetaWas this translation helpful?Give feedback.
All reactions
🚀 9👀 7
-
Is the |
BetaWas this translation helpful?Give feedback.
All reactions
-
It's an unnecessary extra microtask but I find it conceptually clearer. YMMV |
BetaWas this translation helpful?Give feedback.
All reactions
-
Anywhere we could follow along? Would be an immense timesaver to have an integrated RPC in sveltekit. |
BetaWas this translation helpful?Give feedback.
All reactions
-
I LOVE THIS - is there a branch or place for discussion ? |
BetaWas this translation helpful?Give feedback.
All reactions
-
THIS IS SO CLEAN! Taking it one step further to have Tanstack query-like destructuring of the data, loading, error, would be chef's kiss. |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Ah, so no freezing states in child components too, I suppose? I was hoping this was the case, it would certainly help with something like mobile stack navigations, carousels, accordions or drawers where youdo want a portion of your component tree to be frozen (seesvelte-freeze for the general idea, andsvelte-stakkr for a router building on that idea) The entirety of svelte-freeze could be simplified into this single component, and most importantly removes the need for willing packages to opt-in to the freezing functionality. <scriptlang="ts">import {untrack,typeSnippet }from'svelte';interfaceProps {frozen:boolean;children:Snippet;}const { frozen, children }:Props=$props();const PROMISE=newPromise(()=> {});</script><svelte:boundary>{#iffrozen}{awaitPROMISE}{/if}{@renderchildren()}{#snippetpending()}<!-- empty -->{/snippet}</svelte:boundary> I would admit that it's going to be a lot more complicated behind the scenes though, since now you need to have a way to have a derivation that runs outside of that suspension, so that you can check for It's certainly something that can be better handled by a different mechanism for sure, just like how React's |
BetaWas this translation helpful?Give feedback.
All reactions
-
Right, so if e.g. |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Yeah, I had hoped that |
BetaWas this translation helpful?Give feedback.
All reactions
-
Why? |
BetaWas this translation helpful?Give feedback.
All reactions
-
I don't understand this, I personally dislike $derived and $derived.by not working identically. Maybe someone could explain to me like I'm a 5 year old? |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
100% agree, i think the fact that constfooPromise=$derived.by(…)//.. several lines of codeconstfoo=awaitfooPromise; do, this would be very easy for someone to do as a refracting and completely break how something works without being clear why it broke. Should of included the pitfalls directly in the initial message i was pre-coffee :) Looking forward to this shipping, if this works as promised its going to be amazing. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Could the compiler allow both? Even |
BetaWas this translation helpful?Give feedback.
All reactions
-
useless AND nightmarish |
BetaWas this translation helpful?Give feedback.
All reactions
👍 2
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
@Rich-Harris I still don't understand this. Why wouldn't something likethis work: declarefunction$derivedBy<T>(func:()=>T):Awaited<T>// the type of this is number, not Promise<number>letnum=$derivedBy(async()=>await5) ...and the compiler can just treat it as if it were written like this instead: asyncfunctionderivedTemp(){returnawait5}letnum=$derived(awaitderivedTemp()) And, to avoid a breaking change, a new name (e.g. Update: I just realised this can also be implemented in user-land, using an IIFE: letnum=$derived(await(async()=>{await5})()) But, IMO this is not ideal. And, if it, or the workaround using regular functions, defeat the purpose of |
BetaWas this translation helpful?Give feedback.
All reactions
-
I explained it above#15845 (reply in thread) |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
-
I wonder if it could be possible to somehow abort promises that are no longer needed, so that there aren't unneeded in-flight requests due to network lag As I understand, once "Overlapping updates that touch the same state must be applied in linear order" is implemented the following would happen:
So instead by aborting the older fetches the developer explicitly says "I don't care about this anymore, just give the user the latest value" Something like this maybe? exportfunctiongetPrice(produce){returnawaitfetch("/api/price/"+produce,{signal:$effect.abortSignal()})} |
BetaWas this translation helpful?Give feedback.
All reactions
-
We actually implemented this exact thing a while back (as an import rather than a rune, but same semantics) but decided not to land it because your console quickly fills up with DOMExceptions that you can't really get rid of (unless you store a reference to the promise returned from But with async stuff it does potentially become more valuable, so it might be worth revisiting |
BetaWas this translation helpful?Give feedback.
All reactions
👍 16
-
I wanted to up vote revisit the abort signal, I watched that PR and was really looking forward to it. |
BetaWas this translation helpful?Give feedback.
All reactions
👍 4
-
Regarding async derived dependencies effects to be blocked until async derived resolves - you mention inputs being the exception. What about cases like a custom inputs or search bar with a clear button - pressing clear should clear that input and initiate an async search with empty value(it returns unfiltered entries then). There would be no focused input here so input will be cleared only after search resolves? |
BetaWas this translation helpful?Give feedback.
All reactions
-
Great question. The short answer is yes, if you press 'clear' then theinput won't clear until the results have come in. In that case you would need to express that intent ('clear the input as well as resetting the value')programmatically: <buttononclick={()=>name=input.value=''}>clear</button> As for custom inputs, it works by checking if the current element is |
BetaWas this translation helpful?Give feedback.
All reactions
😄 9
-
There are many use cases where we want to respond instantly to user input and fetch something in background. So, we definitely need a way to control that since both behaviors are useful. Maybe for opt in: lettext=$state.deferred("");letresults=$derived(awaitsearch(text)); Other options Or for opt out: lettext=$state.eager("");letresults=$derived(awaitsearch(text)); Other options |
BetaWas this translation helpful?Give feedback.
All reactions
👍 7
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Another idea, syncing only between the parts of the UI that have the same closest parent boundary (or possibly another special element), for example: <script>import {delayed }from'./utils.js';let x=$state(0);</script><svelte:boundary><inputtype="range"bind:value={x} /> <span>{x}</span><svelte:boundary><inputtype="range"value={awaitdelayed(x)}disabled /> <span>{x}</span>{#snippetpending()}<p>loading...</p>{/snippet}</svelte:boundary></svelte:boundary> The outside |
BetaWas this translation helpful?Give feedback.
All reactions
-
That was one of our first designs. Long story short it leads you into impossible-to-resolve situations |
BetaWas this translation helpful?Give feedback.
All reactions
👍 2
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
https://svelte.dev/playground/767e0bfd75614664a41ba73f28cc424c?version=pr-15844 Is this a case of 'Overlapping updates' stuff that is yet to be resolved? Or is this a different bug? I'm confused why |
BetaWas this translation helpful?Give feedback.
All reactions
-
Looks like a new bug, will investigate |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Is this another bug? Seems like |
BetaWas this translation helpful?Give feedback.
All reactions
-
Yeah there are bugs around |
BetaWas this translation helpful?Give feedback.
All reactions
-
For me, simply double-clicking on |
BetaWas this translation helpful?Give feedback.
All reactions
-
Thanks for the test cases — these are all now fixed |
BetaWas this translation helpful?Give feedback.
All reactions
👍 2
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
I know async SSR was mentions as a possible future development. In its current state are the component level await started on the server? or do they begin after hydration on the client? i suppose hydration will likely be much faster if it hits a pending early enough, but it still seems like a pretty big gotcha if request don't begin until after hydration. |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
If you look at the JS Output tab of theplayground and switch to ![]() In other words for now everything starts in the browser. Obviously that's not tenable in the long term; we want to be able to pass promises from the server to the client. It's not straightforward though. Consider a case like this: <script>if (browser) {constx=$derived(awaitfoo());consty=$derived(awaitfoo());// ... }else {constz=$derived(awaitbaz()); }</script> Where does the serialized data 'go'? If we somehow bake the values into a comment that the component reads as it hydrates, then it will expect two payloads but we've only baked in one. And it's not even one that we want to use! Or this: <script>import {blah }from'./stuff';importChildfrom'./Child.svelte';</script><Childblah={awaitblah} /> <script>import {blah }from'./stuff';let props=$props();</script><p>{props.blah===awaitblah}</p> This needs to render const{ head, body, data}=awaitrenderAsync(App,{...});return`<!doctype html><html> <head> <meta charset="utf-8"> {head} </head> <body> <div>${body}</div> <script type="module"> import { hydrate } from 'svelte'; import App from './App.svelte'; hydrate(App, { target: document.querySelector('#target'), data:${serialize(data)} }); </script> </body></html>`; (I'm glossing over a lot of stuff but you get the idea.) Alternatively, Svelte could delegate it to frameworks like SvelteKit which could provide their own abstractions (fetch caching, RPC utilities etc) and if a given expression doesn't have pre-rendered data ready to hydrate, Shorter version: there's a lot of stuff to figure out here and we don't yet know what it'll look like, but it's very much on the radar. |
BetaWas this translation helpful?Give feedback.
All reactions
👍 2
-
This is great 💪 |
BetaWas this translation helpful?Give feedback.
All reactions
-
More of an SSR question: has there been any more research or thought into how streamed components with errors will be handled? I remember reading another thread that was talking about including a meta tag if a component had an error so the page wouldn't get indexed. Interested to see where Svelte ends up. |
BetaWas this translation helpful?Give feedback.
All reactions
-
I'm enough of a purist that I struggle a bit with the idea of handling errors by shoving a Instead, I quite like the idea of separating critical stuff (status code, response.write(`<!doctype html><html><head>`);try{// `stream` returns `Promise<{ head: string, body: AsyncIterator<string> }>`const{ head, body}=awaitstream(App,{...});constresponse=newStreamedResponse(200);response.write(head);response.write(`</head><body><div>`);asyncfunctionnext(){const{ value, done}=awaitbody.next();if(done){response.write(`</div><script>${HYDRATE}</script></body></html`);}else{response.write(value);next();}}next();returnresponse;}catch(error){returnnewResponse(getStatusCode(error),renderErrorPage(error));} We could demarcate non-critical content with an attribute on <script>import {page }from'$app/state';import {getPost }from'$lib/api';constpost=$derived(awaitgetPost(page.params.slug));</script><!-- critical --><svelte:head> <title>{post.title}</title></svelte:head><h1>{post.title}</h1><divclass="post">{@htmlpost.content}</div><!-- non-critical --><svelte:boundarystreamable> <Comments /> {#snippetfailed())<!--ifanerroroccurswhilerenderingcomments,thissnippetgetsincludedintheserver-renderedHTML--> {/snippet}</svelte:boundary> Inside a streamable boundary, certain restrictions could apply, like no |
BetaWas this translation helpful?Give feedback.
All reactions
👍 4
-
Yeah I like it! I can't think of a better way. If you want to stream something critical it just comes with the caveat that it might error and still send a 200. So best practice remains to only stream non-critical content. For a client side navigation this wouldn't matter as much right? Everything could just be streamed as it resolves? |
BetaWas this translation helpful?Give feedback.
All reactions
-
Ah yep, the example wasmeant to show immediate writing of critical content but I wrote it wrong 😆 For client-side nav yeah, I think you could stream everything |
BetaWas this translation helpful?Give feedback.
All reactions
-
Awesome! This is going to be great |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
I'm the author ofTelefunc whichwas mentioned by Svelte Summit. I'm glad to see Telefunc inspired SvelteKit to re-create Telefunc's design! Currently, Telefunc doesn't have that many features and re-creating Telefunc is relatively easy. That said, Telefunc's goal is to support alot more features (including some features mentioned in the conference) while enabling frameworks such as SvelteKit to deeply integrate Telefunc. For example, real-time (two way communication) is very tricky to get right. I've some ideas and it would be great to design it together with the SvelteKit team — in case there is interest. Another example is error handling, which is an interesting topic as well. (The combination tRPC + TanStack Query is one example, but I believe there are much better ways to do it.) RPC's renaissance (it's actually anold technology — older than REST!) is just at its beginnings and I see an opportunity to create a common RPC infrastructure shared between frameworks. RPC has a bright future (full of promises). The door is open on my side to collaborate. |
BetaWas this translation helpful?Give feedback.
All reactions
🎉 4❤️ 21
-
Hey! In principle the door is open on our side too. In practice it may prove tricky, because the proposal we're about to share (this week or next) integrates with the rest of SvelteKit in a way that might be difficult to do in a less opinionated library. For example aquery in our design isn't just a wrapper around an HTTP transport mechanism, it also works with our reactivity system to manage a local cache, and has a mechanism for optimistic updates. (Meanwhile acommand causes currently active queries to clear their cache and re-run, unless you explicitly refresh queries in a more granular fashion.) We also have form functions that are very specific to Svelte, and prerender functions that are very specific to SvelteKit. All of this works with SvelteKit's (de)serialization mechanism which allows everythingdevalue allows, plus anything you've defined in your owntransport hooks, plus nested Promises, plus (soon, hopefully) streams and async iterables. And we'll likely have some opinionated handling of version skew. So there are likely too many implementation details that can't really be outsourced — the coupling of the different pieces within the frameworkis the real value. What's left is the transport mechanism, which as you say is relatively straightforward (though it admittedly becomes slightly less so when you factor in batching and real-time). I think what probably makes sense is for us to build this within SvelteKit to begin with, and then once we ship something we can start to get a sense of which pieces could become part of a common base. |
BetaWas this translation helpful?Give feedback.
All reactions
🎉 7
-
Seems like a good plan! And I agree: I also ain't sure whether/how a full-fledged RFC infrastructure can be made agnostic. Looking forward to your RFC! |
BetaWas this translation helpful?Give feedback.
All reactions
-
I'd like to bring up the behaviour of delayed synchronous results and what I found to be surprising behaviour. Experimenting with the PR, I extended the simple example so that there are two variables <script>import {delayed }from'./utils.js';let a=$state(0);let b=$state(0);</script>increment:<buttononclick={()=>a+=1}>a</button><buttononclick={()=>b+=1}>b</button><buttononclick={()=> {a+=1;b+=1}}>both</button><p>a = {a}</p><p>b = {b}</p><h2>Boundary</h2><svelte:boundary><p>a * 2 = {a} * 2 = {awaitdelayed(a*2,1000)} (delayed)</p><p>b * 2 = {b} * 2 = {b*2}</p>{#snippetpending()}<p>...loading...</p>{/snippet}</svelte:boundary> (https://svelte.dev/playground/7173ec0d84ed42bc85d6c8dc8c926fe2?version=pr-15844) Behaviour:
So the link that causes sync updates to be delayed appears to be if they are altered in the same tick as an async one? I don't know if this behaviour is technically considered right or wrong, but it sure is surprising, and surprising behaviour is always a worry. In particular the mixuture of delayed and instant updates to That said, I don't currently have any constructive suggestions to improve the situation :( |
BetaWas this translation helpful?Give feedback.
All reactions
-
You found a bug, which is now fixed on the branch. You might still find the behaviour slightly unintuitive at first though — if you click 'both' then 'b' in quick succession, there'll be a single visible update in which This is necessary to avoid tearing — when you update If you update |
BetaWas this translation helpful?Give feedback.
All reactions
-
This will make a good example for the documentation once the branch is settled enough that the docs start being written. |
BetaWas this translation helpful?Give feedback.
All reactions
-
What if |
BetaWas this translation helpful?Give feedback.
All reactions
-
They're equivalent - updates are grouped if they happen in the same microtask |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
-
Are there any plans for an equivalent of Displaying a list of comments and you need to fetch each user's avatar? You don't want to delay displaying any comments until all the avatars are done loading, but you also don't want the avatars popping in a random order either. Have three sequential blocks that depend on different data? You really don't want the user to see
If the user tries to interact with that second block, it will lead to frustration since a page layout shift will occur as soon as the first block loads. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Is there any way to opt out of anti-tearing? In my opinion, changes that should be synchronous behaving as asynchronous makes the entire UI feel buggy and slow. I feel that the result is better when the developer makes it clear which part of the UI is out of date using some pending state (like $effect.pending if it were local to the boundary) |
BetaWas this translation helpful?Give feedback.
All reactions
-
You can get the desired behaviorwith |
BetaWas this translation helpful?Give feedback.
All reactions
-
It would be irritating to do for every value but, if you need to just opt out for one or two things, |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
I think a case like this is probably better served with using a resource-like API, where you access the result via a property that updates whenever a new value comes in - basically we need (and will have) something similar to for example Solid's resource API that you linked to. |
BetaWas this translation helpful?Give feedback.
All reactions
👍 4
Uh oh!
There was an error while loading.Please reload this page.
-
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
hello mr code god, did you read through the original post before posting this question? |
BetaWas this translation helpful?Give feedback.
All reactions
😄 4
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
obviously not lol comment deleted |
BetaWas this translation helpful?Give feedback.
All reactions
😄 1
-
Will |
BetaWas this translation helpful?Give feedback.
All reactions
-
No, that would be surprising behaviour. But you could certainly convert an async iterable into a thenable |
BetaWas this translation helpful?Give feedback.
All reactions
-
Finally I took the time to play more with this branch, and I already love it. Few feedback in random order(hope it's not to late to give a feedback):
It makes me think that we should NOT have a pending snippet, but in reallity, we must have one. It's probably for good practice to enforce pending, ok. Would be great to have this info in the doc. (once done) b/ $effect.pending() globality I started to do: <svelte:boundary> {awaitlist(limit)} {#snippetfailed(error)} <p>oops: {error.message}</p> {/snippet} {#snippetpending()} <p>First pending...</p> {/snippet} {#if$effect.pending()} <p>subsequentpending</p> {/if}</svelte:boundary> And its working well when I have one async story. As soon as I add more, I see a lot of Maybe having something like Here is myplayground. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Rich is working on making |
BetaWas this translation helpful?Give feedback.
All reactions
❤️ 9
-
Quick question: wouldn't the |
BetaWas this translation helpful?Give feedback.
All reactions
-
Ah, that makes sense... |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
@elliott-with-the-longest-name-on-github why it isn't supported? I thought it was supported because of the |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
@realfakenerd SSR isn't supported yet because we haven't implemented support for it yet 😉 (I'm being a little snarky but that is the truth!) SSR is still a synchronous process, which means we can't support After this is merged as an experimental feature, we'll start work on asynchronous SSR, which will mean SSR can wait on your promises to resolve and render your components. This is kind of a huge body of work, though, as it involves figuring out when async components should be blocking/nonblocking (streaming), how to hydrate asynchronous stuff on the client, and lots of other internal bits and bobs. To avoid literally never shipping anything due to massive scope, we've opted for the two-step, CSR-then-SSR, release-as-experimental approach. |
BetaWas this translation helpful?Give feedback.
All reactions
-
@elliott-with-the-longest-name-on-github i think i get it, it kind of works but in a synchronous way, what we don't have now is the async SSR, right? 🤔 But when we get that, top level await will be possible? Maybe without needing any hint or if hint needed the way i suggested with a |
BetaWas this translation helpful?Give feedback.
All reactions
-
Yes exactly! |
BetaWas this translation helpful?Give feedback.
All reactions
🎉 1
-
Is SSR support a long way away ? …On Thu, 10 Jul 2025 at 19:08, Elliott Johnson ***@***.***> wrote: The main reason for this limitation is because SSR isn't yet supported -- i.e. we *have* to have a pending snippet to fall back to during SSR. Once SSR is supported, we can make boundaries optional, and frameworks like SvelteKit can wrap your layout in a boundary for you so that they can render your +error.svelte or (maybe, doesn't exist yet) your +loading.svelte. — Reply to this email directly, view it on GitHub <#15845 (reply in thread)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAAAGNFPGWLD7P47I42VFRD3H2MYZAVCNFSM6AAAAAB4BQKD3CVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTGNZSGMZDIMQ> . You are receiving this because you commented.Message ID: ***@***.***> |
BetaWas this translation helpful?Give feedback.
All reactions
-
https://pkg.pr.new/svelte@async currently points to svelte 5.28. Can any of the maintainers update it? |
BetaWas this translation helpful?Give feedback.
All reactions
-
No, we don't control pkg.pr.new (that would be@Aslemammad). At present, links with branch names stop being updated once there's a PR associated with the branch, I don't believe it's possible to update it on our end. |
BetaWas this translation helpful?Give feedback.
All reactions
-
... And it's released! You can now use this in Svelte 5.36.0 rather than running off the |
BetaWas this translation helpful?Give feedback.
All reactions
❤️ 2🚀 9
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
i get error running something like so:
am i missing something? i thought we could await directly within the $derived rune |
BetaWas this translation helpful?Give feedback.
All reactions
-
but there isn't a way to use the svelte:boundary within the <script> tags, or have i missed something ? |
BetaWas this translation helpful?Give feedback.
All reactions
-
<svelte:boundary> <TheComponentContainingTheDerivedWithTheAwait /> {#snippetpending()} <p>loading...</p> {/snippet}</svelte:boundary> |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
-
<svelte:boundary> <MyComponent /><!-- this component can use await in the script --> {#snippetpending()} <p>loading...</p> {/snippet}</svelte:boundary> Also, REPL site was updated to implicitly wrap the entire App in a boundary. |
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Gotcha@Rich-Harris, that's what I was asking about regarding an error more specific for this issue
And instead in our case when developing an application the boundary won't be present by default, so we'll have to add one at the root level, correct? |
BetaWas this translation helpful?Give feedback.
All reactions
-
Currently - yes |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
-
Hello guys! would this be valid async svelte? letdetails=$state(awaitgetPokemonDetails()) |
BetaWas this translation helpful?Give feedback.
All reactions
-
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
-
Oh nice! I guess the linting isn't updated yet i still get errors. Although I encountered an error where the UI wasn't loading some css/js and made some part of the page non-reactive to the point of freezing. |
BetaWas this translation helpful?Give feedback.
All reactions
-
|
BetaWas this translation helpful?Give feedback.
All reactions
-
I'm sorry if this has been asked before, but is it possible to use this feature withStreaming with promises? |
BetaWas this translation helpful?Give feedback.
All reactions
-
I tried playing with it and logged#16403. |
BetaWas this translation helpful?Give feedback.
All reactions
-
I still get
How to fix that warning? Cuse the code is working fine. |
BetaWas this translation helpful?Give feedback.
All reactions
-
This is a language tools issue, support |
BetaWas this translation helpful?Give feedback.
All reactions
-
Ah, that makes sense. Do you have a ETA? This async is such good addition to svelte, want to use it without |
BetaWas this translation helpful?Give feedback.
All reactions
-
ETA is as soon as he can get it done 😆 which, knowing Simon, is very fast! |
BetaWas this translation helpful?Give feedback.
All reactions
-
Released, make sure to update to the latest version of the VS Code extension / svelte-check |
BetaWas this translation helpful?Give feedback.
All reactions
🎉 8❤️ 1🚀 5
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Thats amazingly fast ^^, thanks 🚀🚀 |
BetaWas this translation helpful?Give feedback.