by benmccann on 9/20/23, 1:59 PM with 386 comments
by EvanYou on 9/21/23, 2:07 AM
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...
by satvikpendem on 9/20/23, 2:47 PM
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.
by chrismorgan on 9/20/23, 2:38 PM
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.
by ranting-moth on 9/20/23, 3:20 PM
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.
by wentin on 9/20/23, 4:12 PM
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?
by pimterry on 9/20/23, 3:28 PM
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).
by mbStavola on 9/20/23, 3:04 PM
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)!`;
by jasim on 9/20/23, 3:02 PM
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.
by schietegal on 9/20/23, 2:18 PM
by cornfutes on 9/20/23, 3:08 PM
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.
by handsaway on 9/20/23, 2:59 PM
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.
by Dnguyen on 9/20/23, 3:13 PM
by epmatsw on 9/20/23, 2:20 PM
by pier25 on 9/20/23, 2:26 PM
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?
by hinkley on 9/20/23, 2:45 PM
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.
by wirahx on 9/20/23, 2:17 PM
Svelte for Apps. Svelte for Sites.
by orangepanda on 9/20/23, 2:30 PM
That said, svelte5 does solve a lot of problems that stop me from trying it.
by onsclom on 9/20/23, 6:55 PM
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.
by bluelightning2k on 9/20/23, 3:25 PM
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.
by spencerchubb on 9/20/23, 4:36 PM
by 4kimov on 9/20/23, 2:52 PM
by chrisco255 on 9/20/23, 2:22 PM
Nope, nope. Been there, done that, with 2-way data binding and never going back.
by kalpolintrol on 9/20/23, 5:27 PM
by zztop44 on 9/20/23, 2:21 PM
by jussayin on 9/20/23, 2:51 PM
by gsuuon on 9/20/23, 3:48 PM
by emmanueloga_ on 9/20/23, 2:53 PM
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.
by lominming on 9/20/23, 5:40 PM
by trafnar on 9/20/23, 4:53 PM
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)
by viviansolide on 9/20/23, 3:33 PM
GG
by sbjs on 9/20/23, 2:49 PM
> 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.
by crackinmalackin on 9/20/23, 5:06 PM
by Heechul on 9/21/23, 4:36 AM
by skrebbel on 9/20/23, 3:04 PM
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)
by onsclom on 9/20/23, 5:32 PM
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!
by matthewmueller on 9/20/23, 4:13 PM
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?by adantes on 9/23/23, 4:55 PM
<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.
by netcraft on 9/20/23, 2:32 PM
by michaelsbradley on 9/20/23, 7:45 PM
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.
by beders on 9/20/23, 5:13 PM
And we are back full-circle ;)
by vorbiscuit on 9/20/23, 2:51 PM
Also, I don't really understand why it's at the top of HN either, is this a groundbreaking change to whatever Svelte is?
by supz_k on 9/20/23, 2:40 PM
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.
by amadeuspagel on 9/20/23, 2:34 PM
by notfed on 9/20/23, 4:01 PM
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?
by Nezteb on 9/20/23, 2:42 PM
by makingstuffs on 9/20/23, 4:01 PM
by mgaunard on 9/20/23, 2:51 PM
by klysm on 9/20/23, 2:39 PM
by joeldrake on 9/20/23, 2:55 PM
by zenbai on 9/20/23, 4:31 PM
by barrongineer on 9/20/23, 4:15 PM
It's just even less obvious to me why I might pick it over Vue at this point.
by codelikeawolf on 9/21/23, 7:45 AM
by wikoj1021 on 9/20/23, 4:03 PM
by tootie on 9/20/23, 2:25 PM
by jzig on 9/20/23, 3:13 PM
by machiaweliczny on 9/21/23, 12:12 PM
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.
by schnebbau on 9/20/23, 2:22 PM
by pupppet on 9/20/23, 3:28 PM
Is there any slam-dunk case for using Svelte over Vue?
by tln on 9/20/23, 2:48 PM
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".
by donpark on 9/20/23, 4:46 PM
- simpler compiler implementation - easier to identify moving parts
If so then the intro article needs a rewrite to be simpler without unnecessary districting details.
by noelwelsh on 9/20/23, 2:33 PM
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?
by tamimio on 9/20/23, 7:22 PM
by ptrwis on 9/20/23, 5:51 PM
by jcuenod on 9/20/23, 7:18 PM
let spaghetti = $state(uglyMess)
Does `uglyMess.thingOne[1].anotherThing = { moreMess }` re-render the whole tree or just the children of `uglyMess.thingOne[1].anotherThing`?by keb_ on 9/20/23, 5:15 PM
by revskill on 9/20/23, 5:38 PM
by jaeming on 9/21/23, 6:37 AM
by cayter on 9/23/23, 12:20 PM
by aarpmcgee on 9/20/23, 4:54 PM
Anyone know what's going on here?
by bilekas on 9/20/23, 3:14 PM
I never had so much fun and understanding of a UI framework as I did when working with KnowckoutJS and DurandalJS way back when.
by jcuenod on 9/20/23, 7:21 PM
by nsonha on 9/20/23, 7:49 PM
by meiraleal on 9/20/23, 8:00 PM
by jamincan on 9/20/23, 2:37 PM
by aatd86 on 9/20/23, 7:03 PM
If yes, how do you deal with two $derived sharing some dependencies?
Will the end result see temporary, half-updated values?
by ilrwbwrkhv on 9/20/23, 6:01 PM
If you actually want something different and better look at Imba.
by wg0 on 9/20/23, 2:42 PM
by tipiirai on 9/21/23, 7:21 AM
by lakomen on 9/21/23, 2:13 PM
by yewenjie on 9/20/23, 3:48 PM
by ramesh31 on 9/20/23, 5:42 PM
by EugeneOZ on 9/20/23, 2:46 PM
I do not like magic in code.
by karol on 9/20/23, 2:28 PM
I see it a bit like chess now, there will always be people making progress on a particular opening and variant.
by spankalee on 9/20/23, 2:48 PM
by sambeau on 9/20/23, 2:42 PM
Or have I missed something important?
by jcuenod on 9/20/23, 5:56 PM
by sambeau on 9/20/23, 2:42 PM
Or am I missing something important?
by high_priest on 9/20/23, 2:15 PM