Hacker News new | past | comments | ask | show | jobs | submit login
Svelte 5: Runes (svelte.dev)
471 points by benmccann on Sept 20, 2023 | hide | past | favorite | 386 comments



This is (surprisingly) almost identical to the Reactivity Transform explorations we did in Vue: https://vuejs.org/guide/extras/reactivity-transform.html

  let count = $ref(0)

  const double = $computed(() => count * 2)

  watchEffect(() => {
    console.log(double)
  })
We started experimenting with this ling of thought almost 3 years ago:

- First take (ref sugar), Nov 2020: https://github.com/vuejs/rfcs/pull/228

- Take 2, Aug 2021: https://github.com/vuejs/rfcs/pull/368

- Take 3, Nov 2021: https://github.com/vuejs/rfcs/discussions/369

We provided it as an experimental feature and had a decent number of users trying it out in production. The feedback wasn't great and eventually decided to drop it. https://github.com/vuejs/rfcs/discussions/369#discussioncomm...


Hi! First up — not that it matters, but since people will wonder — our design wasn't informed by the Reactivity Transform. We evaluated something close to 50 designs, some of them extremely wacky, before settling on runes, and it wasn't until after that time that the Reactivity Transform was brought to our attention.

Nevertheless, it's interesting and validating that we landed on such similar approaches. While the Reactivity Transform failed, it did so for reasons that I don't think apply to us:

- $state and $ref are quite different. $state doesn't give you access to the underlying object, so there's no conversion necessary between reactive variables and ref objects (either in your head or in code).

- There's strict read/write separation. Anyone with access to a ref has the ability to change its value, which definitely causes problems at scale. It's something that React, Solid and Svelte 5 get right.

- Reactivity Transform introduces things like $() for magic destructuring and $$() for preserving reactivity across boundaries. We're instead encouraging people to use familiar JavaScript concepts like functions and accessors

- There are already a lot of different ways to work with Vue — SFCs vs non-SFCs, template syntax vs JSX, composition API vs options API, `<script>` vs `<script setup>`... on top of that, adding a new compiler mode that needs to interoperate with everything else is inevitably going to be a challenge. This isn't the case with Svelte. While both runes and non-runes mode will be supported for the next two major versions, meaning there will be some short term fragmentation, we've made it clear that runes are the future of Svelte.


> $state and $ref are quite different.

I wouldn't say they are "different" - they are fundamentally the same thing: compiler-enabled reactive variables backed by runtime signals! But yes, Vue already exposes the underlying concept of refs, so for users it's two layers of abstractions. This is something that Svelte doesn't suffer from at this moment, but I suspect you will soon see users reinventing the same primitive in userland.

> There's strict read/write separation

I'd argue this is something made more important than it seems to be - we've hardly seen real issues caused by this in real world cases, and you can enforce separation if you want to.

> We're instead encouraging people to use familiar JavaScript concepts like functions and accessors

This is good (despite making exposing state much more verbose). In Vue, we had to introduce destructuring macros because we wanted the transform to be using the same return shape with all the existing composable functions like VueUse.

> There are already a lot of different ways to work with Vue

This is largely because Vue has a longer history, more legacy users that we have to cater to, so it's much harder to get rid of old cruft. We also support cases that Svelte doesn't account for, e.g. use without a compile step. That said, the default way with a compile step is now clearly Composition API + <script setup>. Reactivity Transform also only really applied in this case so the point you raised is kinda moot.

Separate from the above points, the main reason Reactivity Transform wasn't accepted remains in Runes: the fact that compiler-magic now invades normal JS/TS files and alters vanilla semantics. Variable assignments can now potentially be reactive - but there is no obvious indication other than the declaration site. We had users trying Reactivity Transform on large production codebases, and they ended up finding their large composition functions harder to grasp due to exactly this (and not any of the points raised above).


In Svelte 4, the let counter = 0 syntax is already reactive by default, a feature enabled by the compiler. This has been the status quo for Svelte prior to the rune change. The introduction of the $state(0) rune actually provides more hints about its reactivity than before, and restore the original meaning of let counter = 0 (in rune mode). While it's true that the compiler's "invasion" into JS/TS syntax has been a point of discussion, this invasion has been happening for a while, and the initial shock wave has been well-absorbed by the community.

Interestingly, the new changes could be seen as a retreat from that initial invasion, likely triggering a different response from the community. In fact, the resistance I've seen (and my own as well) has been in the opposite direction—it's hating this retreat, complaining Svelte becoming less "magical." and more close to regular joe Javascript.


I’m specifically taking about non-component context, i.e. plain JS/TS files.

Previously Svelte was able to get a pass on this because magic only happens in svelte files - but in the future, any JS/TS files in a rune-enabled Svelte project will technically be SvelteScript, this never happened before and I doubt the community has already “absorbed” how significant this change is.


This is a really great point. I think something like a `.svelte.js` file extension is warranted here. This would key tooling to when it needs to interpret runes, and makes it clear which files in a codebase require the svelte compiler. These files clearly aren't just js/ts at this point, but I think its fine as long as they're marked as such. Custom react hooks, for instance, aren't usable outside of the runtime but can be transpiled without issues by esbuild/tsc and interpreted correctly by a js/ts language server.

As long as it's marked separately from js/ts I don't think its a huge issue though. Svelte files already have script tags that aren't completely vanilla js/ts.


Hi Evan You! (Hi from wentin) It's great to see you here in this thread. It's such a wonderful gesture for the open-source community to collaborate in this manner, by sharing valuable lessons learned the hard way.

It’s intriguing to see where the Svelte exploration will lead. Will it face disapproval or achieve success? While I agree that both implementations have arrived at the same place (almost serendipitously), their origins differ. For Vue, it's about adding the syntactic sugar by dropping .value, making it less explicit and more magical. In contrast, Svelte made the change to make things more explicit and reduce the “black magicness” from the svelte compiler, and bring it more similar to javascript. This difference might trigger totally different reaction, time will tell.

Looking forward to more insightful discussions!


All of this looks like MobX


>All of this looks like MobX

Shhhh. Don't tell the Vue/Svelte community that they're just reinventing the React ecosystem on a 5 year delay. It will spoil all of their fun.


Michel and I have been internet acquaintances for years, and we've even talked about this stuff IRL. MobX certainly isn't something we just somehow never learned about!

But anyway: it's absurd to compare this with React+MobX. MobX replaces useState, sure, but you're still re-rendering entire components on each change (which is why MobX explicitly recommends that you break apart your app into many small components, regardless of whether that's a boon to readability and maintainability.

By contrast, Svelte (and Solid, and other frameworks) understand signals on a much deeper and more optimal level. They're really not the same thing at all.


> MobX replaces useState, sure, but you're still re-rendering entire components on each change (which is why MobX explicitly recommends that you break apart your app into many small components, regardless of whether that's a boon to readability and maintainability.

This is not true. MobX has had an `<Observer>` component for years now. You can be as fine detailed as you wish with rerenders in a larger component.

https://github.com/mobxjs/mobx-react#observer


MobX does not rerender entire components.

Unlike Redux at that time (~2016), it was a first approach where minimum rendering was happening effortlessly.

You can have a list of components where each component references a bit of global state and rerenders only if that bit changes, even though the list might have enlarged or other elements changed.

Last time I used it (2016-2020), they used all of the tricks of the trade, get, set object attributes, dropped decorators and it still worked the same.


Notice that you just said "You can have a list of components _where each component_ references a bit of global state". In other words, in order to avoid re-rendering everything, you need to have a component for each item in the list.

In React, the component is the unit of re-rerendering. MobX can't change that fact. The only thing you can do is work around it with hacks that imperatively update the DOM.


Yes, this clarifies what you've meant and I can see the case that is not covered with MobX+React but I assume it is covered by Svelte's runes.

You're saying that I can have the whole app written in a single file without any separation and the updates will still happen only in the place that needs it.

That makes sense. With MobX, this could be done but not with React and not without a bunch of boilerplate that obtains html elements that are referencing the state.


>With MobX, this could be done but not with React and not without a bunch of boilerplate that obtains html elements that are referencing the state.

It's trivial with MobX. The Observer component essentially gives you an "inline" component wherever you need reactivity, without the need to actually componentize.

i.e using a MobX State Tree store:

  const store = types.model('Store', { value: types.string }).create({value:'But I will!'});

  const Page = () => {
    return (
      <div>
        <div><h1>I won't rerender</h1></div>
        <Observer>
          {()=> { 
            const { value } = store;
            return (
              <div>{value}</div>
            )
          }
        </Observer>
      </div>
    )
  }


Cool, did not know that, last time I seriously used MobX was on 2016 primitives. But I see it works similarly to before. All of the accesses will be figured out during the first render.

Observer component is so simple. Just a deferred function invoke. Could have been done with 2016 primitives too.


MobX is not that known unfortunately. It kills me inside.


I guess we are all waiting for Rich Harris to step in and comment on this one. I'm sure he has followed this Vue experimentation and has a clear argument to make. At least I hope so.


Based Vue


Funny, I also thought of Vue immediately.


This is basically what Vue and Solid do, no? Same sort of state and derive/computed variables, it seems like.

Also, I will never understand why people like reactive signals. The article even quotes "Knockout being right all along" which, no, reactivity and two way data binding creating a spaghetti mess of changes affecting other changes all over the place unless you're really careful is why React was made in the first place, to have only one way data binding and to re-render the entire page in a smart way. React will soon get its own compiler as well which will made regenerating the DOM even more efficient.

It's like every other framework is slowly rediscovering why React made the decisions it made. I am assuming it's because the users who are making these frameworks now have not used or do not remember the times where "signals" were called observables, or the usage of Rx libraries, and how having too many of these would cause you to lose your mind debugging the intricate webs you inadvertently spun.


Yes, Vue and Solid — like Knockout — use a dependency tracking mechanism. Back in the day it was called `ko.observable`, nowadays we call them signals.

That's the part Knockout was right about. It's absolutely true that you can mishandle them and create a spaghetti mess, _if your design allows it_. Svelte 5 doesn't — it uses signals as an implementation detail, but in a way that prevents the sorts of headaches you're describing.

Signals and observables (e.g. RxJS) are related but separate concepts. The framework world is converging on signals as the appropriate mechanism for conveying reactivity — even Angular (which has historically been most closely tied to RxJS) is moving in this direction. I promise you it's not just a mass delusion.


Not everyone has teams of perfect developers given all the time they want to make their perfect frontend app. Most of us deal with average teams where half the devs are at or below par while managing very tight deadlines. The spaghetti from everything in the whole system mutating always comes back to bite.

You call signals an "implementation detail", but if someone doesn't know that's what they are, then they'll wind up doing very bad things. This means they either aren't just an implementation detail or they are a hyper-leaky abstraction.


What I mean by 'implementation detail' is that you _literally can't get a reference to a signal_ in Svelte 5. This alone prevents people from mutating things in unexpected ways.


> You call signals an "implementation detail",

You haven’t even seen Svelte 5 yet, I don’t think it’s fair to say its internals will create trouble yet.


> Not everyone has teams of perfect developers given all the time they want to make their perfect frontend app.

Yes, but having gone through this at previous companies, the average/non-front end specialist developers definitely had an easier time understanding 2 way binding ala Knockout, MobX, Svelte, etc. The Redux style stuff was only pushed by the frontend brainiac types.


More like so easy to shoot themselves in the foot. React’s one-way data binding philosophy is defensive position against spaghetti code.


MobX with React is quite fine, haven't seen the problems you describe tbh


Pretext: I'm a backend developer that often needs to stare into the abyss that is frontend.

I used to say these same things about reactivity. It was highly confusing to me years ago; as a backend developer doing frontend tasks was always reaching outside of my cookie jar and testing the boundaries of what I knew vs what I thought I knew. Many headaches ensued. That said, using Vue 3 and Svelte 4 has made utilizing stores and reactivity a lot more obvious in my opinion. Things render when they're supposed to and my applications remain performant. As a non-frontend person, I mainly like the APIs that Vue and Svelte bring. In React I'm almost always switching to class based components for what I can do in the compositional API in Vue or what's natively possible in Svelte. That brings a lot of repeated code and doesn't look as clear to people not as familiar with React.


Seems like your comment cut off there, but if you're using class components in React, there will be repeated code, yes, which is why hooks were invented and why they enable you to reuse such code.


And lose most of the 'reactivity' since you'll now be doomed to manually track your own dependencies everywhere.


Can you explain why that is?

I find hooks are flexible enough that I tend to be able to implement more sane and manageable reactivity, not the opposite.

Maybe I’m misunderstand your issue, though.


I’m referring to the dependency array you pass into hooks, and any hook being able to trigger updates.

With classes there was no manual dependency tracking (except comparing old props?) and all re-renders were triggered by state, context or prop changes.

Not making a judgement either way, just stating the trade-offs.


The dependency array strikes me as far safer and more reliable, but it has been a bit of a foot gun for a lot of people. I still encounter code where dependencies are missing, which virtually never makes sense or should be intentional. I suppose the compilation step that’s proposed would address that, but it’s yet to be seen.

There does seem to be an aspect to modern react where it’s great if you’re willing to put in the effort to figure out all the quirks, but for everyone else who just wants to get things done/has other priorities, it’s a bit of a minefield at times.


> create a spaghetti mess, _if your design allows it_. Svelte 5 doesn't — it uses signals as an implementation detail, but in a way that prevents the sorts of headaches you're describing.

Care to elaborate or do you have a link to a blog post explaining further?


I'll try — I'm currently fielding a zillion messages so excuse brevity!

Basically, you can only modify state _where it's declared_. If you want to allow the 'outside world' to modify that state, you need to expose a function that does so. This is unlike cases where you're passing around an observable object where anyone with a reference, which they need for reading, can also write to it by doing `thing.value += 1`.

This is something Solid gets right — you can only change a signal's value if you have a reference to its setter.


> fielding a zillion messages

Surely you mean signals? :)


Thanks for the reply, Rich. It seems that, given a large enough codebase, that sort of spaghetti mess will emerge on its own, as not everyone will be so thorough. Granted, I haven't used runes and based on your blog post here, I'm not reading where it would prevent such headaches as there's not much mention of that there, so I don't know exactly how it'd work, but just based on my experience using things like Vue and Knockout in the past, it wasn't too clean.

I was just mentioning in another comment how Rust has a similar problem where, as in C, you can mutate variables via pointers anywhere in the codebase, but Rust counters that by having a borrow checker that explicitly tracks the changes made and makes sure that only one user can modify a variable at any one time. An analogous concept might be quite interesting to implement in all these signal based frameworks as well.


> An analogous concept might be quite interesting to implement in all these signal based frameworks as well.

Which is what Svelte 5 is doing with its compiler.

> […] given a large enough codebase, that sort of spaghetti mess will emerge on its own, as not everyone will be so thorough.

LOL! You've just described React projects! Yes, of course you and your team are wonderful and have all the FP experience, so obviously this isn't an issue for YOU.

Most React codebases however turn into big balls of mud. Enormous balls of useMemo-y, useEffect-y, re-render the world-y, spaghettified mud without even any compiler-enabled guardrails that get re-written every 18-24 months but "this time we'll do it right."


I think the true lesson here is that if you fundamentally dislike a programming paradigm, then everything written in it looks like a big ball of mud.


That's completely true. A concede the point.


Based on your profile and comments, it seems you have some particular grudge against React, so I'm not sure I can convince you of anything React related that you have not already convinced yourself of. Nevertheless, I (nor you, it seems) have not used Svelte 5 yet so I cannot judge, just that based on my, yes, personal experience, 2 way data binding based frameworks create messes. Even though you can shoot yourself in the foot in any language or framework, some are simply better at preventing it, such as C versus Rust, as I analogized.


I’m not expert in Svelte or React and have been following your conversation. You stress the point that two-way data binding creates mess. I tend to agree since I did my share of desktop programming long time ago. However, I don’t see how React solves the problem fundamentally. When you combine React with Redux or hooks IMHO you get exactly the same thing. The big difference is syntax that makes it easier to reason how view would re-render in response to change. But in a large enough project I can see how this became less and less true as distant modification trigger cascades of model updates/reducers/hooks and result in an unexpected behavior.


I always found observables need better nomenclature.

I know its not anyones fault (RxJS is amazing), but it does seem to invoke some gray area in the brain, thinking observables would do more heavy lifting around change tracking of inputs / sources, when its not that straightforward. They more rightly should be called SubscriptionStreams maybe

I think its always been somewhat poorly named, based on how often I've had to explain the concept to other developers.


Huh? It's called observable because it can be observed (that's what "-able" means). If it were actually meant to observe something (as you say), it would have been named "observer." But it's not - it's the callback that's the observer.

Also observables are more like streams than arrays.


I don't think I'm entirely out of band to say there could be a better way of naming them, like why not call them SubscribableStream.

Saying its an observable invokes a messy gray area in people's brains. I know this because I've had to explain observables to co-workers more times than I can count in my career (I'm a big fan of RxJS, I didn't mean what I said as a dismissal), and I like them for async work vs promises in many many cases, but the nomenclature does not invoke easy understanding


Because RxJS made at least one huge mistake: it made its observables lazy.

When does it start? How do you deal with oversubscription? Late starts? Double subscriptions?

On top of that streams are always a pain in the butt to debug.

The fifteen million obtuse methods/operators didn't help either (I see there are significantly fewer now).

And to remind you: it took the author of RxJava several months to understand the programming model: https://twitter.com/dmitriid/status/811561007504093184


Maybe it would be easier for you (and your colleagues) if the function to "observe" observables was called... observe, instead of "subscribe ?


not particularly, I think it would make it more confusing.

When I break it down to folks explaining its stream processing over iterables or async work and you subscribe (and can unsubscribe) a pipeline that runs over that stream, people get it quickly.

When I say you can "observe a stream" people start getting other connotations, for some reason. I have ran into this over and over and over. Smart people too, not talking about just juniors here


Indeed !

`observers` do exist in RxJs by the way: https://rxjs.dev/guide/observer


I think it is definitely a learning curve thing: when teaching/learning Observables it can help to use a name like EventStreams or PushStreams. (An RxJS "competitor" is named XStream for this among other reasons.) Observable is a simple English word and the meaning of the English word is complicatedly "shadowed" by what the tech means by it.

On the other hand, on the other side of the learning curve, Observable is a great name. It's a simple English word that you can say and write a million times (and you will need to when working with them) without extra PascalCase or things like that. Also, when you look at the overall "family" that Observables fit into, it is a name that fits the family: Iterable/AsyncIterable ("PullStreams") versus Observable ("PushStreams"). (In .NET LINQ the family uses Enumerable/AsyncEnumerable and also extends to Queryable and the strangely named but makes sense in context Qbservable. [QueryableObservable; often pronounced like "cube-servable".]) As a family of tools that all generally work well together and are essentially related in a "four quadrant" way, it helps that they all have a nice -able names that sound related.


Qt was always right.


Yes, the API is very similar to Vue's. $state is ref/reactive, $derived is computed, $effect is watch/watchEffect.

> why React was made in the first place, to have only one way data binding and to re-render the entire page in a smart way

This last part is why Vue and now Svelte didn't adopt React's model. Yes, reactivity and two-way data binding give you enough rope to thoroughly hang yourself, but it also gives you a very explicit picture of how and when components will update. React, on the other hand, expects you to trust its smart algorithms, which definitely removes a lot of the pain from day-to-day coding but also makes troubleshooting performance problems harder.

I see the distinction as similar to GC languages vs something like Rust: if all you need is to have an app that does a job and you don't care about how it does it, React is a good choice. If you need to have control over exactly what will update and when, Vue's model gives you fine-grained control over updates that's hard to achieve in React.

EDIT: And with that in mind, it's obvious why Svelte, which prides itself on being lean and fast, would avoid the React smart-but-complicated runtime model in favor of the Vue model.


React is the pragmatic answer.

Most devs are of average talent and will hang themselves and everyone else with the stateful webs they weave. Even with careful PR reviews, these things have a way of sneaking in and becoming permanent hinderances.

Performance hasn't been a dealbreaker in most JS apps for years now. What HAS been a problem is getting good code out the door as fast as business needs. MOST React code is disposable based on the whims of the company. The bits that aren't disposable are used enough to justify having them designed and maintained by your best devs who should also have the skill to write performant code.


Counterpoint: https://ericwbailey.website/published/modern-health-framewor...

Performance does matter to the people who depend on our products. Can we please stop throwing people under the bus in the name of churning out more crap?


The real-world performance difference between Svelte and React outside of the tiny benchmark apps isn't very much. The fact that React can prioritize rendering of some things over others means that it can be slower overall, but still feel faster to users.


> The real-world performance difference between Svelte and React outside of the tiny benchmark apps isn't very much.

I don't know, IME it's pretty easy to run into bottlenecks with React. To resolve these, you have to spend time optimizing data flow and preventing unnecessary re-renders, and it can be really difficult to trace where an update originally comes from. Svelte and other reactive frameworks give you good performance by default, so it's very unlikely you ever have to do this in the first place.


I agree with you on this.

I never had to deal with `useMemo` and `useCallback` equivalents in Vue apps. The framework is implemented in such a way that it can let me focus on the task at hand. If I have errors in Vue apps, they are logic errors not "you didn't cater to the framework's rendering model" errors


What is the actual difference between React and Svelte? People don't actually know, but this isn't like the old days where React offered 10x (or more) performance increase over AngularJS without even trying to optimize. We're arguing "better" using very slim margins.

Looking at the geomean benchmark suite everyone uses, it's 1.33 for Svelte 4 and 1.67 for React. That's a mere 0.2x difference and most of that is due to row swapping performance from React iterating lists of thousands of elements -- hardly typical in most apps.

Your team will make THOUSANDS of decisions in your app that will make WAY more difference than 20%. Incorrectly nest some loops in your data processors and the performance difference will almost instantly outshine the update differences.

And all of this is without mentioning that the React team is working on a compiler that will offer many of the benefits you get from the custom Svelte compiler (though TBH, I dislike needing a special compiler for custom JS).

EDIT: I'd also add that the Stage 2 record/tuple proposal will make comparing props many times cheaper and should give a massive performance boost to React as this comparison is one of the things that slows it down.


The statistical performance difference is somewhat irrelevant. The measure should really be the extra time spent optimizing your code, and that value can be far higher in React than it is in Svelte. It doesn't matter if the raw performance difference is only 20%—if that 20% means the difference between a smooth UX and a janky experience, it's still extra work you have to do with React that you don't need with Svelte.

Now, I'll grant you that it really depends on the project. Building a simple admin interface? This probably won't matter. But for an interactive dashboard with dynamic charts and data being updated in realtime? You're almost certainly going to spend some time making it fast. And optimizing React code is currently a pretty poor experience.

For the record, I'm not arguing that the performance difference alone makes Svelte worth using over React. In fact, I think the developer experience with Svelte is far better, which is (in the majority of cases) a much better reason to use a framework. I just want to dispel this myth that React is so fast that you'll likely never have to think about performance, because I've had to do a non-trivial amount of optimization work on just about every React codebase I've worked on.


> What HAS been a problem is getting good code out the door as fast as business needs. MOST React code is disposable based on the whims of the company.

I know you're right; but this still deeply saddens me. I want well crafted software. I want the code I write and the code I depend on to be made in a way that holds reverence and honor for the craft of software engineering.

I don't want to be running crappy, badly performing javascript made by average talent in react, that exists to serve someone else's transient business needs. Gross.


Gotta love how people trot out this crap on Hacker News, a place they ostensibly self-selected into.


I don’t know about you, but I have bills that need paid. I’ll clutch my pearls over something else


I have a friend who's a car guy. He bought some fancy Mazda that he just adores and he takes to the track sometimes.

He's not pearl clutching. He's in love with that car. He keeps it immaculate and he has a sparkle in his eye when he talks about it.

Some people are the same with furniture. They buy super expensive, custom stuff and look after it for decades. Not me! All through my 20s I didn't care at all and my various homes were full of cheap ikea furniture. I had bills that need to be paid, and why should I pay more? Most of it is probably in landfill by now.

I'm not an expensive furniture guy. And I'm not an expensive car guy - I don't even own a car. But I am into software. Software is kind of my thing. When software works fast and well, when its clean, reliable, tested and memory efficient - its the best. I know deep down everything is right in the world.

And, obviously, I hate disposable, cheaply made software. I hate when software runs slowly. I hate seeing my expensive computer working hard to do basically nothing because of lazy code. And I hate running into stupid, avoidable bugs. I don't want to create work like that. And I don't want to use with software like that. When software is laggy and unreliable, my skin crawls and I feel disgusting.

Intellectually, I recognize that there's a place for the cheap ikea furniture equivalent in software. But craftsmanship matters to me. And I personally, hate bad software and I don't want it on my computer.

Does that make me a pearl clutching, elitist snob? Sure, whatever. But I'm done acting like I'm sorry for what I like.


My comment was meant to be a more humorous jab at my own efforts as a software engineer but in re reading I think it came across as rude and I apologize.

I think if you feel strongly about something you should defend it!


Was not funny at all FYI. Trotting out overused clichés about how little pride you have in your work is never funny.


Average devs struggle with useEffect, useCallback, useMemo and other hooks. If anything, Svelte, Solid and Vue are significantly easier.


it may have been true in the Knockout days, however signals in Solid is very very similar in feel and reasoning to React hooks.

It makes it straightforward to reason about, because you aren't dealing with globals, undeclared deps etc. like in the Knockout days


I've seen people hang themselves with (or should I say on?) hooks.

Performance was the main issue because one incorrect usage of a hook can make a huge difference.


You make it sound like react is a dark box with a lot of magic behind the curtains, but I always found the react model very easy to reason about. Modifying state is explicit and is the only thing that can trigger a rerender. These rerenders can only happen down from where in the tree the state change happens.


Let's be honest: the state (see what I did there?) of React state management is a dumpster fire.

https://fe-tool.com/awesome-react-state-management

That's an article listing the top 18 state management libraries for React.

18?!?

React devs can't even agree on a common development model for state, but you think it's explicit and very easy to reason about?

Folks don't adopt utility libraries for things that were already easy to reason about on their own. I'm glad you've found peace with React's basic notion of state, but it's a far cry from optimal. And the "state ecosystem" of React is a dumpster fire. Layers upon layers of madness that acolytes peer through and proclaim insight.

> These rerenders can only happen down from where in the tree the state change happens.

Yes, after it has DIFFED the whole tree to see where the changes occurred in the first place. Madness. Layers of utter madness.


React isn't a state manager and why should everyone be forced to use the one "blessed" manager?

Despite there being so many, only a handful (redux toolkit, jotai, zustand recoil, and mobx) see much real-world use and they are basically just 3 approaches (reducers, signals, and directed graphs) with varying levels of complexity and features.

> Yes, after it has DIFFED the whole tree to see where the changes occurred in the first place. Madness. Layers of utter madness.

Not true. It only needs to diff the leaves of the part that changed and some of those sub-trees can be skipped too if they are functionally pure (or uses shouldComponentUpdate). This is how they reduce complexity down from O(n^3) to something generally closer to O(n)


I use vue, so I’m assuming that is the “signals approach”. I use pinia btw

Can you explain how all 3 state mechanisms you mentioned, and how they are different ?


I’ve written a lot of react apps (first used it in a hackathon in 2014) and this list is really just fluff. hooks + context make all of these libraries pretty much unnecessary for most react apps as they are not that complex

I think the more glaring criticism is the lack of any unified component library. The amount of different Button implementations alone is astounding


I agree on both points. I used to quite like Redux but, between NextJS simplifying the page model and hooks/context being a lot easier for CRA-style apps, I just don't need them anymore for the sort of things I do.

The real kick to the shins is that React Server Components did a number on most component libraries, too. I've been forced to go to Tailwind (and DaisyUI, which is pretty nice) just so my stuff doesn't require 'use client' all over the place. The end result will be way better, it already is when you actually can get there, but right now it's annoying and awkward.


That was something that React Server Components definitely got backwards. The default state of the world before RSC was client components. If a mark is needed it should have been "use server" for the new style of components.


I don't mind that, because I think server components should be the default. They're better. But the profusion of CSS-in-JS solutions (which always seemed unwise to me) take it on the chin because of it.


> hooks + context make all of these libraries pretty much unnecessary for most react apps as they are not that complex

To be fair, context is not a state management tool [0], an article by acemarke, the Redux maintainer. It does work as a dependency injection tool and for many people, that's enough, but it's not a true state management tool.

[0] https://blog.isquaredsoftware.com/2021/01/context-redux-diff...


React context is is just a way to bridge props deep down a component hierarchy. By combining it with an appropriate hook you can almost obtain the effect of a state manager like redux. There are limits to this however; being just a way to pass props it doesn't give you any fine control over reactivity


Yes, that is indeed what the article I linked says.


I did specify hooks + context, not just context. Hooks + context together can be cobbled together into an adequate state management solution for most apps, this article even agrees with me. So not sure what your point is lol


I just write my first fairly complex react app. As a mostly backend/tool Dev with good knowledge of functional programming I agree with this. I could solve almost any problem using hooks + context and memo. I briefly considered using Redux but I quickly realised that a few changes in certain components would take care of most of my state management problems


> That's an article listing the top 18 state management libraries for React.

> 18?!?

I mean, the top library has more weekly NPM downloads than every other library in the list combined.

> Yes, after it has DIFFED the whole tree to see where the changes occurred in the first place. Madness. Layers of utter madness.

That is not how rendering works in React.


React is honestly how I used to write my code in jQuery too, for some pages that had a lot of state. Basically, just like in game dev, I had a render() function that I'd call at the end of the file that would re-render everything. The pattern itself is very easy to understand, re-rendering efficiently is the hard part, but for React users today, that's an implementation detail.

Hooks are also very interesting, they're basically functions that run at specific times, or that is to say, they're `f(...parameters, state)`. They hold state inside the function, sort of like a closure.


Indeed, seeing hooks as closures helped me to understand how they are use for state management. It's really a "poor man's object" with all the advantages of FP in terms of reasoning about state changes, lack of side effects etc.


Same here. For complex UIs, I almost always had my own 'render()' function.


I mostly agree with you.

Unfortunately, many React apps use Relay (another Meta product) and it opens up a world of “magic” that is sometimes a real pain to reason about.


What do you mean by "many?" While I like Relay, I've almost never seen Relay used in the wild. It's sad as it's quite an elegant concept; just as you define your props for your React component, you define your "props" coming from the server as well, through the GraphQL notation. I've been looking at ways to combine both concepts so that there is no client- or server-side state at all, it's all just state, from a cache that determines whether to refetch from the server or to keep the state local.


Maybe it's isolated to me and my work here on this repo:

https://github.com/coralproject/talk

I agree that Relay CAN be simple, but it isn't for what we do. Have a look at this ReplyListContainer and its nested Relay logic. I didn't originally write this, but I can see what they were trying to do and how Relay made it difficult for them. Your thoughts are welcome, I won't judge you for being critical of our code and welcome any other Relay dev's opinions.

https://github.com/coralproject/talk/blob/develop/client/src...


Relay tries to solve the problem of: let a component define its (server) data dependencies. It indeed does this with more magic. But it's not exactly the same problem and you can't really fault react for it. It's also a problem other frameworks don't try to solve.


Now if only we had an analogous borrow checker in Vue and Svelte so that we don't hang ourselves with 2-way binding. That might a good research project, actually.


React & redux both come standard with tools to dynamically observe behavior. A flurry of updates is easy to pin down & fix.

Static analysis seems like a nice to have. All in all I class this category of concern as very far down the list of concerns, one way or two way. Yes bad things are possible. But the martial attitude that oh no people will do it wrong this tech is horrible is, in my view, actively harmful.

99.99999% of times it goes great. We don't need to make coding environments were bad things are impossible.


> 99.99999% of times it goes great.

I'll disagree with you on that. I've seen and used enough 2-way binding in various projects to know that even the best of devs can create tangles of effects everywhere. At some point, you gotta blame the tool for having footguns, which is why Rust was created over C and C++, to solve such footguns. In the same vein, something like that should be made for frontend frameworks too.


But have you used 2-way binding with a more modern framework? Or are you still hanging on to your experience with a defunct framework like Knockout from over a decade ago?

And don't get me started on React's "put all the logic you want in our templating language that doesn't even target HTML5" elephant-footgun. Oh! Sorry! Forgot that React's footguns are aKeats elegant and reasonable while everything else's footguns are dealbreakers.


> And don't get me started on React's "put all the logic you want in our templating language that doesn't even target HTML5" elephant-footgun.

Sorry, but how is JSX a footgun? I have a lot of issues with React, but JSX doesn't even come close to making the list.


You obviously keep the amount of JS logic to a minimum in your templates. I have encountered many React codebases that did not do this.


There was/is a state management lib called Mobx that was released years ago and was usually combined with React. It was kind of reactive, very easy to use and fast. It normally only updated the components that was effected by a state change.

It was a bit sad that it didn't get more popular and possibly improved. Some devs liked it but we were a minority compared to those who liked/used Redux.

One strange thing they did was to release a new "version" called Mobx State Tree which was very different. It had a great api but was different and slower.


I'm replying to you, but I'm asking the room: what, if anything, stops vue3 from compiling down to pure JavaScript like svelte does and reaping the speed benefits?


I think the main thing is the existence of alternatives. Svelte is cool, but it has the key flaw that the more Svelte you write, the more compiled code appears - generally, Svelte compiles to a size somewhat larger than the original source file.

For Svelte as an "island" tool (i.e. for building islands of interactivity in otherwise static pages, like, say, graphs for the New York Times), that's not a problem, because the extra generated code is made up for by the lack of a bulky runtime dependency. But if you scale that up to complicated SPAs - which has been Vue's main stomping ground - you can end up shipping larger files with Svelte than with other small frameworks.

That said, SFCs in Vue are an ideal source for compile-time compilation, and my understanding is that they're heading more down the route of SolidJS. SolidJS has a similar goal of using a compile step for optimisation, but it leans on its signals library implementation much more heavily, which means the compiled code tends to be much smaller, but you also need to include a runtime. (In practice, there's not much size difference between Svelte and SolidJS at all, but it shows itself at the more extreme ends of very small components and very large apps.)

Vue already has a runtime that's very similar in some ways to Solid's (read: it's all signals, baby), so adopting the rendering ideas from there is an obvious next step. That should drastically speed up rendering, as well as reducing bundle sizes significantly. They've already demoed this a bit, but I think it's not fully released yet - they gave a name for the new system, but I've forgotten what it's called.


> the more Svelte you write, the more compiled code appears - generally, Svelte compiles to a size somewhat larger than the original source file.

This is one of those things that's more of a problem in theory than in practice, but nevertheless it's worth mentioning that Svelte 5 output is _much_ smaller than Svelte 4 output.


I assume that the Svelte 5 output is smaller because more stuff is being handled internally by signals, rather than the compiled output. Does that mean that the shared "runtime" code is larger, or have you just managed to shrink everything down here?

I'm very impressed by this stuff - I'm still not sold on the implicit reactivity, but I'm really excited about the pressure this is putting on the ecosystem as a whole and where that's going to go.


This is exactly what I was looking for, cheers.

Looks like early experiments were called Vue 'vapor'


What is the difference between $derived/computed and $effect/watch?


I don't know about in Svelte, but in Vue watch is for taking some sort of action when things change, while computed is meant to return a value.


I recently took Solid for a spin and I found none of that 2-way data binding mess you complain about. To be fair, I think you’re assuming is has behavior that it doesn’t.

Eg if a form input changes, that change triggers an onChange and in a handler function, you can let the change just flow through the data layer (ie through a signal or a store, which is just a hierarchy of signals). This then updates the input, but it already had that value so nothing happens. It’s pretty much the unidirectional loop that React people love to talk about.


Sorry, I should have been more clear, I was talking more about Vue and Svelte rather than Solid, which explicitly says they don't have 2-way binding due to learning about how dangerous it is and how React doesn't have it: https://www.solidjs.com/guides/faq#why-can-i-not-just-assign...


These discussions are so tiring.

React has as much two way binding as vue - in vue v-model is just syntactic sugar for setting up event listeners and setting the value on an input element.

Per the docs [0]

<input v-model="searchText" />

Becomes

<input :value="searchText" @input="searchText = $event.target.value" />

It's such a small thing that it's crazy it's being discussed this much.

[0] https://vuejs.org/guide/components/v-model.html


React has no data binding at all, let alone 2 ways.


What you’re talking about is unidirectional data binding, and what you’re replying to specifically mentions its failure to scale with complex applications.

It’s not the kind of problem you can appreciate when taking any framework for a spin with a form input.


No, what I replied to said that about 2-way data binding. React also (just about) forces you to do unidirectional data flow, just like Solid.


> It's like every other framework is slowly rediscovering why React made the decisions it made

Nope. More like every other framework is slowly rediscovering that observables and dependency tracking offers the best DX and most of the innovations that React introduced have better alternatives.


Yeah, I have no desire to go back, regardless of "performance" gains. React keeps me sane and it's fairly simple to keep it performant.


I have a similar feeling. I keep up to date on changes to these other frameworks but in my work we've never run into React performance issues that couldn't be fixed by approaching things with good principals. Signals are brought up in convo every now and then as an approach to fix an issue, but stepping back we always seem to find a better solution but just re-writing bad React code. I'm sure if you're on a certain scale of users or extremely custom UI you could run into circumstances where signals would help you, but for our system that serves hundreds of thousands a day, we don't need them yet.


I've worked on react codebases, and non-react codebases. Maybe it's a coincidence, but I find the react ones in general to be harder to debug. And not great for my sanity either.


My experience is it tends to depend on the folks who made the application. Regardless of what framework you chose, they can't save you from yourself in a lot of cases.


second this, plus its mature ecosystem, which is very valuable for the long term.

though, the SSR madness movement including React concerns me, everyone tries to mix CSR and SSR into one now, which makes things way more complex than it needs.


I could not agree more. There is a huge push to make both side of the rendering “the same”. Next.js is pushing it really hard for their edge level rehydration.

I get it, it gives you flexibility to hydrate the view as close to the user, as late as possible. That sounds cool, but I wonder how many folks really use it and how much you pay for not clearly defining where and when each bit is happening.


As someone who tries to limit their client-side JS usage through uBlock/uMatrix, websites that aren't just blank <div id="root"></div> with JS disabled would be nice to see, which is why I like React Server Components. Of course, if it's a useful enough web app, I'll enable JS, but if someone's writing a blog, ecommerce site, or really any site that may not require a full blown SPA. Sending minimal unneeded JS to the client is best, as it saves bandwidth and battery, as well as feeling faster due to loading faster, in my opinion.


I agree with you. It seems wasteful to spending a whole "wait around period" for that <div id="root"/> to eventually load once the js gets around to it.

I also agree that server components make a lot of sense to solve this problem. It's the obvious optimization (and in some ways, a good re-learning from past wins with PHP, Ruby, etc).

I also still feel we have a long way to go before it becomes elegant and obvious how all this is working. It hasn't become standard in the way that everyone easily groks the concept of how it all works and expects it everywhere on every web stack.

Still waiting to see if we go down another rabbit hole of complexity, or see more cautious and careful improvements towards an easier, more maintainable environment.


You can also achieve this with Astro, which will render your React islands statically and also enable client-side JS for interactivity / progressive enhancement when the client has JS enabled


True, however it's wrapped up in a nice DX in NextJS. In Astro, if I have multiple components that need React interactivity, are they all separate React apps basically? Or are they the same but with different roots? In NextJS, they're the same and Next can intelligently figure out which to render server side and which to render client side.


If I understand correctly, the React runtime is shared between islands (and you can share state between them if necessary), but they're also pre-rendered for their initial state at build-time.

So you can't do as much in Astro as you can in Next.js, but it will definitely scratch the itch of compile-time rendering.


The "ecosystem" is taking vanilla js libraries that work without modification in other frameworks and making them work with react via a wrapper. The react ecosystem is nothing.


I disagree—I regularly find (and use) libraries that are built specifically for React and don't have a vanilla JS analog. As someone who uses Svelte on personal projects, I actually find this really frustrating and wish most of these libraries were just wrappers over some core functionality built without React.


React Three Fiber is a good “wrapper” library that proves the ecosystem is far from “nothing”

https://docs.pmnd.rs/react-three-fiber/getting-started/examp...


I know what react three fiber is and I find the idea of using xml for 3d rendering to be terrible.


> It's like every other framework is slowly rediscovering why React made the decisions it made.

Definitely there is convergence in DX now. No need for everyone to admit one or another framework was right first or not - that is just creating antagonism or negating people lived experiences and innovation. But I do find it pretty weird that this convergence is happening. Initially I thought it was diverging with svelte but it seems to be reserving direction.


> * But I do find it pretty weird that this convergence is happening. Initially I thought it was diverging with svelte but it seems to be reserving direction.*

Convergent evolution [0]. Just as a shark, dolphin, and ichthyosaur all have the same body shape which is efficient for swimming and hunting in the water, so too do technologies converge when the problems are all the same and the solutions are understood, only as humans we can learn from each other rather than randomly mutating our codebases [1]. It's the same reason why we see a lot of languages starting to adopt more functional features such as not using `null` and having exhaustive pattern matching, such as Rust (from OCaml), Dart 3, recent versions of Java, etc.

[0] https://en.wikipedia.org/wiki/Convergent_evolution

[1] https://en.wikipedia.org/wiki/Genetic_programming


But for every similar shaped organism, there exist as many, if not more dissimilar ones, either alive or preceding. Convergence is not a given, and for every instance of convergence there are just as many divergences, even when appearing similar on the surface. For each degree of software 'carcinization' [1], I'd contend there are as many evolutionary offshoots going against the grain.

[1]: https://en.m.wikipedia.org/wiki/Carcinisation


That's true, but perhaps just like in biological evolution, the ones that are against the grain don't survive, for whatever reason. So it could even be that convergence occurs via selection.


It's not convergence, it's the cycle of development patterns. Patterns come and go leaving bad memories that become anecdotes. Anecdotes become "misunderstanding the paradigm" and even the misunderstandings are long forgotten when the pattern that made them comes into vogue again.


I wonder if it's due to how new people are to the industry, as well as how new the industry itself is. In disciplines like mechanical or chemical engineering, you don't see nearly this much reinvention of the same patterns. I imagine most people these days using React, Vue, Svelte, or Solid have never even used jQuery or Knockout, as those are almost 15 years or older at this point.


If you're an engineer, physics are always there to smack you in the face. As a result, engineers collect sets of things that physics seem to be fine with and reuse them. If engineering were programming, a woodpecker in Central Park would bring down the Eiffel Tower.

Programming is not physical. It is generally bound by Turing completeness, the halting problem, 2 generals problem, and the like, but most developers don't even write code on that level. That leaves them with an infinite number of ways to solve problems with the real limiting factor often being the humans instead of the fundamental limits. If you use 5 different design patterns in 5 different frameworks, they all still work, so now you must decide (based on ever-changing factors) which one is actually the best.

Complicating this is the issue that not all people were taught the same or think the same way either, so an approach that makes sense to some people might not make sense to other people. The extremes here based on education and what you learned first are massive even when there are objectively better answers too. An entire generation of devs either retired or died rather than move from assembly to Fortran or C. That generation retired or died rather than move to OOP and the OOP people are retiring/dying rather than moving on to more functional approaches to programming.


Indeed, design patterns in physics and chemistry is a matter of the laws of nature, one cannot try something that doesn't follow such laws. In software, design patterns are simply guidelines, as there are no laws of nature in the realm of virtual space. It reminds me of mathematics but even mathematics has its own laws to follow, so software is even more unconstrained.


I think this somewhat inevitable given the flexibility of javascript. The lack of convergence on one single paradigm as a long-lasting set of best practices speaks to all of things that a web framework needs to have in order to accommodate all developers.

In Svelte's case, it feels like they went as far as they could without directly addressing observables until they reached a point where it became one of the largest features that had yet to be addressed.

Open source frameworks, not unlike companies, need to continue attracting new users to grow the ecosystem, which means pleasing an ever-growing user base.


Svelte Stores are observables, just without the extra boilerplate.


> reserving direction

autocorrect style typo, i think


> no, reactivity and two way data binding creating a spaghetti mess of changes affecting other changes all over the place

Honestly never understood this - 2 way is less code and way more understandable to me. Redux style codebases are very difficult for me to understand, and never saw benefits praised for. More frequently was "why isn't this updating?".

Different strokes I suppose.


Indeed. You can get all the main benefits of two-way binding in a one-way dataflow system like React by using cursors... i.e. whenever you access a property `state.foo.bar`, also derive the setter/updater, `setBar(…)`.

With proper memoization, this is both fast and ergonomic, and it even allows you to turn mutations into data and pass them to a server. I've implemented this as a stand-alone state helper [1] based on JSON patch/diff, and it's magical. Undo/redo, multiplayer, it's all within reach.

[1] https://usegpu.live/docs/reference-live-@use-gpu-state


> implying react codebases aren't spaghetti mess


> React will soon get its own compiler as well which will made regenerating the DOM even more efficient.

This will be amazing if works as people are hoping it will. I suspect it's an impossible task (in the general case). My hope is a certain coding style will be the path forward, and not a new version of putting shouldComponentUpdate (and others) all over the place.


Architecture and the used reactivity mechanics are different things.

You need architecture to avoid a big ball of mud or spaghetti code. Organising your code in layers, modules, each with its own API. Rules which layer can access what other layer. Like backend does for ages. You can and should do this in large frontend SPAs as well. No matter if written Svelte, Angular or React.


> I am assuming it's because the users who are making these frameworks now have not used or do not remember the times where "signals" were called observables

And also a tendency to not have experiencing working on large web apps (I’m talking 100k+ cloc) where issues arise, and why those React engineers made the decisions that they did


I work on Svelte 5 and I was also a React engineer on the core team previously FWIW.


Two way data binding and signals are such bad ideas when dealing with large real-world apps. I feel they only make sense in small code snippets that are cool to tweet.

For me they're a dealbreaker when considering a new framework.


Is it not possible to write Svelte code with one-way data-binding? Would that not give you the best of all worlds: compiled javascript, no virtual DOM, and easier to debug code?


I’m not particularly comfortable with some of the nature of the change. Runes are magic compiler symbols, but they look even more like just normal code than was the case before. Previously, Svelte’s reactivity model was very easy to understand, including its limitations, because it was the result of very simple analysis—you can cover the rules in a few minutes without difficulty. It included some things that were obviously magic: $: reactive blocks and $ prefixes on stores.

When you had this:

  let count = 0;
  count += 1;
… it made reasonable sense, because that’s just normal JavaScript; the fact that `count` was made reactive was basically incidental.

But once it’s this:

  let count = $state(0);
  count += 1;
This looks like you’ve called a function named $state, and given that you’re talking about migrating from compile-time to runtime reactivity, you might (I think reasonably) expect `count` then to be some object, not just an integer, and so `+= 1` would be the wrong (since JavaScript doesn’t let you overload those operators). But no, it’s instead some kind of decorator/annotation.

Yes, stores are unwieldy as you scale them up, and definitely have some practical problems, but that createCounter stuff looks fragile. I’m curious how it all works, because it looks like it’d be needing to do quite a lot of control flow analysis, but not curious enough to investigate at this time. But my intuitions suggest it’s probably markedly more complex and difficult to explain, though perhaps and hopefully more consistent.


> it looks like it’d be needing to do quite a lot of control flow analysis

Implementation-wise, this is vastly simpler than Svelte 4, because everything is explicit.

One thing we didn't really show today is how this works in your editor in practice — for example, TypeScript thinks `$state` and `$derived` are just the identity function. It makes sense when you use it, but I appreciate that I'm basically asking you to just trust me on that!

> Previously, Svelte’s reactivity model was very easy to understand, including its limitations, because it was the result of very simple analysis

I totally understand what you're saying. But in fact the analysis is _anything but_ simple — in places it's frighteningly complicated, to the point that even I sometimes don't understand what's going on! And that's part of the problem — because Svelte 4 is more implicit, you can't really know what's happening in a lot of cases, you just have to hope that the compiler knows what it's doing.


I've seen the demo and you're right, in cases where the code gets more complex, it does look way cleaner. I also really appreciate that you guys made it so that you can still use Svelte in the same old way.

But at the same time I just wish there was some other solution to this while keeping it implicit somehow. I would do anything to keep things implicit while solving the backend complexity some other way. The thing I most love about Svelte is the principle / vector of "as little learning as possible", as well as in many cases transfer of learning, makes it much more user friendly, and I wish evolutions of Svelte continued to evolve along that direction, by reducing more and more.

But things like `$something` are a bit strange. Even `$:` is strange. It adds cognitive load. It's not very English-like and in turn not easily parseable. `on:click` is closer to the attractor of user friendliness. I think all programming languages and frameworks should try to approach English or Python, to allow for maximum "transfer of learning" so things just feel like they flow "without thought". Taking inspiration from UI/UX... things should be as close as possible to 'understanding at a glance'

The gold standard would be to approach something like this level of intuitiveness in the future as crazy as it may seem: https://twitter.com/brianjoseff/status/1617556877218570241 https://twitter.com/mathemagic1an/status/1700232760756207956...

I have many ideas on how, but it would no longer be a programming language.


> for example, TypeScript thinks `$state` and `$derived` are just the identity function

That seems like a missed opportunity on Svelte’s part… but hard to fault, because TypeScript doesn’t support nominal primitive types very well. Ideally it would be something like Reactive<T> to signal (ha) that it’s not just a plain value.


We've toyed with this idea. There's a couple of problems though. Firstly, if you have this...

type Reactive<T> = T; function $state<T>(value: T): Reactive<T>

...then TypeScript will 'unwrap' the type anyway, unless you do funky stuff like this...

type Reactive<T> = T & { [uniquesymbol]: any };

...in which case things like `value += 1` will cause type errors because it coercies `value` from `Reactive<number>` to `number`.

But it also creates problems here:

let message = $state('hello'); obj = { message };

The type of `obj.message` is Reactive<string>, but it's _not_ reactive — it's a non-reactive snapshot of the value when the object was created.

It's possible that we can do some fun stuff with TypeScript plugins, but we haven't dived too deeply into it yet.


> TypeScript will 'unwrap' the type anyway, unless you do funky stuff like this […] in which case things like `value += 1` will cause type errors because it coercies `value` from `Reactive<number>` to `number`.

Yeah. I’ve spent more time than I’d like to admit trying to find a nice solution to this, and I’ve ultimately arrived at “it needs type system support to work for the general case”. I think you can make your brand (symbol) optional to address this case, but it doesn’t address this:

> The type of `obj.message` is Reactive<string>, but it's _not_ reactive — it's a non-reactive snapshot of the value when the object was created.

And here is the real problem: the types are right (in this case)! It’s Svelte that is wrong (in that it deviates from the JavaScript language semantics, which TypeScript has correctly modeled).

This leads to my other ultimate conclusion with nominal primitive types: most of the time you’re better off just boxing the value… unless, or until, it becomes problematic for other reasons (eg performance, which would probably be a concern here, albeit one worth testing). Boxing allows correct, refined typing; it makes semantics of the value clear. The only downside is convenience… but this sort of convenience is exactly the kind of thing people rightly judge about the JS ecosystem.

I’m not likely to use Svelte (for a variety of other reasons), so I don’t have a particular dog in this race… but I will say I find more explicit types for signals a great deal nicer to work with. Whether the explicit mechanism is a function call (like Solid) or an accessor (like many others).


With Rust, mutable variables are underlined by RustAnalyzer by default - it would be really useful for reactive variables in Svelte to have a similar distinction.


Fair enough. I’ll see how things go and wish you well. For simple cases, the new will be syntactically-inferior, but it makes sense that the explicitness allows it to be more consistent. Ah, modelling mutable trees as stores… not a great deal of fun.


Functions can return primitives, so there’s nothing wrong with $state() returning a number that you can +=1.

What is weird is that it’s actually typed as a svelte-compiler-only ‘extended int’ that can have side effects when you increment it, and weird knock on results from reading it.


Perhaps I'm just the grumpy old guy that's afraid of change.

But I fell in love with Svelte because it was dead simple (according to me). It was a breeze of fresh air and I felt I just program again without wiring enchantments together.

I do agree that its simplicity has downsides too, so perhaps it's just nothing to be afraid of?

But I can't help seeing this as ominous:

> This is just the beginning though. We have a long list of ideas for subsequent releases that will make Svelte simpler and more capable.

Please don't turn Svelte into a black magic box.


Largely agree.

I've got a couple of thousand hours of Svelte dev experience, and these changes offer me nothing I really want.

Svelte dependencies outside my .svelte files? No thanks, I'll keep them usable in non-Svelte projects.

A new way to do reactivity to try to appeal to React users? ("When people come to our community in future..." in the vid.) No, thanks! Svelte 3/4 reactivity was very straightforward, one could learn the whole thing in a day from the excellent tutorials. It was better than React.

There was definitely a bit of weirdness with overuse of reactive vars but that's been incentive to keep components small and simple. A good thing!

Personally I'm still stuck on v3 because 4 introduced breaking changes I haven't had a chance to debug, so it'll be a while until any of this impacts me anyway.


I’m definitely getting some react vibes from this. And I hate react.

Maybe I just need to try it out.


Agree. Svelte is a blast to write as an old grumpy backend engineer. But yes, probably just scared for nothing. Turning onMount() into $effect() is a tiny change, but this self-aware smol brained grug likes onMount() as it means something! To enable logical grouping, Svelte 5 allows us to nest the $effect()s? What does that even mean? Where am I? Nurse!


nesting means that a variable being watched in the parent scope triggers both the parent and child functions, but a change to a variable in the child's scope only triggers the child function.


maybe super specific to this comment but onMount isn't going away, it could be replaced with $effect from an implementation standpoint, but it would be wildly confusing if used for that purpose without the clearer name for the wrapper


This set of changes makes things more explicit. That's the opposite of a black magic box as far as I can see


Definitely. It's surprising to see all these magic comments.

Maybe it's because of using the "runes" word :)


Was my first gut reaction as well. Especially when i saw `$state(0)`.

But watch the introduction video. It isn't at all like the functional reactivity that entered other frameworks. It's still the svelte way. Read and assign is plain javascript. Only the initialization syntax changed.

They even promise backwards compatibility, so you don't have to migrate or migrate file by file if you want to. Which is also not how other frameworks handled this in the past.


One of Svelte's biggest advantages is its compiler, positioning it more as a language than just another JS framework. If I'm not mistaken, the compiler allows Svelte to define its syntax to anything they want.

Given this, I'm curious: couldn't the traditional syntax of `let counter = 0` be made to function similarly to the new let count = $state(0);? Transpile it to let count = $state(0) under the hood? If that can work technically, instead of introducing a new rune for reactivity, why not introduce a "negative" rune to denote non-reactive statements? This way, the change wouldn't break existing code; it would be more of a progressive enhancement.

I agree the move to unify the Svelte <script> tag with regular js/ts files is an improvement. It was indeed a little odd that certain syntactic sugar, like the $, would work exclusively within the Svelte <script> and not in a js/ts file that's right next to it. However, from what I gather, it seems the Svelte team is aligning the Svelte script more with js/ts, rather than bringing the js/ts closer to Svelte's unique syntax. This trajectory seems to be pushing Svelte towards resembling traditional JavaScript frameworks, like React. It's a departure from Svelte's unique strength of having a custom compiler and behaving more like a language. If every syntax in Svelte is expected to mirror its behavior in js/ts, eventually svelte will lose all it secret sauce that made it so unique. Why can't we add a rune into js/ts file, a note in the beginning to tell svelte compiler that this is svelte enhanced js/ts file, compile it like svelte script tag code? Bring js/ts more alike to svelte?


We evaluated somewhere close to 50 different design ideas (seriously) before settling on this one, and what you describe was one of those ideas.

But one of our goals was for you to be able to use Svelte's reactivity inside .js/.ts files, since that's one of the things people have been crying out for since we released Svelte 3. For that to work, reactivity has to be opt-in, not opt-out.

And that's how it _should_ be — someone reading the code should be clued into the fact that this `let` won't behave like a normal `let` in JavaScript, and it should be possible to move code between modules (and between modules and components) without worrying about whether a specific file was opted in to certain behaviour.

In other words this...

> This way, the change wouldn't break existing code

...isn't quite right — it would break _all_ your existing code that wasn't in .svelte files.

> If I'm not mistaken, the compiler allows Svelte to define its syntax to anything they want.

On this point specifically: unfortunately not. The code in a .ts file, for example, has to be valid and typecheckable. You can't insert a preprocessing step ahead of the TypeScript compiler. Again though we concluded that this is a good thing, since it means this all works with all existing ecosystem tooling.


> for you to be able to use Svelte's reactivity inside .js/.ts files, since that's one of the things people have been crying out for since we released Svelte 3

I can't find an issue for that among top 50 open issues on Svelte's GitHub repo. I've also been a member of Svelte's Discord server for years and do occasionally hang out there, I haven't seen people "crying out" for this at all.

On the other hand, there are things like `<style module>` or `forward:class`, etc. that people have ACTUALLY been crying out for (literally one of the most upvoted issues in the repo) which haven't been addressed at all.


"...isn't quite right — it would break _all_ your existing code that wasn't in .svelte files."

What if it is opt-out reactivity in .svelte files and opt-in reactivity in .ts/.js files? Yeah I know it would be a bit more combersome to copy code from .svelte to .js/.ts files but I think it would be worth it


That would be a _terrible_ outcome. Things would routinely break, and code would be vastly more confusing.


I love all the changes except that single thing with let count = $state(0);

I'm just brainstorming here, but what about an optional $reactive rune where everything in that is reactive by default?

$reactive(() => { let name = 'world'; });

vs

let name = $state('world');


They mentioned that the team tried around 50 different variations. Meaning they spent a lot more time than a comment on this. I would trust they know what they are doing considering track record of Svelte team.

Tbh this seems kinda rude. Maybe check github i am sure the whole journey can be seen there.


I don't mean to be rude, I'm just brainstorming. I'm sure they have thought about it I'm just commenting in the small chance that they haven't


Maybe reuse the $:{} here, tho that would probably be really confusing for svelte 4 developers lol

$:{ let name = 'world'; };

vs

let name = $state('world');

$: is valid javascript right? So that should also work in .js/.ts files I assume


I think the reason they didn't opt for this approach is that putting stuff in a {} block creates its own scope, so any variables declared within that block are inaccessible from outside said scope.

The $: label syntax is valid JavaScript, but allowing scoped variables to be accessible outside of scope is very invalid JavaScript.


First off, thanks for chiming in with that detailed explanation. It's always a learning curve when you dive into the technical side of things, and I genuinely appreciate it.

Given the constraints with TypeScript not being further compilable, I've been pondering on Svelte's direction. Personally, I'd lean towards letting go of some of the special touches in js/ts file if it means keeping more magic in Svelte. If we're heading towards making Svelte syntax work exactly the same in js/ts entirely, it feels like we might risk turning Svelte from its unique language-like identity into just another framework in the JS world.

Thanks again for the insights! I have already felt a little better about my current work in migrating an app from another framework to svelte 4. I was worried that I have made a very wasteful decision for my own company.


> Given this, I'm curious: couldn't the traditional syntax of `let counter = 0` be made to function similarly to the new let count = $state(0);? Just transpile it to let count = $state(0) under the hood? If that can work technically, instead of introducing a new rune for reactivity, why not introduce a "negative" rune to denote non-reactive statements? This way, the change wouldn't break existing code; it would be more of a progressive enhancement.

exactly my thoughts, feels like they could've kept it much simpler


It's great to see people moving in this direction, but I'm disappointed that everybody has decided to reimplement basically the same thing independently.

Mobx was ahead of the game here (though, granted, it too draws on Knockout.js). You can use Mobx to declaratively describe reactive state, much like this. But it isn't integrated into any framework - you can use it in vanilla JavaScript with no other runtime or compilation required. You define models with Mobx, then on top of that there's mobx-react, which ties your model into React's update APIs (essentially making render() automatically observe values, and making relevant changes trigger a re-render), or there's mobx-vue, or mobx-svelte, or mobx-preact, etc etc. Decoupling this is super helpful - for example I'm using mobx to model raw state, computed state & reactions to changes in server side Node.js, no problem.

Meanwhile, recreating the same reactive concepts independently in each library instead makes all the resulting code incompatible, so even your pure JS state models are coupled to your UI framework - e.g. createCounter in this post has to import & use $state from Svelte. That makes it far harder to change frameworks in future, hard to share code between apps using different frameworks (plausibly even different versions of the same framework), etc etc.

I'd love to see a native common standard for this, similar to how promises were eventually standarized and suddenly everything had a compatible model for handling async future results (I could swear I've seen initial discussion on exactly that already, but I can't find it anywhere now sadly).


You may be thinking of the ECMAScript Observable proposal: https://github.com/tc39/proposal-observable


I loved MobX. Used it for years with React and Inferno.

But not only it's an added layer of abstraction, it's also a complex piece of machinery which is not needed when the framework solves reactivity.

When I started using Svelte back in 2019 I was very happy to let go of MobX.


This is the way.

Mobx tc39 decorator support is pretty much done too. I check in on the PR weekly haha.


It kind of had to get sent back to the drawing board to work well (avoid all the absurd one-at-a-time limitations of generators), but async-iteration-helpers I think will be an incidental huge help in normalizing/nudging the consumer api into "just an async iterable". Updating/writing state might be more complex, speak to the implementation, but seeing things change should have a semi-standard api. https://github.com/tc39/proposal-async-iterator-helpers

One huge sadness I have is that when you have a callback in .then or .next, your handler doesn't get a gratis reference to what you were listening to. I'd love to have this be a better record. DOM is so good about having thick events that say what happened, and it's so helpful, sets such a rich base, but js snubbed that path & left passing data in 100% to each event producer to decide as it will. Consumers can craft closures to seal some data into their handlers but it sucks compared to having an extensible data flow system. We're kind of sort of finally fixing this crime the hard way by standardizing async context/async_hooks, which is a whole new ambient way to create context that we can enrich our async events with, since there was no first class object to extend for having omitted passing in the promise to the promise handler. https://github.com/tc39/proposal-async-context

Also worth pointing out, maybe arguable as a hazard tale, observables was proposed a long long time ago. There's still a ton of adoption. But it also feels extremely similar yet notably apart & worse ergonomics than async iteration. It's imo a good thing it didn't get formalized. https://github.com/tc39/proposal-observable

Alas one reactivity I really wish we had had is object.observe (note: different API than observables), or something like it. Undoing good specification work & saying, 'yeah, if users want it, they can implement it themselves with proxies' has lead to no one doing it. And you can't just observe anything; whomever is the producer has to up front make the decision ahead of time for all consumers, which turned a great capability into something first boutique then quickly forgotten. Alas! https://esdiscuss.org/topic/an-update-on-object-observe

I ack your ask, and there's no shortage of options that are pretty damned good. But I feel like we are still in a discovery not deployment phase, still delay competing because we have a lot of terrain and idea space to consider. Before we pick, standardize & ship one.


As a recent adopter of Svelte, these changes are intriguing but I don't really have a grasp of how I feel about it quite yet.

One thing that I am definitely happy to see is the removal of $: as it should help Typescript users. Personally, I was quite sick of writing:

  let input = 'Hello';
  // ...
  let loudInput: string;
  $: loudInput = `${input)!`;
Instead of:

  let input = 'Hello';
  // ...
  $: loudInput: string = `${input)!`;
It's an incredibly minor thing, but when you do it 1000 times it becomes very frustrating. Having reactivity be rune-based should help TS avoid the syntactic confusion, bringing us to:

  let input = $state('hello');
  // ...
  let loudInput: string = `${input)!`;


Having a great experience with TypeScript was very much one of our goals. Many design ideas failed to clear this hurdle


That specific TS issue has literally been fixed for ages. What version of Svelte were you on?!


What about long arrays? Is there a mechanism where Svelte knows which element is mutated, and do fine-grained recomputation/update only the corresponding view elements?

This is the primary place where we have to go outside the framework in React. Only a large linear list has this problem -- if it was a decently balanced component tree, then we could skip updating huge swathes of it by skipping at a top level node. But it is not possible in an array. You have it iterate through each element and do a shallow comparison to see if the references have changed.

That said, it is fairly easy to escape to DOM from inside a React component with useRef and the portal pattern. Then we can write vanilla JS which makes updates to only the values it changes.

If Svelte solves this in an elegant manner, then it would be a very compelling feature over React. I'm asking here because last I checked, most of the examples in Svelte's documentation pointed to simple counters and regular objects, and I couldn't find an example of a large linear list.



Thank you!


Did you try setting the `key` property in React?


`key` informs React of the identity of an element. That helps it during the reconciliation phase -- if it knows only one `key` in a list of DOM elements has changed, then it will run the DOM updates only on that one. Similarly if the order has changed, it only needs to move its index in the parent DOM element.

But it doesn't help in the rendering phase - aka when the virtual DOM is constructed when `render` is called on the root component, and all our JSX code is executed across the component hierarchy. Virtual DOM reconciliation cost is only a part of the performance penalty, re-running the "view as a function of state" computation is another major chunk.


Comparisons (Svelte 4 vs. Svelte 5 and other Frameworks): https://component-party-runes.vercel.app/


The vue 3 composition api syntax. Very clean


It's a really strange comparison. They didn't even try to be consistent in code formatting.

Svelte:

    <button on:click={nextLight}>Next light</button>
Vue3:

    <button @click="nextLight">
      Next light
    </button>


Hey, cool site, but it's down now :(


thank you so much for sharing this site! I've been having a hard time wrapping my head around some Vue2->Vue3 changes and this is very helpful


> At first glance, this might seem like a step back — perhaps even un-Svelte-like. Isn't it better if let count is reactive by default

Actually, it was Svelte who coined the term and sold us on the idea of reactivity by default. I don’t think anybody asked for “Reactivity by default”. Svelte advanced this idea, and it helped the framework gain traction. It was easy to get started, and gave Svelte this sense of better ergonomics than other frameworks. I was always skeptical about the performance claims, amortized, and the real selling point of Svelte was ergonomics and the dev experience.

The problem with the Node.js ecosystem is the devs are borderline marketing and sales type. They’ll justify, rationalize and make things sound good after the fact. Previously, Svelte was persuading us that Svelte was better than the rest because of reactivity by default. Now they did a literal 180. It’s probably in the right direction, and maybe how things should have been. A related symptom of the Node.js ecosystem is reinventing and rediscovering the wheel. The problem here is a lost of trust. Anything else which Svelte purports it’s got figured out or is more enlightened about should be taken with a grain of salt.

So it seems those boring FANG engineers with React has it right all along. They had experiencing building sufficiently complex apps where verbose but explicit code was necessary.

> Because the compiler can 'see' where count is referenced, the generated code is highly efficient

Yeah, I don’t believe such claims anymore. Sure, in cherry picked and constrained settings, the performance benchmarks might seem good. As much as I hate to admit, I will reach for the production ready and battle tested React, as boring as it is.


We never made any such claim! In fact, the reverse: https://twitter.com/nsthorat/status/1653890181592653825

In Svelte 3, you had to opt in to running code on updates, using things like the `$:` label. It was designed to be conservative about updating components, unlike virtual DOM solutions that like to update everything unless you opt _out_.

I too am very sceptical of benchmarks — they can certainly obscure more than they reveal at times. But you don't have to take my word for it, or the benchmark results showing that Svelte 5 is faster than every other framework in existence (https://twitter.com/Rich_Harris/status/1688581184018583558) — you just need to understand the different mechanisms in play.


I've dabbled with Svelte and find it pleasant to use and I think this is a step in the right direction. The main reason I ultimately keep coming back to React is I find the compile-time alterations to the semantics of my code difficult to reason about.

I've spent a lot of time building an intuition for how Javascript code executes and how I can combine its primitives to make reasonable abstractions. The fact that this _looks_ like Javascript but suddenly operates differently is almost more confusing to me than if Svelte was just a non-Javascript language.

React's `useState`, `useMemo`, etc. are perhaps more verbose but they're just functions. Dependency arrays are messy but it's fairly easy to extrapolate their behavior from a basic description.


I've been trying Svelte for the last couple of months. At first the claim was that it's not complicated like React because there's a lot less concepts to learn. And it's just using basic Javascript and CSS so those skill sets are transferable to any other job. As I use it more and more, there's more and more special way of doing things I have to learn: store, reactive variable, $, $$, etc. I didn't mind, sure I'm in Svelte's world. But the number of libraries is limited and it really slowed me down tremendously. Now with runes, it's just more "magic" to learn. I think that's the last straw for me. I'm done with Svelte experiment. Back to React land.


Did you read the bit about how runes make all those things unnecessary in future?


there are so many comments here that really feel like they didn't read any part of the announcement other than that there's a thing called runes.

For me personally I tried svelte in the past and bounced off because there was too much implicitly happening that I needed to have a deep understanding of to model correctly. This solves basically all those problems for me.

I thought your video[1] especially did a great job walking through the pros this change brings. Thanks for all your great work on this!

1. Link for the curious: https://www.youtube.com/watch?v=RVnxF3j3N8U&t=6s


Please don't get me wrong. You guys are doing great work. And I did notice the hard work you put into runes to make things better. My point is that, it feels like I'm just trading one complexity for another. Like most people, I am constantly searching for ways to do my job better.


I'd argue that there are way more libraries, since vanilla JS libraries integrate beautifully, unlike in React. Unless you are only talking about component libraries, of course.


Yes, UI component libraries. I just want to leave the UX to the expert and get going on the rest of the application.


That is exactly my experience after trying svelte/sveltekit for 2 months. Loved svelte at first sight but soon their own invented complexity (and a very confusing error log) made me realize that I was changing React for something quite similar (with a bunch of different problems). In place of going back to React tho, I tried the next one in my list: Lit. No regrets, found the (powerful) simplicity I was looking for. Give it a try before getting back to React: https://lit.dev/


This looks like it’s moving closer to React Hooks, but using the compile step to optimize them out? Kinda like a better React Forget?


This might be the impression on first glance because it uses the word "state." But keep reading, and its much more akin to what Solid is doing. In fact, the new docs openly credit the work Solid's team is doing. They also credit Knockout's approach form way back in 2010.


Under the hood it's doing something more similar to solid, but the API exposed is a step in the direction of React (it doesn't expose the signals to the user). It's not quite React either because there's no 'setter', just a different way to opt in to reactivity which also (IIUC) makes it possible in .js/.ts files


For a second, ignore Hooks, Signals and Runes, and look at the way Runes were presented in the video "Introducing Runes.. with Rich Harris". You will find this presentation very similar to but much shorter than "React Today and Tomorrow and 90% Cleaner React With Hooks" video. Both of them talk about:

1. primitives for managing state - $state vs useState

2. removal of lifecycle mechanisms - onMount vs componentDidMount

3. replacing lifecycle mechanisms with new primitives - $effect vs useEffect

It's like the Svelte team took a leaf out of React team's book on how to upgrade a framework - this is evident by the way these features are presented as opt-in like how React marketed Hooks as opt-in. I would go on to predict that the upgrade to Runes will just like the upgrade to Hooks. Developers will use it and then love it - because it presents improvements to the way codebases will be structured and maintained just like React did with Hooks. This is really a Hooks moment for Svelte. Good job Rich and the Svelte team!


For sure. Look at this Svelte 5 example:

<script> let time = $state(new Date().toLocaleTimeString());

  $effect(() => {
    const timer = setInterval(() => {
      time = new Date().toLocaleTimeString();
    }, 1000);

    return () => clearInterval(timer);
  });
</script>

<p>Current time: {time}</p>


This example is a bit strange to me. I wonder if `$effect` will actually replace all usage of `onMount` and `onDestroy` for Svelte. In Solid you could totally do these things with `useEffect` too, but they chose to keep `onMount` and `onDestroy` (which they call `onCleanup`) to make this kind of thing more simple.

Example: https://www.solidjs.com/examples/counter

`onMount` and `onDestroy` feel like really useful, dependable callbacks. `$effect` is scary because if you add a reference to state in it, you can't depend on it being called like `onMount`.


They don't claim they'll remove `onMount`.

They claim most (but not all) of current usage of `onMount` will be better off using `$effect` instead


I kind of feel the same. React and all the new stuff now feels like unnecessary complexity but they definitely got the initial DX right


The fact that the frameworks are converging on the same idea should suggest that it is necessary complexity in the framework for any sufficiently complex app.


Or that they are too invested to drop features in place of adding more? When this happens, incumbent frameworks appear. Svelte was one but it became just like the old ones before its prime time.


It looks so close to react hooks, that is the first thing that struck me. Of course the syntax is slightly different but functional it is mostly the same. It seems weird that we are definitely converging between the various frameworks. For a while with svelte I though we were diverging but that seems to be changing now.


This makes a lot of sense and will simplify some confusions around reactivity.

I'm guessing runes will make it easier for the compiler to track the reactivity which will enable stuff like automatic partial hydration? Maybe even something like qwik?

I only read the blog post and didn't watch the video... was there any mention on perf and size improvements?


Reactivity is faster now: https://twitter.com/Rich_Harris/status/1688581184018583558

And the output from the compiler is much smaller. You can compare the output on the Svelte 4 REPL to the output on the Svelte 4 REPL. The runtime has grown a bit, but the output overall is still much smaller even when factoring that in


Smaller and faster :)


Can't wait to see some numbers!


So if I’m understanding this, Svelte is moving from reactive by default to declarative reactivity? That does seem like an improvement in signal to noise ratio.

Shared-everything does not scale. It ends in whack-a-mole and an escalating blame game about whether team members are fit to work on the project. It’s bunk. It’s deflecting from the real problem which was dereliction of duty by the “architects” who took a laissez-faire stance on state management instead of providing structure. Worked on a couple of those. Never again.

Practically the whole point of encapsulation is gated access to data, putting constraints on sharing, compressing the possible state space of the system closer to the desired state space.


I'll be the first to mourn the (future) loss of $: but the video clearly shows that the changes are a pretty enticing way to make your code that little bit cleaner, and solve all of the "but Redux!" style questions.

Svelte for Apps. Svelte for Sites.


I'm not going to miss $, I've found it to be a weirdly documented nightmare...


I originally created https://neovimcraft.com in Svelte to learn how it works.

I found `$:` to be extremely confusing, full of weird quirks, and completely turned me off to using svelte for anything more than basic sites.

Runes seem like a clear improvement, but brings Svelte a step closer to React -- which hurts its appeal to me.

The difference between `let counter = $state(0)` and `const [counter, setCounter] = useState(0)` is near its initial value -- zero.

I do love the view library competitive landscape and enjoy seeing different paradigms leveraging reactivity. I also like the compiler optimizations that Svelte is bringing to the entire ecosystem.

I wrote my initial thoughts on sveltekit when I built neovimcraft: https://bower.sh/my-experience-with-svelte-kit


As we've taken to saying around the virtual Svelte offices:

> The magic of Svelte isn't `let count = 0`, it's `count += 1`

That part hasn't changed!


Yeah I gotta agree. No comment on runes but $: was so weird that I was immediately confused at why I would try and use svelte for anything


React Hooks has its problems, but it got so many things right from the start - code written in 2018, when hooks first came out, still works today. No need to rewrite everything when a new major release comes out.

That said, svelte5 does solve a lot of problems that stop me from trying it.


> code written in 2018, when hooks first came out, still works today

Does not Svelte from 2018 works today?


I have a sapper (pre-sveltekit) project from 2019 that doesn't build. I needed to make a tiny update and neither my current computer nor my previously configured netlify autodeploy can produce a build that works. I have no idea, my first guess was that one of the sapper people didn't pin the version of an important dependency, but the project was simple enough that I just wrote a new one from scratch.


jQuery from 2009 also still works today. What I meant was, developers want to use the latest and greatest. Hooks added in 2018 havent changed, there’s no replacement api for them - it’s still modern code.

They got the DX right from the start, that other libraries are still trying to emulate.


> They got the DX right from the start, that other libraries are still trying to emulate.

The DX isn't "right". It's just the one they are sticking to. There are many issues with the actual developer experience when it comes to hooks in React.

So it's a good thing that other frameworks are iterating and finding new and possibly improved ways of doing things. E.g. neither Svelte nor Solid require dependency arrays to effects or other reactive primitives. Their effects work everywhere, and not just inside component code. You're not beholden to the order and number of effects, unlike with hooks. Etc.


that's one thing I admired about the React team back then, they took the time to think about how things "should" work long term. The functional/hooks release was criticised as people liked their class components, but time has shown that hooks were the correct decision.

I feel they lost that as people gradually rotated out of the team, around the time they announced concurrent-mode, now suspense and the half baked RSC "release".


Yeah, I'm pretty skeptical about concurrent mode. People have been trying to implement something like this since ~2010, and I haven't seen it done well yet.


> Component re-rendered because hook 16 updated.

DX Amaze.


Most of this I really love. One thing seems a bit strange though...

Let's compare Svelte's and Solid's approach to nested reactivity. Both of them implement the same nested reactivity todo example:

Svelte: https://svelte-5-preview.vercel.app/docs/fine-grained-reacti...

Solid: https://www.solidjs.com/tutorial/stores_nested_reactivity?so...

In Solid, converting something to use nested reactivity is one step. In Svelte, it is two steps. And that second step is really verbose and annoying:

  todos = [...todos, {
    get done() { return done },
    set done(value) { done = value },
    get text() { return text },
    set text(value) { text = value }
   }];
Solid makes read and write segregation very simple and obvious. You don't need to manually make all these getters and setters.

It is nice that runes allows nested reactivity in Svelte, but it feels nicer to use in Solid.


FWIW you can of course implement createSignal in four lines of code, if you prefer the ergonomics of that:

function createSignal(initial) { let value = $state(initial); return [() => value, (v) => value = $state(v)]; }

Note that the Solid change is _not_ 'one step' — the `completed` property is being turned from a property to a function, which means you must update all the usage sites as well. Using getters and setters also allows you to use Svelte's convenient `bind:value` approach, which is much less verbose than using the equivalent event handler code. And don't get me started on the [type narrowing issues](https://www.typescriptlang.org/play?#code/C4TwDgpgBA4hzAgJwD...).

There's nothing _wrong_ with the Solid approach, but the ergonomics aren't to our liking. If we need to take a hit in terms of verbosity, we'd rather do it once at the declaration site than n times at every usage site.


These are great points! Thanks for the super thoughtful reply. I'm actually sold.

1. It's really nice that it's so easy to make a `createSignal`

2. I didn't realize that in Solid you had to update all the usage sites too, so now I'd rather stick to the Svelte usage. Nested reactivity is not as effortless as I thought in Solid.

  get done() { return done },
  set done(value) { done = value },
  get text() { return text },
  set text(value) { text = value }
Looks a bit boilerplate-y maybe, but keeping your preoptimized call sites is totally worth it.

This might be common enough that some syntax sugar might be worth it?

The short hand for:

  todos = [...todos, {
    get done() { return done },
    set done(value) { done = value },
    get text() { return text },
    set text(value) { text = value }
  }];
Could be:

  todos = [...todos, {
    $done,
    $set
  }];


This is the biggest weirdness that I hope gets addressed.


I've always respected Rich Harris and the Svelte team.

They do an excellent job of some pretty substantial tech. But also the way he/they explain it is so powerful.

That includes the blog posts, the videos, the framework itself and the playground.

This does seem like a unifying step. Seems like (at least) Svelte and Angular have both declared this model superior to their existing implementations. The video gave credit to prior art in general but would have been better to give the specific projects credit - not just ethically but also to be explicit about what is and is not similar.


The whole selling point of Svelte was that it was simple, like a breath of fresh air. You could update the state of your component just by assigning a variable. I guess this is the natural progression of web frameworks.


To be fair, assignments to variables still update the state of your component. `count += 1` will still update the state of your component. I think what you meant is that you now need to explicitly declare `count` as state. Personally, I think the magic of Svelte is that assignment part. And now the magic of Svelte works across files and even inside regular `.ts` and `.js` files!


Having moved from React to Svelte, it was always a breath of fresh air to write less and have it just work. Feels strange seeing state/props/effect again, almost like I'm back to React.


Svelte 5 is basically a Vue 3 wannaba; except that it has a smaller ecosystem/community, a smaller team, and is less feature-rich. Genius, really. It just lost its #1 selling point and they're talking about it as if it's a good thing.


"Like every other framework, we've come to the realisation that Knockout was right all along."

Nope, nope. Been there, done that, with 2-way data binding and never going back.


> with 2-way data binding and never going back.

We used to know that, too. We also used to know that entirely event-driven architectures were a level of chaos you shouldn’t invite into your enterprise. Don’t need to look hard to see those either.

Whole industry has been cycles of collective amnesia going back to at least 1975.

[Edit] but in this case what we seem to be doing is having another go at Aspect Oriented Programming, which I was interested in for some time but concluded it, like event-only systems, are a poor fit for the average developer’s mental model, and also a terrible way to encode business requirements. Particularly from a testing perspective. They are usually dabbling at functional core, imperative wrapper architectures, but tend to retain global shared state which is a reliability nightmare waiting to happen.


I thought that quote of yours was a sarcastic overview you yourself had written but no, it's an actual quote from the article!

> Like every other framework, we've come to the realisation that Knockout was right all along.

> Svelte 5's reactivity is powered by signals, which are essentially what Knockout was doing in 2010. More recently, signals have been popularised by Solid and adopted by a multitude of other frameworks.

> We're doing things a bit differently though. In Svelte 5, signals are an under-the-hood implementation detail rather than something you interact with directly.

That's a sad development and further makes the framework more complect (as defined by Rich Hickey), with more hidden layers and "magic".


I’m still waiting for every other framework to realize that jQuery was right all along.

But if these guys are only now reaching Knockout, I still have to wait for them to catch up to Backbone.js, I guess.


jQuery is not a framework by any definition of the word. It's a collection of largely unnecessary (in modern times) utility functions for imperative DOM manipulation.


It's still much easier to manipulate DOM with jQuery than with any of the "modern times" APIs.

Hell, even querying the DOM is still easier with jQuery.


Barely. document.querySelectorAll() has about 98% of the capability, and 10% extra too.


You probably haven’t used jQuery beyond the basics. Its API is much more powerful, composable and terse than the native one. We lost a great opportunity to standardize on what everybody was already using.


jQuery: returns an array-like structure that is consistent with the rest of the API whether it's one element returned, no elements are returned, or many elements are returned.

DOM:

- few if any DOM methods work on an array of elements. Or even on a NodeList

- `querySelector`: returns null if not found, Element if found. Throws if there's a selector syntax exception.

So you have to wrap it in a try/catch and in a check against null when you need to use it

- `querySelectorAll`: returns NodeList, Throws if there's a selector syntax exception.

NodeList is not an array. It's so badly designed that even the .forEach method was only added to it two years after the method was introduced.

If you need anything but .forEach, it's better to call Array.from() on the result than deal with iterator shenanigans of it's sparse interface

But sure, "it has 98% and 10% extra", whatever that means.

And that's just two of the methods. Everything else is just as bad: 90s-era verbose imperative object-oriented API.


I have never heard of a case where I need to care about selector syntax errors. If it ever happened, I guess I'd just use a try?

Much of the time "checking for null" consists of adding a single question mark.

    document.querySelector("div#options")?.setAttribute("hidden", "true");


> If it ever happened, I guess I'd just use a try?

Exactly, you'd "just use a try". Instead of not using it.

> Much of the time "checking for null" consists of adding a single question mark.

Note: this API was introduced way before the `?` was even thought of. Which tells you a lot about the quality of the API.

So. Just for the simple task of selecting elements:

- you have to different APIs for "select 1 element"/"select multiple elements"

- these APIs differ in their behaviour. They can also throw

- almost none of the DOM APIs work with the return values of one of those APIs (e.g. your example stops working the second you use querySelectorAll)

On top of that:

- none of the DOM APIs can be chained, or combined in any meaningful way, so if you want to do more than just call one method, you're up for some very verbose and tedious boilerplate


> Exactly, you'd "just use a try". Instead of not using it.

This has happened zero times so far, to me.

You can use qsa all the time if you want a consistent interface. I consider throwing to be a good thing if the input was bad.

For me, none of these things represent a significant enough problem to take on another dependency.

I'm probably doing different things than you. If JQuery solves some of your problems, I'm not trying to convince you to stop using it.

I know you're asking/wishing it was the standard library. I don't even disagree, really.


> This has happened zero times so far, to me.

This has happened more than zero times to me.

> You can use qsa all the time if you want a consistent interface.

Indeed. And qsa is so much more verbose.

Note how this whole discussion started with:

- [jQuery] a collection of largely unnecessary (in modern times) utility functions for imperative DOM manipulation

- It's still much easier to manipulate DOM with jQuery than with any of the "modern times" APIs

My last statement is still a fact. "Modern" DOM APIs are anything but. They are the same 90s era OOP that is extremely verbose, cannot be composed in any meaningful way, and provides just a handful of somewhat useful utility functions that don't mean much in a grand scheme of things.

There's a reason that even the most staunch of anti-framework people (like most of the web component crowd) immediately fall back do just dumping strings into DOM via .innerHtml


Library vs framework is a largely pointless distinction, IMO.


Not really. A framework is something that has opinions about the structure and architecture of your whole application. A library doesn't.


One day my MooTools skills will be cutting edge again, i'm positive.


I was very glad when jQuery won. I never liked MooTools or Prototype, really. jQuery was love at first sight [site]


<3 backbone


> I’m still waiting for every other framework to realize that jQuery was right all along.

I find myself feeling this way a lot while writing front-end code.

While I am primarily a back-end developer by trade, I find myself working in Vue or React quite often just to get things done and regularly come to the realization that the majority of the reactivity in the projects I am working on is either unnecessary or so simple that it would be handled with less complexity as a line or two of jQuery.


Thats similar to me as a frontend dev seeing all the backend complexity and thinking it would be easier just to read and write a json file instead of a db + apis.

It works but on longer projects where requirements can explode in complexity it becomes a problem. It really helps to have tools that can stay maintainable.


That comparison works against your point quite well because there are an absolutely incredible amount of backend services built with scalability and sharded postgres dbs with redis caching or what-have-you that would have been perfectly served by a perl script and an sqlite file.


Yeah, sure. It's pure joy of mantainability and dependencies.

Just watch out for that dust, if you sneeze next to a 5 year old Node.js/React project, the whole thing falls apart.


We sometimes have to step back from our high tech bubble. Check out jQuery's usage on the web. The unbeatable juggernaut that React seems from up here clocks at under 5% market share. It's sobering.

https://w3techs.com/technologies/overview/javascript_library


There might be a long tail phenomenon at play here. Do you have stats on number of developers using the tech or on page views for each framework?


Regarding page views, from a quick search, the only top 10 sites that use React are from Meta.

So it’s either a strange distribution curve, with a bump in the neck and a colossal tail, or we’re trapped in a bubble and blinded by our own crazy reality distortion field.

As to number of developers, if a lot more of us are needed to write a tiny fraction of the pages, maybe that’s the symptom right there.


My experience with JavaScript is limited, but knockout is what I use because it's what makes sense.


Knockout is fine to use if your JS doesn't exceed 1000 lines or so. After that, in more complex apps, 2 way data binding becomes an absolute mess of side effects.


I've used knockout in much larger apps than this. I still don't understand what side effects people are talking about when they say this.

I don't love knockout, but I find it easier to debug than react. Mainly because stuff is synchronous, meaning the thing that caused the change is above the problem in the callstack. In react, a lot of stuff goes through an async work scheduler, so the originator of the problem is long gone.


I've built frontends that are much larger than that (and I'm not even a frontend developer) and they all worked fine.

If anything it makes it clear what's going on and when, which is important for the kind of stuff I do which has a lot of interconnected components which are constantly refreshing.


theyre really not mucking about - just a cursory play in the live preview and it promises to solve basically 99% of the weirdness I encounter in my projects. it makes sense that automatic reactivity for any let was always overkill, and the use of $: in complex scenarios got stringy. $state / $derived / $effect seems elegant and I'm sure will make everyday grokking + maintenance easier ("ergonomics"). bigup


This looks great. Stores are one of the unexpected pleasures of Svelte and this seems like it will extend them both in terms of power and also grokability


I'm evaluating Svelte for a project. The previous Svelte syntax governing reactivity is easier to reason about. For what it's worth, I don't understand the new proposal after several readings. I suggest that the Svelte team pause and consider feedback for a year before jumping into a what appears to be a wrong design direction.


Had the opposite experience. It seems intuitive and a step forward making the API clearer. It also eliminates a bunch of potential footguns at the same time.


Interesting that signals are coming back hard - Elm had and removed signals due to the learning curve and complexity. With solidjs I pretty immediately ran into the gotchas of signals. I like that reactivity is explicit rather than implicit in svelte 5 - implicit reactivity makes debugging stale views pretty unintuitive.


Yes. Signals are a wonderful mechanism, but they do come with headaches. Our goal was very much to adopt the elegant reactivity model without all the downsides, and we've approached this by making them an under-the-hood implementation detail that you don't interact with directly.


Hmmm. Perhaps "intrinsic" would have been ok for this? "a function which a compiler implements directly". In any case, it really seems like mainstream frontend programming has gone too far, and has started parodying itself... Runes... sigh :-p

Facebook itself (and FB messenger) are pretty buggy apps that are built on React, so not even the "masters" know how to do React properly, judging by the results... To be honest, I don't know that the whole thing that KnockoutJS started is really necessary. These days I prefer to work with the DOM directly when possible. http://domenlightenment.com/ is a good resource for people wanting to explore how to implement HTML5 applications, going back to the basics.


Obviously there are huge similarities to solid-js and other signals based framework with creating a signal, creating computed/derived, creating effects, etc. Would it be fair to say that Svelte 5 is going to more "runtime reactivity" rather than compiled time?


What I like about Imba is that you can update a variable, and the result in the view/page is updated, without any special syntax.

  let count = 0

  def increment
    count++

  tag App
    <self>
      <button @click=increment> "Increment"
      <div> "Count: {count}"

  imba.mount <App>
Try this example here: https://scrimba.com/scrim/cpbmKzsq

(Imba is a compile-to-js language that includes JS/HTML/CSS and a react-like framework all as part of the language. https://www.imba.io)


Imba is the only sane framework (and mithril used to be) because it actually uses "events" as the driver of state which makes sense since the web is event driven and allows you to avoid runes, horcruxes and incantations.


It's pretty cool to see the direction this framework is taking. It was already easy enough to work on Svelte, but now it's even easier. Especially if you're familiar with a framework like Vue or React. Performance seems to have improved quite a bit too.

GG


> Isn't it better if let count is reactive by default?

> Well, no. The reality is that as applications grow in complexity, figuring out which values are reactive and which aren't can get tricky.

People keep re-learning that there's a certain amount of context that needs to be explicit, and you can't just imply everything. Just like when ruby and python made the mistake of getting rid of let/contst/var/etc and programmers said wait no that's a bad idea, now it just makes everyone's job harder, because neither the compiler nor the developer can figure out what context something belongs to.


Someone with Svelte experience please help me understand: what did "tricky" mean here? Tricky to compile, tricky for readability, tricky to design, what?


Implicit reactive `let` statements make the code harder to understand for humans AND the compiler. This new explicit state pattern even simplifies designing. Now reactive state can work outside of components and across files as you would expect. It was tricky in all three ways.


I see these changes as net positive in the long run. Especially since it sounds like performance is getting a boost as well. The $props rune isn't something I realized I needed, but it definitely clears up code clarity. The $effect runes makes people think we are going down the React useEffect route... but I didn't see a dependency array attached there waiting to obliterate performance? I'm all for removing a tiny piece of Svelte magic to improve code clarity and performance gains. Seems like a big win to me. Thanks Rich and team!


> The $effect runes makes people think we are going down the React useEffect route... but I didn't see a dependency array attached there waiting to obliterate performance?

This is exactly what SolidJS already does, and SolidJS is #1 in almost all performance benchmarks.


I feel weird that runes are being used in `.js` files without explicit imports. This means some `.js` files without runes can still be interpreted independently without being compiled, but some `.js` files with using runes will not (how do I tell my editor to not warn about these runes while still being `.js/.ts` files?) . For components, using `.svelte` instead of something like `.jsx` allowed avoiding this kind of issue. What would be a good solution to this? Would explicit imports fix this issue?


If you like this, I recommend you also look into SolidJS, which is basically this idea with less compiler magic and fewer dollar signs (and more JSX).

It also comes with a built-in model layer called Stores which is genius in its simplicity. In React land I’ve used Flux, Redux, MobX, mobx-state-tree, zustand and pullstate, and IMO Solid Stores beats them all (because Solid makes this possible, not because those libs are dumb)

https://www.solidjs.com/


Why didn't you like mobx then? In the end, it's just implicit signals (where modifying the signal is done by the proxy)


What is different about stores compared to what React offers?


I snooped around Rich's GitHub history and found he's working on esrap[1], a package to convert an AST into code. It uses Bun for development and testing!

Crazy theory: esrap will be part of a transpiler that converts Svelte 4 code to Svelte 5 code. I'm not sure if that's actually the case or if it's even technically possible. But it would be really cool!

[1] https://github.com/Rich-Harris/esrap


Congrats on the announcement! This seems like an impressive step forward to accommodate larger Svelte apps while making the language simpler.

One thing that popped out was that it seems like .js files will also need to be transformed now to accommodate the $ to rune translation.

Feature request to make that optional, perhaps something like:

  import { rune } from "svelte/rune"
  let $count = rune(0)
Oh, one other thing. Will reactivity apply to nested fields in objects and arrays?


"step forward" lmao


For a large code base, this is a massive step backwards. Open up a Svelte file and try to figure out which, if any of these, are reactive:

  <script>
  let thing_a = createThingA()
  let thing_b = createThingB()
  </script>
There's no hints from the Svelte language. There's no hints from the tooling. You have to manually open up both of those functions to see what they're doing. For a large code base, they probably just call another layer of utility functions so you that's another level to dig deeper.

And that's on top of plain *.js/*.ts suddenly being hi-jacked. New team members can look at the *.svelte extension and know to go look at Svelte documentation. Why would they think to do that for plain *.js? They already know JavaScript.


I dont use Svelte or react, im sure its lovely and solves real problems. And maybe im just getting old, but over the last 20 years all evidence I have is that "magic" is a trap. Its so strange to me to see such a high profile project leaning into it like this. Youre writing javascript, but the way you must reason about what your code is doing is so different than javascript.


React gets a bad rap because of all the rubbish built around it, but if you do ever want to try the declarative model over vanilla/jQuery, React is actually exactly what you want if you want to avoid compile time magic. The only thing happening at compile time with React is a line-for-line swap from JSX tags:

  <foo bar="baz">{boop}</foo>
to a createElement function call:

  React.createElement("foo", { bar: "baz" }, ...boop);
Other than that it's entirely Javascript. No templates, computed/derived values or any of that other bullshit. You could probably implement the compile step in like 5 lines of code.

I've built big projects in Vue and find it almost impossible to find a reason to use it. Svelte looks cut from the same cloth. They just fundamentally have the wrong approach.


And you can eschew the JSX syntax entirely with nothing but a small cost to dev ergonomics.

A company I worked at had a O(1 MLoC) React frontend with no JSX at all for a long period of time due to the Typescript compatibility issue, just `export const El = React.createElement`


Fair points, though React has hugely complex runtime magic. SolidJS's compiler magic is just as simple while also having much a simpler runtime.


yes, good point, I shouldnt have evoked react itself, its everything else thats been built on top of it. But yes, Vue is exactly what I mean. Its so difficult to reason about how things work unless you live in it all day every day.


Putting the runic terminology aside and looking into how the signal primitive is implemented should dispel the magic. I learned a lot from examining preact's implementation: https://github.com/preactjs/signals/blob/main/packages/core/...


It's amazing how far back all the research and experimentation goes on reactive Web/JS tech, e.g. Brown PLT's work on Flapjax starting back in 2006, even before the JS renaissance kicked off by googl's V8!

https://github.com/brownplt/flapjax

https://cs.brown.edu/~sk/Publications/Papers/Published/mgbcg...

http://static.cs.brown.edu/research/pubs/theses/ugrad/2007/l...

It might be interesting to do a compare/contrast with v5's Runes and Flapjax's implementations.


> Like every other framework, we've come to the realisation that Knockout was right all along.

And we are back full-circle ;)


I'm not a website programmer like most people here (I work mostly in C and ARM assembly) so can someone knowledgeable on this topic please explain what is the purpose and background of this?

Also, I don't really understand why it's at the top of HN either, is this a groundbreaking change to whatever Svelte is?


jQuery changed the game for frontend web development. Instead of static pages on the browser, interactivity for the client-side proliferated because DX on top of jQuery was way better. Then they started cursing jQuery for its limitations.

Then came React -- which again changed the game for frontend web development. Instead of wonky scripts and targetting CSS classes, you get a modular and reactive approach in building the web. Then they started cursing React because of performance issues and implementation complexities.

Svelte was designed to behave like React but perform better and reduce the implementation complexities. I had the chance to work with Svelte 1 back then and as a React developer, it would really make you think "Why did React do that?".

This is probably on top of HN because people loved Svelte too -- but some followers are now questioning the direction as this change is gravitating towards solutions that React already implemented. As it happens, React did solve a lot of problems for the frontend, and they really nailed it.


Thank you for explaining.


"At first glance, this might seem like a step back — perhaps even un-Svelte-like. Isn't it better if let count is reactive by default? Well, no. The reality is that as applications grow in complexity, figuring out which values are reactive and which aren't can get tricky. And the heuristic only works for let declarations at the top level of a component, which can cause confusion. Having code behave one way inside .svelte files and another inside .js can make it hard to refactor code, for example if you need to turn something into a store so that you can use it in multiple places."

This is absolutely true. I have been confused many times figuring out what are reactive states and what are not.

I never knew Svelte needs changes like this, but seeing this, it sounds like a good plan.


it is reactive by default, just if you use $: and the dependent value never updated, it would give undefined, personally i never got this kind of issue XD so I'll stick with old syntax until I really2 need $state/$effect/$derived


Exporting functions makes so much sense. Had asked myself why this doesn't work many times.


Exporting a function from a Svelte component has been a feature at least since Svelte v3, in 2019.


As someone who just started Svelte two days ago, my naïve take is that this feels like adding verbosity.

1. Is there no way for the compiler to automatically, recursively find reactive dependencies?

2. Assuming no, is there not a more terse way to decorate reactive expressions?


Instead of finding reactive dependencies at compile time, `$effect` and `$derived` automatically track dependencies at runtime. This might feel like it would result in a performance decrease, but it is what SolidJS has been doing. And SolidJS is #1 in most performance benchmarks!


Runes remind me of Recoil atoms/selectors: https://recoiljs.org/docs/introduction/core-concepts


Guess that puts an end to the whole spiel of "You already know Svelte"


Web tech. So much noise about trivial things.


Hey man, I'm busy making a career here concatenating strings.


I don't know svelte, but it seems like every front end framework introduces 'new' reactivity concepts deep into it's lifetime. A lot of them start looking like react hooks too.


Why not just call it signal and computed? (instead of state and derived)


After reading this from rich_harris:

”Basically, you can only modify state _where it's declared_. If you want to allow the 'outside world' to modify that state, you need to expose a function that does so. This is unlike cases where you're passing around an observable object where anyone with a reference, which they need for reading, can also write to it by doing `thing.value += 1`. This is something Solid gets right — you can only change a signal's value if you have a reference to its setter.”

I now realize that this isn’t exactly the same thing as Vues ref of Preacts signal. Maybe its own name is good after all.


Angular right?


Yes, and Preact.

Vue also uses ”computed”, but ”ref” instead if signal. It just strikes me that a lot of frameworks seem to implement the same thing (signals) but use different names for it.


Solid is still the best implementation of fine grained reactivity.


Svelte has never looked more like Vue to me. I don't mean this as a dig, I think it looks great.

It's just even less obvious to me why I might pick it over Vue at this point.


Svelte 5 is just Vue 3 with a smaller ecosystem. That's basically it.


There's a lot of comments here so I may be asking a question that was already answered, but will the runes be explicitly importable in non-Svelte files? Or does it use an approach similar to testing frameworks like Jest and Vitest where you have access to them as globals? I'm thinking of the implications for TypeScript. I usually opt out of globals and import explicitly when I can.


What about scoped reactivity? Sometimes you need to react on some of the states not all of them. Right now we are achieving this by passing function with arguments to react on to $: but with $derived and $effect it seems to be not possible because it takes variables from every function passed. Are there any plans how to resolve this? Also nested $effect instead of onMount looks awfull and to be honest is less readable.


You can use `untrack` [1] when you don't want to react to some state inside an effect.

You can still use `onMount`. It's not deprecated [2], although `$effect` could be used similarly going forward.

[1] https://svelte-5-preview.vercel.app/docs/functions#untrack

[2] https://svelte-5-preview.vercel.app/docs/runes#$effect-what-...


Perl called these sigils. They were incredibly useful and powerful, but the dev community decided that they hated them.


Apart from the superficial use of the $ sign, what else is Perl about any of this?


Parent made no such comparison to perl, but merely observed a lesson learned from perl.


There’s almost nothing that Perl hasn’t done before and first.


Everyone comparing to React but this looks similar to RxJS Observables as well. Don't leave out us Angular folks!


Doesn’t it basically another implementation of MobX? Seems like Vue, Signals, Angular 14 all copy this reactive pattern which IMO is simplest to write testable apps.

The only drawback with MobX is that’s its upadates are as granular as components but in practice it’s not hard to optimise manually.


This is what happens when bored developers just have to improve something that doesn't need improving.


Svelte 3 came out in early 2019, and the framework hasn't really changed much in that time — one thing we can't be accused of is making changes for changes' sake.

But since then, the front end community has discovered valuable new ideas and techniques. Meanwhile, people have encountered the limits of the Svelte 3 approach. Svelte is really good at solving most of the problems you throw at it, but it's not perfect. The changes we announced today are _necessary_.

If you're not convinced, I encourage you to watch this video, where I talk about why that is: https://www.youtube.com/watch?v=RVnxF3j3N8U


That's a great - and funny - video. Nicely done!


I think Rich clearly demonstrated the pitfalls in today's Svelte and the introduction of runes seemed like a great solution to them. I'm not a Svelte user but this new feature does seem clearer to me when looking at the refactored code than the magic reactivity behind the `$` syntax. Overall a net win in my opinion.


I was a bit apprehensive reading the comments here, but reading the presented changes, I'm actually quite happy.

I built two Svelte apps. I liked using Svelte but was a bit annoyed by the aspects these changes are fixing.

The code also seems easier to write and to understand.

My feeling that the Svelte team has taste is strengthened.


Always gotta be someone like you in the crowd eh?

Perhaps, just perhaps it's a good change for a lot of people?


These updates lean heavily towards how Vue approaches setting reactivity.

Is there any slam-dunk case for using Svelte over Vue?


I recently wrote a game in Svelte 4, and went through a transition from using the <script>/$ reactivity to stores. This looks MUCH nicer to deal with.

Their examples seem to be missing some imports? Trying to use $state as shown with svelte@5.0.6 gives "ReferenceError: state is not defined".


No, runes like $state do not need to be imported. They're similar to import() that they look similar to functions, but are keywords built into the language.


Make sure you opt in to use runes!

You can do it project wide or per component: https://svelte-5-preview.vercel.app/docs/runes


> The easiest way to opt in to runes mode is to just start using them in your code.

Opt-in is optional, no?


Whoops, I missed that. Good catch! I'm not sure how tln's problem is happening then.


Unless I misunderstood, Svelte 5 'runes' appears to be just 'markers' making explicit what used to be implicit with two noteworthy benefits:

- simpler compiler implementation - easier to identify moving parts

If so then the intro article needs a rewrite to be simpler without unnecessary districting details.


So it's a kind of type system using a kind of Hungarian notation? :Flashbacks to Win32 intensify:

I think a real type system (i.e. compiler checked, rather than relying on falibilities of human programmers) would be a better solution. If Svelte already has a compiler why not implement this as part of it?


I don't really know them well enough yet but some of these frameworks do seem to be in need of some compiler engineers e.g. with this compile time reactivity for example I was surprised there was no mention of dataflow analysis.


Can you clarify what you mean? I'm not sure how you watched/read that and got "type system" out of it.


Adding annotations (runes) to expressions to describe their properties is basically putting type annotations on expressions. Maybe I missed something, but that what it seemed like to me.


Is this the turning point where svelte start to over engineer stuff and becomes just like other frameworks/libraries? The whole selling point of svelte is simplicity and straightforward implementation, you over complicate it, I will just use something else, popular at least.


Seems like Svelte 5 is conceptually simpler and significantly less "clever" than its predecessors. No more playing fast and loose with the semantics of Javascript syntax. It was the hoops Svelte had to go through to provide reactivity that always that always seemed like over-engineering to me.


This is cool, Svelte5 may be the lightest signal-based library. I hope that the old, outdated things mentioned at the end of the article will be finally removed in the future. I like it's API for signals more than in SolidJS returning an array with setter and getter.


I have a complicated spaghetti object that I need to render. Given:

    let spaghetti = $state(uglyMess)
Does `uglyMess.thingOne[1].anotherThing = { moreMess }` re-render the whole tree or just the children of `uglyMess.thingOne[1].anotherThing`?


If you created `anotherThing` as nested state, then just the children!

See this for a real example: https://svelte-5-preview.vercel.app/docs/fine-grained-reacti...

Here is the same thing in SolidJS with more explanation: https://www.solidjs.com/tutorial/stores_nested_reactivity


I'm cautiously optimistic for this. My first instinct is that it doesn't seem to provide much value add over just sticking with stores, which I think were already thoughtfully designed, but I won't knock it till I've tried it.


What you don't get about React is that, in React, the reactivity atom is the component itself, not those state in useState. It's encapsulated if you look from the outside. And what you really care is reactivity at the component level.


Yeah, you know that thing Vue did with the composition API that a bunch of their users didn't like and then subsequently turned to Svelte over? Well, it turns out they were right and we're going to do the same thing.


Can anyone share how this change would help with your current app/library? Would be great if we get to see how this change leads to real world use case improvement.


For me, in both Firefox and Chrome (but not Safari), all the code samples look like this:

https://imgur.com/yGXHb1h

Anyone know what's going on here?


> Like every other framework, we've come to the realisation that Knockout was right all along.

I never had so much fun and understanding of a UI framework as I did when working with KnowckoutJS and DurandalJS way back when.


I must say, when I see `$` in js, I think it is going to refer to a DOM element. Maybe the new kids don't have those vestigial jquery instincts, but I dislike the use of $ for non-DOM element things.


Lots of roundabout thinking to eventually reinvent observable


Honestly, quite the over-engineered solution for a problem they were supposed to solve. What does svelte brings to the table with this much complexity? Speed?


As I understand it, this should make it possible to subscribe to non-top-level stores and avoid having to use the horrible hack from svelte-subscribe.


Can you build a $derived from multiple other $derived?

If yes, how do you deal with two $derived sharing some dependencies?

Will the end result see temporary, half-updated values?


> Can you build a $derived from multiple other $derived?

Yes

> Will the end result see temporary, half-updated values?

No. It uses a push-pull mechanism — dependency changes don't result in a re-evaluation until something asks for the value, meaning derivations are 'glitch-free'


Nice! :)


All of these frameworks like react vue svelte solid are basically the same framework.

If you actually want something different and better look at Imba.


This seems better and makes JS uniform all across but I hope we don't go to the nightmare called hooks. useXXX - please no.


The canvas painting / $effect() demo on the video was super cool! Is the source publicly available somewhere?


Aw man... It's spreading. Soon Svelte will be identical to Vue, React and to a degree Angular. Why bother


This is all great stuff but my silly mind was expecting new cool features from Svelte 5, not only DX improvements.


If you collect them all, does Douglas Crockford magically appear to grant you three wishes?


Same thing but without magic - Angular Signals.

I do not like magic in code.


I never expected that in 2023 someone will still be inventing new abstractions in JavaScript.

I see it a bit like chess now, there will always be people making progress on a particular opening and variant.


All these compilers and language forks, man...


Isn’t this just qwik?

Or have I missed something important?


It is actually taking inspiration from vue https://vuejs.org/guide/extras/reactivity-transform.html

They are too close for the similarities to be a mere coincidence


Now the only thing missing is JSX


Isn’t this just Qwik?

Or am I missing something important?


It’s nothing like Qwik, nothing at all. Qwik’s key selling point is being what they call resumable. Svelte is not that.


Svelte slowly shapeshifting into jquery. Day after day, methodical evolution.


Apart from the superficial use of the $ sign, what else is jQuery about any of this?


Principle of charity, perhaps they're just referring to how much easier & ergonomic it's becoming over time! ;)


hot takes get a lot of upvotes on Hacker News, I've even done it myself recently and it works (despite me knowing very little about the topic).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: