The Physics of Solid 2.0
By Ryan Carniato
Summary
Topics Covered
- AI Images Beat Lazy Stock Photos
- Colorless Async Pushes Blocks to Leaves
- AI Writes Better Than Raw Human Drafts
- Effects Need Known Dependencies Pre-Async
- React's Delayed Commits Ensure Consistency
Full Transcript
All right, everyone. Welcome to my stream today.
I've been last minute doing bug fixes, which is pretty par for the course here.
It's one of those things. I didn't
advertise a stream earlier just because I didn't have time to create a cover and then as soon as I'm like ready to advertise it, I realized that there's actually a pretty big regression um that
would actually get in the way of me doing the stream. So, I fixed that um this morning. Um, but I still haven't
this morning. Um, but I still haven't done the latest uh the latest stuff. So, um, for like a new beta release. So, I'm just actually in
beta release. So, I'm just actually in the process of pushing that out right now.
Nice. Okay. So, everything is perfectly clean now. So, I'm just about to press
clean now. So, I'm just about to press go on on on that um PMP change set version. And I know you guys can't see
version. And I know you guys can't see what I'm doing cuz it's on my other computer, but I'm very excited today to to go a little deeper into Solid 2.0. We
we've talked a lot of theoretical stuff.
And then the last stream, I knew that the beta was going to be pretty broken out the gate, so I just used it as a excuse to kind of test it, right? Um,
today I've fixed a lot of stuff in the last two weeks. So today I think we can actually like showcase some of the mechanics a little bit better. I mean
not not that last week or two weeks ago didn't showcase some pretty cool stuff.
But yeah, anyways, yeah, everyone come say hi in the chat. The AI thumbnails are going out of town. I want to talk about this a bit too cuz see I have a very different perspective and maybe it's because of my age and I think maybe
this is going to be one of those things that like you know you know when people call people boomers or whatever you know
that kind of perspective. Um, I I think my perspective on on AI is kind of like they'll be probably making fun of millennials, you know, in a few years.
Um because I don't like a lot of people see a lot of AI stuff and they consider it cringe because it you know I understand because
of the the the low amount of effort um it takes to generate or create stuff but um
if you were going to spend a low amount of effort anyway I think the the the output's better. I I don't I I I don't I
output's better. I I don't I I I don't I don't like I I've been getting a lot of push back on using AI generated images and I'm like thinking about what I would
actually use instead and I mean we could we can look at this on stream you know actually you know give give me a second here but let's look at the YouTube
covers that I create versus the YouTube covers when an artist creates them versus the YouTube covers that AI generates. um for
me and you tell me which ones are the best or the worst, but we can do we can do this right now.
Yeah, we're going to talk about this article uh a bunch today because I I I realized kind of like in hindsight like I'm very much down a path and the article is an introduction of some topics but a lot of people are like yeah
so what what's this mean for solid? I'm
like I thought I laid that out and but I like I didn't connect those dots. So
yeah, I would many of those. Yeah. Yeah. Well,
I I am a programmer, not a visual artist. So, I'm I'm going I'm This is
artist. So, I'm I'm going I'm This is kind of what I want to Let's Let's just do this right now cuz I honestly I keep on getting this feedback and I I'm
sorry, you guys. I I think it's a very I think you kind of got to look at it for what it is. So, let's let's look here.
Let's go to my YouTube channel and uh yeah, let's just call it out right here.
Okay. So
these are some video covers that I made myself. So these ones actually AI
myself. So these ones actually AI generated this image uh inside the painting. Uh David made this image. I
painting. Uh David made this image. I
did this one and I did this one by just putting these three labels on top of a pre-made image. So I didn't really make
pre-made image. So I didn't really make this image. Okay. But let's look at my
this image. Okay. But let's look at my live streams because there's there's more examples here.
This is a live stream cover where I took a stock image. This is an AI generated image. Actually, let's just go right off
image. Actually, let's just go right off the top. AI generated. AI generated. AI
the top. AI generated. AI generated. AI
generated. Um,
actually AI generated, but then I put the labels on top.
Uh, this one is someone's art, so I gave them credit for it. I found I found someone's art. This one is
someone's art. This one is um AI generated. This one I found a stock image and put the word async
signals above. This one I found a stock
signals above. This one I found a stock image and put microf's done first. Uh,
this one's a screen cap from a talk.
This one someone an artist actually created. They took the image and they
created. They took the image and they put it together. Or no, maybe I did this one. I feel like this is better than my
one. I feel like this is better than my average guys from Marco made that one.
This is from a slide. I took a pre-existing image and put a slide on it. This one was AI generated. This one
it. This one was AI generated. This one
I took a table and put my face on it.
This one I took an image, put my face on it. This one I took a photo that I took
it. This one I took a photo that I took on a mountain and put my face on it. Um
I image put my face on it. Put
this one actually. I add the layer some fire on top and a logo on top of a sci-fi image. Screenshot image. Oh yeah,
sci-fi image. Screenshot image. Oh yeah,
look at this one. I just took an image.
I also just took an image here. This
one's AI generated. Kind of looks weird.
I I like that the these old AI generated ones are a lot worse than the new ones.
Like they actually garble stuff in a weird way. Um
weird way. Um took some like Iron Maiden background and put a logo on it. Someone an artist made this one.
My my point is I I I I don't An artist made this one too. I don't know if this was AI help, but this was made by an artist. Um stock image. I I my point is
artist. Um stock image. I I my point is I I I actually think on average the AI images are better than like when I do something like this, like where I just
like take some stock image and put a font on it. I
for articles. I love lowfidelity handdrawn sketches than AI. Yeah, I mean I'm not going to hand draw those sketches. We can do the same exercise on
sketches. We can do the same exercise on dev tube because I mean I'm coming I forget where I got
that image from with the solid in there. Uh, someone
might have created it, but if you look, my articles are infamous for using like clips of Twitter and which is why a lot of them are no
longer around or meme drawings because literally I'm not creating the the art, right? Like I find like stock image clips and then I find
memes to support them. Like
occasionally there's diagrams. But see, one of the things I learned really early on with articles is especially dense articles where there's a whole freaking lot of text and a lot to get on, you have to kind of force the gaps in for your readers um yourself because
otherwise if you just give them the blob, it's going to feel heavy. It is
already heavy. So things you'll see that I'll do very often is between sections I'll add extra like line spacing like these kind of dividers even though I don't really need to. I I learned this
earlier from the from the from editors when writing articles. is just you're writing highly technical articles that were very dense and people will probably reread sections multiple times and
they'll try and get through it all.
Breaking up the flow is incredibly important. Even if it's just like for
important. Even if it's just like for spacing things like these are just blank spots without any images. The images let them like temporarily relax their brain.
So, like there's a whole like I I will fight people on this AI image thing because to me it is 100% improvement. I
I don't understand how people could even argue otherwise.
They look cheap, but are they worse than me literally going pixels?
Atomic atoms in space.
All right.
Reactivity expanded cover chopped like that. This is basically
that. This is basically what you're getting in in here. We go.
This one looks like one I would use with a like graphic designers can do the the work, but am I going to hire graphic designers every time I want to write something?
This is it's just completely insane to me the push back on the AI image generation stuff. I I I I get like if
generation stuff. I I I I get like if that's not the pri like primary goal of the thing and the actual goal is mechanical in terms of actually spacing
and writing like as I said the memes where they fit are a lot better but the images are also valuable and if you look I I've been using this pattern forever um even if it's not I also you know
obviously have code examples where I can do it but in stuff that's fairly like conclusion like what is this it's it's a spinning top. I mean, some of these make
spinning top. I mean, some of these make you think more, but let's compare this to like um an a AI generated image, right? I actually think this cover makes
right? I actually think this cover makes a lot of sense, right? You have like signals kind of like flowing through and then you have like this rocky hazardous place, but then where React sits and like it actually has more contextual
meaning in terms of what the actual article is about, right? Sometimes these
text things are a little bit existence, but like it actually better corresponds with what is is being said. And obviously if I don't like the
said. And obviously if I don't like the images like I kind of tweak or look at the look at the like the kind of takeaway, right? Like I the the art of
takeaway, right? Like I the the art of of actually choosing these images is like a little bit tricky anyways like client side routing without the JavaScript. Does that cover make any
JavaScript. Does that cover make any sense to you? Like it makes sense to me.
I'm playing on it. I apply the same kind of thought process into how I look at AI images when I find like an an opportunity to kind of play around with
the idea. Um, right? Like
the idea. Um, right? Like
I to me the process is the same but the results are just infinitely better. I I
don't I I don't And the funny thing is I got I've been getting push back on this repeatedly, but it's like it's not like the push back has an actual um workable suggestion or solution
behind it. It's just like I don't like
behind it. It's just like I don't like this. And it's like part of you got to
this. And it's like part of you got to go like okay well I have to think about why they don't like this and what that actually says. But then when you like
actually says. But then when you like think about the the actual output quality in a holistic sense being better, it's
hard to like really care that much about about the I don't like this.
You don't see the value in creating image yourself, then you can't pretend any image in the article adds value besides space. Yeah, that's what I'm
besides space. Yeah, that's what I'm saying. It's mostly space and then like
saying. It's mostly space and then like a little bit of like like visualization of a concept or a relational thing. Just
enough to trigger the mind to be like, "Oh, okay. I'm not I I'm getting all the
"Oh, okay. I'm not I I'm getting all the words. I'm just I'm just like, you know,
words. I'm just I'm just like, you know, I'm like it's a distraction.
Yeah, sorry. Like I I I think when when I actually like solid start
I mean some of these I work I mean I don't know I as I said this is going to be probably considered a boomer taste because take because it's or type or
millennial take or something because what I'm doing is arguably distasteful, but it's like
what it's replacing is not actually good in any like intrinsically better in any sort of way.
So like the and the people are like, "Oh, we'll just get rid of the images."
It's not that is not the solution. So
what I've done is found a way to streamline like my process to to actually make a tangible improvement.
And I my one one thing I've noticed over time is that like the AI images have gotten better and over time I I think one of the funniest things and we'll talk about this in a in a minute when we
get to this article, but I there's there's something really funny here. I I have a conversation here uh
here. I I have a conversation here uh with with a response in my in my in my uh to my article here or someone's like uh let me see here
uh where is it? Thought it was really funny.
Let's see if I can find it. It was one of the very first responses to my article.
Uh, let me see.
Okay, this one here. The uncomfortable
truth through naming signals didn't fix the async problem. They just delayed it.
React achronous was a mistake. It was a shape that constraint become visible.
The frameworks that pretend async is special case are the ones that will break first when the graph gets complex enough. Yeah, thankfully my worker two
enough. Yeah, thankfully my worker two has shown that we don't need to be mutually exclusive things. We can
consistently address async and keep all the advantage of signals. We just have to be open to it. Difference is you're building the constraints to a design instead of pretending it doesn't exist.
That's the line between a framework that teaches you something and one that gets out of your way until it doesn't.
Looking forward to seeing where solid 2.0 lands. I this was the first comment
2.0 lands. I this was the first comment response in this in the on my article and I was like wow someone gets it. you
know, like this is this this is a really reasonable, well thoughtout response and like a lot of times these are not the
kind of responses I get and then I I you know I make small clarification and the person seems legitimately excited about it. I find out later.
it. I find out later.
Are we having discussion about images and stuff? Yeah, a little bit right now.
and stuff? Yeah, a little bit right now.
Yes, these stock images are charming and authentic compared to AI generated ones.
I suppose they they feel stolen and they like and they and they and they kind of miss
a little bit. I mean,
yeah, I mean, it's tricky. The stock
images are great when the when the artists give them for free and then I can discredit them. Obviously, paying
for stock images is a whole other thing. It'd be interesting to to
thing. It'd be interesting to to basically guide the AI to have the aesthetic of stock images. Like there's
something about the the the stuff that like, as I said, really is repulsive to some people, but doesn't bother me in even the slightest.
But sorry, the reason I I I I brought up this conversation here is apparently this this isn't a real person and I was
actually talking to an AI. Um, and I had no idea idea. Someone actually pointed this out to me on X. They're like, "Do you realize this this this interaction was with an AI?" And I was like, "No, they just sounded like the most
reasonable person that I've ever come come across." And I'm like, "That should
come across." And I'm like, "That should have been my my clue." Um, if someone responds reasonably, they're probably
not a real person. Um,
and I what I'm getting at is I'm I'm expecting these lines to blur even more in the future to the point
that the that the like current distaste that we're experiencing right now is going to be basically meaningless in a short
period of time. Um,
obviously you will be able to tell, at least for a long period of time, the craftsmanship of a true expert, like of someone who's actually really good at
what they do, that's hard to to replicate. But
replicate. But um if you're not in a position to pay someone to commission your artwork
um like the funniest thing about this is we'll talk about AI writing too because I I want to talk about this a little because um and we'll get into the topic today,
but I just want I want to talk about this again because it's like again this is an example of where people's distaste of it. I read stuff
for its value. The reason I don't like AI written stuff is because it does it isn't valuable usually. It it usually regurgitates. It usually doesn't
regurgitates. It usually doesn't actually provide true insight. it
usually uh doesn't position things in a in a sensible argument. It's too like the way it thinks what's logical presents its argument isn't like really all that compelling. Sometimes it feels
like it's being like smacked at you with like a hammer. But if if an AI generated article actually had relevant content, I wouldn't care if it was AI generated.
Again, this is like such a weird constraint. It's the the content is more
constraint. It's the the content is more important than the delivery. You know
what I mean? Like there's an aesthetic artistry to certain things. Uh but if that's not your primary out go out
outgoing goal or goal, who cares? Like
the important part is to clearly communicate. It's not like
communicate. It's not like again this is why I I I get the impression that my perspective is going to age very poorly or something cuz
people might care about this stuff. But
from my perspective, it's like focusing on the wrong things. People, you know, like I don't get like okay
let's flip this example around hypothetically, right? Like
hypothetically, right? Like AI makes me feel undervalued, underappreciation. It's like the person
underappreciation. It's like the person didn't care enough.
flipped around, does it mean that the person found a more efficient way to get to the same means if the content is actually valuable? Like, I'm just I'm just I'm
valuable? Like, I'm just I'm just I'm just kind of throwing this this out here.
I there is craftsmanship in the art and if you have the time to do it, there's probably real value there. But
otherwise like who cares?
I mean, there's definitely mis Okay. And
I I want I want to give an example here because I I agree with you like from the perspective of like earlier in in in the
week before I uh before I I posted this where very clearly I basically asked AI
to write me an article, right? Um and
sorry, let me just quickly get this um this release going. I just need PM change set version. Just want to see if
I can just hit commit, so to speak, on this.
Yeah, beta 4, beta 4, beta 4, beta 4.
Okay cool.
Sorry. B2.0
beta 4. That way, like it'll all be out there by the time we're actually doing anything important. Okay, perfect. and
anything important. Okay, perfect. and
then commit that precommit. What the?
precommit. What the?
It's fine. I could freaking It's being weird right now. Um,
some weird.
Okay. Uh, but my my point is I wrote this forward here.
Oh, sorry. Just reading some chat here.
Just draw some simple sketches that help native adventure people stay on a topic like Theo and Pirate Software does. I I
will do that during my Excala draw. I
have something a thing. But like for for articles like you could be like you should spend an extra 45 minutes to an hour uh actively
working on your articles if it means the images are better or you but like I I have the code examples where they're relevant. Here's an like sometime I will
relevant. Here's an like sometime I will just use the code highlighting instead of using an image often in my articles.
Um I don't have infinite time. I this is my secondary thing. So I mean I guess you
secondary thing. So I mean I guess you can appreciate that I like you be like look I don't appreciate that you don't spend as much time as you should on this and it's like I'm looking for ways to
spend less time on it. So you know the the the the value is in the content.
We're going to do some Excalibur draw today.
If they if I AI images are not for the kind of thing, what are they for? I
mean, that's that's that's an interesting question. I mean, this is
interesting question. I mean, this is pretty much I I think the use of AI images is for like presentations or like little like Yeah.
Okay.
Okay, now let's do this pmppm build pmpp test and if this all goes well I will be releasing beta in this case imagery are side dash to
the point not the art and it's not there as the only consuming the content it's more how pacing the reading is exactly okay so I got AI to write something for me. And this is going to be relevant
me. And this is going to be relevant more to the content of the stream because I was like I had I've been talking with Copilot a ton and like going over stuff and I was like which is
more just like my think out loud thing.
Um and I was like I feel like all these aspects kind of are pointing at a bigger truth. Can you
help me like put that like get more tighter on what that truth is? And I you know so I wrote this forward and then AI wrote the
article and I've written if you've seen on the stream I've used HackMD to generate article type stuff and AI lots of times as like concept stuff just like kind of like oh you know give me a sales
pitch or a message to contributors or like some kind of like kind of like different types of writing. But you're
right, they all kind of it's not I for me with AI, it's not it's not the phrasing or the pacing as much as like the the line of argument
they take is very indicative of like their personality, right? So like for me when when I I look at this um obviously
there's a lot of AI ob like things here like uh the limiting factors no m looking for like the really there's
there's always those real like I'm just going to drop this in chat. You guys can probably pick out the AISMs like hugely.
Yes. Unsplash
was that didn't add much value anyways.
Yeah, pretty much as far as I'm so for me this is that that it's just an upgrade. Okay, so I'm I'm going to drop
upgrade. Okay, so I'm I'm going to drop this article in here. Um
the the one about determinism and you you could probably see some of the telltale signs of AI here. But on the other hand, as I said, they
like I' I've done enough of this that it's very obvious, at least for me, when I'm like writing something like I can't get AI to write the article I want to
write it. This one was is basically a
write it. This one was is basically a point form list, so it kind of works.
Um, but you can you can never get it to write a real human feeling narrative. I
find um ASIC is no longer a side effect. It's
part of where the values identity limits need that do. I I do think we should this this whole thing is probably worth talking about. March 9th was that did I
talking about. March 9th was that did I cover that on my last stream 14 days ago would have been the 4th. So yeah, this
is we should talk about this content on thing. But my my point is like um
thing. But my my point is like um I I do find myself using AI in new and interesting ways while I'm I'm I'm
working on on on on stuff like for my article that I did post the one that we're going to go into today about React and variance thing. I did I I I I basically asked Copilot and I extracted
this out at the time because I didn't want to like lose in the conversation. I
said let's see the outline below. Was it
optimized for for that title sharp competing structure to both value where is it depending the article now reframes and has two archers strange still correct basically
um I wanted to I I asked AI at the very beginning I was like I want to do an article about this but I want to make sure that I don't miss any of the key points. Can you like give me like a a
points. Can you like give me like a a rough outline of like all the points I should touch? and
should touch? and it it did um and kind of like gave it like sections. The funniest thing is if
like sections. The funniest thing is if if you actually followed this as for writing your article, you wouldn't end up with a very good article in my opinion. And in fact uh this is the kind
opinion. And in fact uh this is the kind this is kind of what AI would have generated if AI had written the last article I wrote because it would have been like two
rejected because two red the sync constraints print principles color sync track the reactive the right variance but the wrong model around them shared constraints both varants ran into modern
UI's default stream transitions cannot optional color nullable y for suspense blah blah blah blah design decisions got right must be except from commit blah blah blah react wrong. We're
predictable double renders effect using world to hook. What's all too like you could already see that it's trying to build a narrative where it's like us versus them, you know, cuz it's very to the point. This the way react sorry AI
the point. This the way react sorry AI doesn't like leaving things open-ended.
It doesn't like talking about general truths. It's like it wants something
truths. It's like it wants something actionable out of it. So, it's like every single section in here is like structured in this kind of like and this is why you should do solid blah blah
blah blah blah blah. And it's just like it's it's a bit much. And this is kind of like like
I I you could almost never trust like I I can already see the narrative gap that you like that you find in these canarles. AI is biased towards sounding
canarles. AI is biased towards sounding smart.
Yeah, everything is bullet points. Yeah,
I mean I asked for if you actually want to see I could probably pull back the original prompt on on on on this, but I was like, "Give me an outline. Do not
write me an article. just give me an outline of what you think the key talking points would be around blank, right? And then I like I I I took this
right? And then I like I I I took this and I just started writing and then I was like, you know, and I kind of just like I was like, okay, that this is not the narrative. But this is useful for me
the narrative. But this is useful for me was it was very helpful for me to be be able to identify like like I mean I already knew this stuff, but it kind of laid it out. So I was like
because the big the hardest part about when I write articles is and my normal process is that I end up just like writing huge blobs per sections and then deleting like half the paragraphs
because I write too much and then I go back and I'm like okay I realize something in this part but I need to get it back into the original message. So I end up rewriting it again
message. So I end up rewriting it again and then I rewrite it again and then I rewrite it again. Obviously, if you learned this in grade school, if you start your article with an outline, you can at least know that you don't forget
anything, so you can actually write it into the initial narrative, right? Um the it to be fair it got all
right? Um the it to be fair it got all this information because copilot might have a short context window that it keeps on sliding stuff out but because
uh I mean I can probably show you here because of of uh like these conversations I've had over time and like things that is kind of
frozen into memory currently. If I just jump in on a new topic today and ask it about some aspect of solid 2.0 or something. It doesn't like remember the
something. It doesn't like remember the specifics, but it remembers the general thing. So like it's very much it knows
thing. So like it's very much it knows in principle what I'm trying to do. So
you know when I give it a I was trying to I was this is how I got the idea for the stream the stream title today. Um because I was like I was like
today. Um because I was like I was like I've been doing a ton of Salt 2 beta fiction. It's been two weeks since the
fiction. It's been two weeks since the last stream. I also published this
last stream. I also published this article. It sounds like one of those
article. It sounds like one of those deep work sprints where you disappear but dropped a big piece of thought leadership blah blah blah blah blah blah blah blah blah blah I I I need to think of tomorrow's dream and I need a title concept hidden physics of react and how
solid 2 solves them differently blah blah blah that's ultimately what led me to where where I am today but it it was very it doesn't take very much context
because of like the baseline that I've set for it for it to be able to jump directly into like what I need out of it.
Um, third 2.0.
Um, let me see if I can.
But I I know people were really interested in this. So, I'm going to I'm going to show you this because this is actually a multi-day process
that kind of that was going through while I was writing that last article.
I need to write an article around the two controvers changes of solid 2.0 deferred commiss effects. I don't want to write the article I don't want you to write the article. They clearly have an AI voice, but I'd like you help laying out the structure and the points. That's
how the conversation started, right? And
then the thing that I copied was I gave it some clarity, blah blah blah.
And the thing that I ended up copying was right after I was like, we so still giving it clarity, I'd rather lay out the article by
headers and bullet points. And then like how would you change this on where we're
how would you change this on uh by changing the title and then this was the thing that we just looked at and then I just started dumping my literal intro and I ended up rewriting the first
thing because I it didn't tie together.
But if you look at this, this this is like basically verbatim of like what actually ended up in the article and except it basically was like
it was it it added like as when you know I got rid of this part.
It's all too late. It's been a journey like it basically added the right periods and commas and kind of like semicolon type stuff. Uh
so then strong section media pivots this then it's like okay and if you look what I end up doing is basically taking what do you think about framing for interesting async characters? I basically just
async characters? I basically just dumped because I use Grammarly right but Grammarly um costs money for grammatical fixes. it
just does like like spelling but for complex structure sentence fixes it actually um it actually costs money. So
basically what I would do is write like three or four paragraphs at a time and go can you correct the structure of this everything involve foundation line option the async moves us out of
impaired comfort zone async is about red that's a question what's available stale up something fl and out of synchronous declared assistance at least that way it looks most parameters by the time it's a different axis we understand parts of the intersect it appears unpredictable
has impact the whole system with a bit of work can be modeled in consistent way essentially This process can take is is is
essentially how I ended up with the article. Right? So people noticing
the article. Right? So people noticing AISMs weren't completely off but I also wrote every single paragraph in here.
As you know, I've been working the last sing territory.
You know where was the other one we just saying everything in the web building the entire platform the network brown you know like I didn't add this dash but
it fits better with the the flow right comfort zone right things same thing blah blah blah async look at fal state flitting in and out like this is my
exact wording um like it it's basically a grammar corrector um
but It's enough to give us a slight voice on this that I I get rubbed people the wrong way. Um,
but AI could have never written this article. Do do you know what I mean?
article. Do do you know what I mean?
Like when when you go and and be like, hey, with these points, write the article. He doesn't write this kind of
article. He doesn't write this kind of narrative structure. doesn't construct
narrative structure. doesn't construct this sort of I have not had any and this shouldn't be surprising to you because it's not like
it's it's a bit like trying to execute a plan without plan mode. The problem is with writing. Plan mode would basically
with writing. Plan mode would basically essentially force you to the get the the right tone, narrative structure, all that. you the plan you'd basically have
that. you the plan you'd basically have to write the article like you'd have to write the whole article first to actually sufficiently do what plan mode would do for for for code by by by
comparison. Um,
comparison. Um, and this is another example and I'm bringing this up right now before we get into the more solid 2.0 know stuff just because this has been controversial cuz there a lot of people talked about the
AIness of this article and they were upset about it and I'm like I'm thinking about like I know what if I if id set AI to write this article it would be
nothing like this. Um like I actually have the artifacts as I was showing to prove that. Um, but
prove that. Um, but when I look at this, the way it reads compared to my Yoda speak, you know,
this feels much nicer, much more professional, much more hopefully understandable, um than you know, my writing typically is. It
actually tightens up little bits of phrasing things where I miss words. I,
anyone who's ever edited my articles before they get published knows exactly what I'm talking about. I I used to I for for years I've used like four or five people like different people
different articles but I I always run my articles through a bunch of human review because they're tend to not be understandable otherwise. If you look at
understandable otherwise. If you look at my hackmds versus my dev2 articles like the ones that I write you can tell a worlds of difference. Part of it is because of the amount of time I spend editing but the other part is because I
other people actually read it and edit it because what I write tends to not make sense.
uh co-pilot's like on something old like five uh GPT 5.1 or something right which is what what I was doing I was posting whole sections and being
like what do you think about this that that's what I'm saying like you you AI would not generate it but when I I see this come back which is basically identical to what I wrote but like added
the spacing timing pausing slightly rewards like a thing here or there. I'm just like this is Yeah,
there. I'm just like this is Yeah, honestly, this is much better, you know, add some quotations around my, you know,
like is it my questioning like you're like, okay, this actually reads better.
It's a question of every UI thing. Can I
show this or expose something? This is
like this reads a billion times better.
I mean, I've streamed for six hours, so you know, I'm sure we'll get to whatever you want to talk about.
This is important though. I needed to get this out of the way. Um, mostly
because this is Yeah. Again, what what is my goal? My
Yeah. Again, what what is my goal? My
goal is to clearly communicate with people.
Yeah, this is the this is the gist of it. The challenge is you let's say that
it. The challenge is you let's say that this experiment was a little bit heavier-handed than I usually go.
Was it worth it?
If it's less than six hours, it's AI.
Um, yeah, just replace me with AI. Um,
did it did it work? And the answer is depending on who you talk to.
I I got that first comment in the in the in the in the comments and I was like, yes, it worked. And then I found out find out that AI wrote it and I was like, okay, well, maybe maybe maybe it
didn't work. Um
didn't work. Um Um, which which is a little bit harsh.
Um, sorry. I actually should actually do the
sorry. I actually should actually do the publish command now.
Um, sorry, I just need to quickly get my authenticator app going here so that I can actually publish. Do not
challenge for the next five minutes.
Okay.
All right. Thank god. Okay. Beta out.
Okay. Um,
yeah. Uh, the funniest thing is this.
I'm going to talk about the contents of these articles in two seconds. I just
the last bit of this conversation is, uh, I want to go to Reddit. Um, and I I uh and let's see if I can I can find what
I'm looking for.
Uh, all right. Here we go.
all right. Here we go.
Great article. The TLDDR is you basically have the deep Oh, so the person Oh, they deleted it. Okay. Well,
good to know.
So, is it only good comments now? Basic.
Oh, yeah. Here it is. I think it would be helpful if you adjust your title and note in your post that this article is basically a subtle plug for solid. You
posted in the react sub. This isn't
really advice for react dev. It frankly
reads more as haha. You you react peons are stuck with the stuff and you don't have to deal with felter solid. Thank
god Rick Hanlon. Remember him? React
core team had him on the stream. You're
wrong. This is absolutely great content for reacts. It explains the exact reason
for reacts. It explains the exact reason for choices we made that I've struggled to explain to React devs myself and several times even says it's not about the framework being better than the others.
Thank you, Ricky. Thank you. Honestly,
I think the takeaway is even with AI, people still don't really understand anything um you know, if they don't put
the time in to. So yeah, I I was really happy reading the article and and seeing how much clearer the points were and I'm like, "Oh, I wish I thought of doing it
that way. Oh, this is much nicer." Like
that way. Oh, this is much nicer." Like
just little like little it's the structure, the paragraph per paragraph were the same, but it was just like, "Oh, added this word here, paused here, and you're like, "Oh, okay." Yes,
exactly. Right.
Um, so like more people came to defense, so whatever.
But yeah, this is if you look at this article, it's it got downloaded on Reddit React forum like past zero. Like
basically everyone downloaded this article. No one upvoted it. Um, which is
article. No one upvoted it. Um, which is insane, but it's also par for the course of Reddit. You know, we've often said
of Reddit. You know, we've often said that like on average the developers on Reddit are like like YouTube comments sometimes are pretty low bar. Reddit is
like the bottom. You know, you can like go on there, say something reasonable, and then I mean it's almost like like like I think my response where I was
like I was like uh it seems reasonable to me got downvoted a bunch. Okay,
that's not the message. It's four. Okay,
this was like minus 6 at one point.
Um, when I'm like literally saying like, "No, that's not what the article says."
Like I'm not sure people on Reddit, like I I guess they would need to know how to read if they were going to like write this stuff, but I'm actually like I'm sometimes not sure if they know how to read.
Um anyway, so yeah, my my my takeaway on this is is that um
maybe the thing that I thought I was attributing to the clarity of my writing is is actually not my writing's fault
completely. I I thought that if I could
completely. I I thought that if I could like clean things up in a meaningful way, people would get what I'm what I'm talking about better. It could be still problem with my narrative structure. It
could still be other stuff, you know, because that's I obviously didn't write that article, but um I like my narrative structure. I like
the arguments I make. So, I would never change that. Um,
change that. Um, but it was it was it's definitely frustrating when you write an article that's literally like, "Look, React fans, here's some ammo. You guys were right." And the person's like, "You're
right." And the person's like, "You're just trying to rub solid in people's faces. You're just like," and it wasn't
faces. You're just like," and it wasn't just them. Like, there there's multiple
just them. Like, there there's multiple comments to this to this degree and like in in this kind of thing. And I was just like, "How do you how do you get there?
How how like do I just give up?
Um anyway, uh enough on the AI topic. Let's get let's get to the topic at hand. I think I've I've probably talked your guys ear off about this. I don't I don't generally
about this. I don't I don't generally like talking too too much, but I had to address this because there's a bit of an elephant in the room.
>> Yeah. Yeah. Yeah. Well, we'll see if we can get Delaney on. I I think I think it's I think I think data star is interesting because it tries to sidestep
a certain category of problems which I I think I I think in a sense the way I would look at data star just holistically before actually like going deep into it is
it's it's really taking that htmx perspective that you you like yag me you're not going to need it and and just like look
HTMX is just missing this last little bit. This is how you just stretch into
bit. This is how you just stretch into that next zone a little bit farther. My
challenge with this is is once you introduce that zone, you you have a new set of problems you should be solving and you can pretend
those problems don't exist and you can basically be like, "Okay, I'm okay with it. My scope is right here and you
it. My scope is right here and you you'll be fine." It's kind of like a bit like some of the issues I have with Astro Islands. But then it's like once
Astro Islands. But then it's like once you cross that threshold, it's insufficient and then at that point you have to rethink everything and you
kind of end up where actually I where I'm sitting. So it's like
I'm sitting. So it's like there's this interesting tension between solutions that that uh um you can clearly go they belong over
here and one's trying to expand over more of the range. And the thing is if you take those I just belong over here solutions and try and expand them beyond
their range. Uh sometimes you can hit a
their range. Uh sometimes you can hit a really sweet spot, but you can also hit a zone where you're butdding right up
against like models that would be more suitable um uh for you know like like you're you're just hitting that piece.
So it'll be interesting talking to Laney and and figuring out exactly where that line falls.
React and especially react in a serious community I see.
It is a big mind shift. But the the thing is and I think this is still true.
Delaney still doesn't believe in shared client state.
He believes that not everything has to go back to the server which is which is which is key like that you can keep interaction while keeping that kind of like partials sub view. The challenge is
when you have partials that share state like island same kind of concept. There
is a fundamental mismatch here on shared state works with cl server side rendering right like how do you you get the old update panel thing. I we're
going to talk about it I'm sure when I get to Delaney on it's just it's it's kind of fundamental. It's not like a it's it's a physics thing. And I like talking about these things in terms of physics, which is the whole reason that
I wanted to uh do the stream today because um these things feel like rules that are
discovered rather than inventions, things created by people. I think that's really important.
Cash in the cash is really interesting.
It's like 13 content probably it makes sense to me especially if they're using that with something like server islands like I I I think we
we just we just need to um I mean there's only a few core mechanisms behind all these things and even if we figure out how to model the
data or the transport layer like slightly different you're like you're still dealing with the same types of problems you can like kind of shift it around so I haven't actually looked at
this specific specifically, but I I'm guessing um I'm guessing that's the realm in which it's operating in. I could be completely
wrong though.
Okay, so let let's talk about physics here. Um I'm going to change my view
here. Um I'm going to change my view slightly so we can get into the topic of today. Um because
today. Um because I want to start with this article mostly. I I think my hackmd about yol
mostly. I I think my hackmd about yol 2.0 0 is interesting um about temporal determinism and all that. It is
interesting but it's kind of like a AI point and I don't I don't know if we want to talk anymore AI right now. Um I
think I've made this point on stream over and over and over G again essentially that the shape of our solution is important but there's no point talking about the
shape of our solution until we actually look at the shape of our solution. So
let's start let's instead start from from here right let's start by talking about
why react was right and why this is actually physics not DX consideration
right and then we'll talk about how solid 2.0 solves that.
So, if you haven't read the article, it's worth a read.
React was wrong. React was right because Angular was oh so wrong.
Or Angular.js original. Yeah. I mean,
Angular.js had its challenges. it. I
think conceptually Angular.js came from a really reasonable place. It was like look we have data we bind it. We update
what changes. Honestly, anyone
engineering a solution for front end at the time that seems like what the problem was. You have a bunch of
problem was. You have a bunch of imperative writings all over the thing.
Let's make it declarative. Let's just go this change to this change. Like it had the shape of the solution it knew it wanted to solve.
it didn't have any of the guarantees on propagation. This is the whole problem
propagation. This is the whole problem with the the early systems. They they basically were just like a wrapper over jQuery, right? They were just like,
jQuery, right? They were just like, okay, well that's imperative spaghetti code. Let's make it declarative
code. Let's make it declarative spaghetti code. Like the the process in
spaghetti code. Like the the process in in which we could like do these updates wasn't as refined. Right? Back then it was just like about the abstraction. It
was like how do we get the DX? It's like
okay, you know, we'll do we'll dirty check everything. We don't care. just
check everything. We don't care. just
make sure that when I say that this state is tied to this thing that it will update. That that was our primary
update. That that was our primary concern. React was kind of more like no
concern. React was kind of more like no we need guarantees here otherwise it's zgo like literally anything could go wrong.
Right.
The problem with the react approach was it's it was too simple. Right. the the
both it's it's both the benefit and the like it's both react is like who cares just rerender everything and you're like how can that be good enough and they're like you know what we figured out a way
to make it good enough that's their whole premise but it it was never like arguably the the the best solution to the problem but they didn't approach it
like engineers solving a specific you know like mechanical problem they kind of were like holistically this truth needs to emerge from our system, right? And almost everything
system, right? And almost everything from there flows out from React. Um,
does solid get compiled into web components? No. I don't know why anyone
components? No. I don't know why anyone would want to do that. I mean, we can support web components and people can put solid code in web components, but
it's kind of like web components are kind of a waste of like they're just a thing. It's like I can have a component
thing. It's like I can have a component and then I can also make it a DOM element for some reason.
AngularJS had its good side. To this
day, no modern framework has better modal dialogue DX than Angular. Spent
months trying to recreate mega powers in React. Yeah. I mean,
React. Yeah. I mean,
and also I feel like Angular spent a lot of time fixing very specific problems that were fit their real needs.
Sometimes React's solutions seem kind of heady, like kind of academic. And to be fair, I'm in an
of academic. And to be fair, I'm in an interesting place because with Sol 2.0, like at a certain point, you you you sit there and you batching
up bugs all over the place and like see these patterns emerge and you're like, the solution does actually need to happen at that level, right? the level
at which React kind of tends to operate at. It doesn't mean you should like
at. It doesn't mean you should like change to just doing what React does, but you have to like step back and be like, look, is there a systematic problem here? Are we is it our fault?
problem here? Are we is it our fault?
Right? Almost every major framework uh change in the last like five or six, seven years has been around that. Back
in the day, it was originally just like pure DX play, but now new frameworks now have been mostly coming out of like is it our fault thing and being like saying yes. Like Quick was like saying like is
yes. Like Quick was like saying like is hydration being slow like that piece our fault and Quick's like it's not the developer's fault, it's definitely the framework's fault. That that's their
framework's fault. That that's their premise.
Solid's perspective was is the UI getting updated slowly or in like like not as efficiently as possible and like
weird like kind of like rerenders and all this kind of like obscure uh kind of weird mental model pieces the developer's fault and it was like no
it's the framework's fault like I feel like that has been has been kind of like the sign here originally it was just like you I don't want to write jQuery
anymore. But then it's evolved into like
anymore. But then it's evolved into like us recognizing that the abstraction or the tool should be providing something that it does that it doesn't currently.
Why do you hate web components so much?
Um, okay. I mean, I can answer this actually
okay. I mean, I can answer this actually pretty simply because they they they actually aren't that much of a problem in a certain sense. You could say that
they're just extra. They're just like an option. And and if if they were just an
option. And and if if they were just an option, I'd be like, okay, the problem with web components and why I have so much thing is they're unnecessary and
then their existence influences other decisions. So, it makes it a very
decisions. So, it makes it a very awkward place to be because basically we've tagged on something that arguably is optional and then tried to base
everything else off their existence in a way that like over complicates and undermines the ability to do things in the most simple, direct, and performant
way. So it's like
way. So it's like like on the surface as someone who using these APIs could be like okay well you don't have to use web components I can just use web components
on in principle cool go for it but like the reality is the impact of their very existence makes everything
else worse. So
else worse. So I I think I could even be okay with that except for like web component people keep on coming around and being like hey do you know why do this or do this with
web components and it's like if you knew what you were doing you would even ask that question. It's it's like yeah yeah
that question. It's it's like yeah yeah sure go ahead do that with your web components but why would I have to worry about that cuz like they don't add any value like it's like do you know what I mean? Like it's it's like I it's a
mean? Like it's it's like I it's a combination of like their impact on the platform and the fact that like people seem to be like really wanting to push them when like it almost like not
understanding what they do and it's kind of like you have to like repeatedly be like okay well sure like you can go do that with your web components. You don't have to do
web components. You don't have to do anything in solid to do that. we support
web components, you know, we we've taken that hit, but it's like um it's like it's like I have to it feels bad after a while being the one to have
to deflate people's expectations around web components, right? You almost get kind of like annoyed or frustrated with the people pushing them because it feels like they they're selling a a lie or
something like that that that's usually the challenge there. it I don't the technology in a sense could just speak for itself but there's a lot of misconceptions around them and it's not
that I I don't think that they're incapable of doing things it's just like it's like it's one of those things it's like yes you can do this with web components but then like you can also do this without web components and it's
arguably better so why do you why are you conflating web components with this So, you don't hate white women, you hate the culture around it.
Um, I don't have the the same conflict with React or or that. I I think the thing is React knows exactly what it's doing. I mean, maybe not all of its
doing. I mean, maybe not all of its fans, but React actually generally is fairly straightforward. You know, like
fairly straightforward. You know, like it's very clear to me at least what the trade-offs and the design decisions are and how that flows. It doesn't feel ever
um like it's dishonest.
Um anyway what does any of this have to do with anything? Well,
anything? Well, React's ivory tower and oversimplistic design gets us to
certain places much sooner than others would have got to because most of us were just building apps and just trying to build things. And if we hit a few awkwardnesses, we're just like, do we have the tools to deal with them? Yeah,
we do. That's the pragmatic approach, right? You kind of like figure out where
right? You kind of like figure out where the lines are. I think there's a Ryan Florence tweet that we covered a couple weeks ago that was like this. And then
honestly, you just when you have to ship, you just fill in the real you fill in those gaps with whatever crap you have available and you move on. I mean,
AI works the same way. You just kind of move forward to it. At a certain point though, you have to really ask about like where those lines are drawn. And um
in React's case, there's like two really really big reactisms that piss people off a ton. And I think it's important to look at why they exist. Um one of them
is the set state and then state not committed one. And the other one is um
committed one. And the other one is um the fact that they have these dependency arrays. Now
arrays. Now the set state and state after one wasn't always a clear picture in like react 0.13 or 014 like 14.13 there were cases
where you could read the next state and eventually point they were just like no stop doing that we need to make this um we need to like settle on this one
behavior.
This one is funny because I I'm calling out effects particularly because you don't need
the reason that effects are special here is because technically the side effects should happen independent of the rendering. like dependency arrays on
rendering. like dependency arrays on your use memo or use callback or whatever like other mechanisms you're using in React aren't necessarily important because you know that that
code's all going to run during render.
It's basically part of the render pure part. So the mechanical need for uh
part. So the mechanical need for uh dependencies might you know be seen as a shortcut but for effects
you do need to know the dependencies before you run any effects um because the those dependencies like you need to make sure that all the
effects run cons at the same time. If
you run some effects and then you get interrupted or something can't go and you run other effects, you end up with torn UI. So you have to make sure that
torn UI. So you have to make sure that you know all the dependencies up front.
And signals libraries kind of got away with not necessarily doing this because you can kind of ask for
the data wherever you need it. So
they're just kind of like, okay, well we'll just create effect, you know, whatever. read the stuff and then it it
whatever. read the stuff and then it it could you know it'll just get it and who cares if like we process some of the pure calculations late you know if it's
lazy pole system or if we you know do some part of an effect and then do some other stuff and then do some other effect and do this and kind of isolate it across because there was no possible
way because everything is synchronous for for any of those interruptions to escape that render frame like you knew for sure that you know some stuff might kind of flip around a bit, but in the
end, you're going to end up with in the same tick, you're going to end up with a consistent UI. And I think once you understand like these kind of two
fundamental things don't hold up during async, you're posed with a a very kind of interesting question. And I think and this is why I I want to talk about this
and I'm talking about this like physics because this is kind of a fundamental truth. I I'm very open to people in chat
truth. I I'm very open to people in chat arguing with me saying why both of these things in React are terrible. I'm but
try to argue that these are aren't necessary is a much harder task.
Uh, is your latest YouTube video a good introduction? Not really. My my what
introduction? Not really. My my what React developers should know about signals is a good introduction to React developers who at least know like what a
signal is and then they've been hearing all this bad stuff about it. It's morely
the to it's more mostly myth busting. I
don't have a great like intro to signals video in the same way that I have an intro to signals articles, but even my articles like how to build a signal system, depending on what level um of
what you're looking for, you might find it better elsewhere.
And only thing a program with effects can do is heat up your CPU.
Yes. And a lot of the stuff that we're going to talk about today in terms of physics is kind of understanding this like if a tree falls in in the woods and
no one's there to listen uh like did it make a sound? Like that is that is part of of what we'll be talking about today.
React's biggest gotcha for me personally is that use state doesn't update when you source it from a prop and prop changes later use effect. Almost
everyone does this. This is why solid 2.0
does this. This is why solid 2.0 directly addresses this. I also want to talk about why solid 2.0's design is better than dependency arrays even though it feels like dependency arrays.
Um this is a problem not unique react at all. And I came to the same conclusion
all. And I came to the same conclusion about three or four years ago when I started working with solid 2.0 designs when I I I realized that this was like the biggest source of people needing
synchronization is that you're when you construct the graph you can't create the the dependency through state which is kind of crazy because react rerenders
almost everything about react makes you think that like you would like oh if the props change coming in I should be able to reset my state and the answer is you actually have to create a side effect to
do Now you can key the component but that's such a brute force way of doing it. The
other thing is you can derive your actual state from your local state and the props and then kind of like calculate it in line. Um that will also
work but these are very like complicated ways to do things that are very clearly trying to set up a graph like dependency change in a rerender
model. It it
model. It it I said it's not you need to react at all, but it feel like at a certain point I was like this is the gap.
Yeah. I mean, I don't know if you've seen Solid 2.0, but that's that's exactly what we did. You're in the stream. You definitely know what I'm
stream. You definitely know what I'm talking about, right? In React, when you have state and you pass a function to it, it just it's a safety guard for when
you have work to do. If you want to know what I mean for people who uh sorry not Excalibur uh I'll just use play I'll just use solid playground for for for for
explanation here. We actually use this
explanation here. We actually use this trick on Ricky stream. But essentially
like when you do use state in a React component and you have something like expensive first of all if you do use state zero
and your component reruns because um I'm going to call it count uh count set count excuse because you
might have moved count, you know, like did an event and set it to to three or four or whatever because you have to persist the state in React when like the
component reruns, it doesn't reset it back to zero. It keeps whatever the count is. It makes sense. But the
count is. It makes sense. But the
problem is if you have like expensive calculation is how you're thinging it would be the problem is because this code actually runs even though it returns back out
like a cache value out of here because this reruns every time you wouldn't want to do that. So React gives you the ability to pass the function in but the function only runs initially. Um
essentially it's just a way of guarding.
So it's like look if if someone passes a function into this use state don't um don't rerun this expensive calculation
keep the cache values only run this initially um so it doesn't solve the problem right the whereas um if you have
create signal your components aren't rerunning and for that reason this behavior is implicit because you like it will never rerun. So it will
never run this out again. So the fact that this updates is fine. You'll never
have to worry about it. Which lets us overload this now. Like basically you this would be perfectly fine because the
component only only runs once.
But it means we can do this too and and have the function like most things in a signals library mean that it actually reruns. So whenever the props
actually reruns. So whenever the props change you can reset. So this behavior of deriving state which is very natural
is something that we can do um very naturally in this model.
Yes.
Yes. Exactly. You want you want to reset. This happens a ton in forms and
reset. This happens a ton in forms and what most people do is they they they put use effect in
um the better solution is to yeah I the the things that get allocated and throw away immediately tend to have way less of a memory impact than you'd expect.
um I've found.
But yes, this this this is a this is a source and it's a little bit off topic today, but it's a it's a key place to pro kind of show like how you can adhere
to the same sort of physical rules but by slight adjustment in the execution model not be subject to the same downsides. Okay. So
downsides. Okay. So
with something like this all like 70 no I'd say 80% of state synchronization bugs or sorry needs for effects go away right off the bat
because suddenly you're not like writing like there's so much wrong with with with doing with doing with doing this right use effect sorry let's go back even
further I want to go back to the yeah there's so much wrong with doing with doing this
um count prop value uh depends on props value um
because like it's actually telling the component to rerun again right off the bat like like because it runs sees a state uses the effect now the effect
doesn't run until afterwards so it goes through renders with count uh being zero. I I it's possible that if it sees this no actually wouldn't even
know even with that invalidation it run it renders with count being zero and then it cycles through and renders again.
You've never had to do this with you. You're You're telling me you've
you. You're You're telling me you've never done what's in front of me in React?
I I I I feel like you hit this problem within the first two hours of using React. Like every developer has hit this
React. Like every developer has hit this problem.
You've never used use effect to synchronize state.
Sorry, I I I'm I'm I'm I'm like whenever you see those horror examples on Twitter with forms and all that, it almost always boils down to
someone doing something like this.
Like React had to write a whole doc section specifically on avoiding this pattern because it's literally what everyone does.
Yeah, people do it now, but this is like the like this is like the the dumb pattern. Everyone I I don't know if
pattern. Everyone I I don't know if React ever suggested this was a good pattern.
We have UI live management to lots more.
We have tons of this. Yeah, like this is the problem is this is a very common shape like it's called the ephemeral override state like scenario like this is like
the what is a good pattern in React?
Sure. Two things. The easiest pattern for this in React is is this uh let's do value
so we can see it.
The easiest pattern for this in React is that when you call this component, you do this key props. If you do this, every time value
props. If you do this, every time value changes, the whole component is going to reset, which means it's going to create new state hooks, which means it's going to get the latest value. Um,
right? Like it's basically going to throw away all your previous state and reset reset it this way. This way you don't need synchronization. Now,
obviously, if you have multiple of these and then you'd have to come up with like an interesting like if key or value like I mean I guess you'd be fine with it over rerendering but you know get all
your get all your depths in here so to speak you know um I guess if I made this an array that would be awkward because then the array
would be a new instance every time. Um,
but you you can basically create your dependency array for your effect in your key really really I I'd be interested at some point to hear why how felt by broke your brain. I mean unless it's like what I've
brain. I mean unless it's like what I've been talking with the async stuff which I think is breaking everyone's brain.
I understand in the thing I just don't see reason to store a prop value and use state. Okay,
state. Okay, picture this. I I I I mean the example
picture this. I I I I mean the example with forms is really really really easy.
Um I have an input, right? Bunk. Actually I
I deleted too much function input. Okay.
So now it is an input component. Okay.
Input. Okay. And our input component is going to graph uh an actual native input. Okay.
Now, we want some sort of way of this component saying what its value is.
But I mean, I it's going to be a complicated input. It's going to have
complicated input. It's going to have like other functionality in here, which is why you wrapped in a component. But
we also want the ability to manage it in here. So like essentially we don't
in here. So like essentially we don't want to save we don't want to do like this like we don't want to like on like input might not be because it has immediate feedback but like some kind of
component like on save or something like we don't actually want to to pass our information back until we we commit it.
like let's like let's pretend our input has a button to save instead of like in instant typing. So our input bas
instant typing. So our input bas basically wraps like uh like you have to press enter to commit the value. So
there's this temporary state that essentially gets initialized from here but does not get communicated back up here to get pushed back down. It
actually stays inside the component while you're editing it and then when you press like enter or on save it actually communicates the information back up. So in this scenario,
back up. So in this scenario, if the input ever coming in changed, you need to actually reset this count, but you also want to have a temporal
override until you're ready to communicate the change back up. It's
just like a temporary uh state. I I used an input here. Um
but basic basically the idea is that you have some kind of like temporary like scratch pad that doesn't doesn't impact the rest of the system. it just lives locally,
right? In this kind of scenario,
right? In this kind of scenario, you you're you you're going to need to initialize it with this, but then you're also going to like, you know, maybe there's a button in here, too.
I I mean, I'm just making stuff up here, but then like on click, this calls on save, right? So
at the end when you click on save it will hopefully you know we'll do something like you know value you you'll probably set it to like set
my own set my count to value and then you know my count or whatever like is here like
you you'll close the loop but generally speaking this has to be although even though it's derived from this, it needs
to um it it needs to uh have its own temporal override. And as I said, this
temporal override. And as I said, this this pattern is relatively common. forms are where you see this like a billion times, but
it it also happens in other situations like um just like places where you need to isolate changes from the global store or like places where you like any place
where you you do some kind of speculative change and and it doesn't have to be like over the course of like a specific life cycle, right? It's not
we're not talking about like like optimistic updates necessarily. We're
talking about like something that could persist a while. Um, sometimes errors are another example of kind of like a speculative kind of override where the life cycle isn't necessarily tied to
either the action itself or to the the persistence in the in the store. It's,
you know, these kind of patterns naturally emerge.
No, that's that's what I was getting at with with key. You'd have to like you'd have to like somehow register them all and any of them would actually cause a
change potentially. Um
change potentially. Um the if you I don't need to go too far, but it's like uh React docs have a whole page on this. Uh when not to use use
effect.
You might not need an effect. Beautiful.
These docs are worth reading for every single person in any framework, but it's very react specific, but I think I think this is important.
React key is such a hacky solution.
Yeah, I I don't like it, but I understand because it's often the simplest. Like they're examples
simplest. Like they're examples literally what I talked about the like this example here the obvious answer is you should just derive it like
this is a use memo case you don't need to like make it a separate state for full name set name but what if it's writable
then you actually well see the the if you can calculate it during rendering this is better right but some sometimes you need it
stapes add little thing like they have a ton of examples in here. This like react knows this is an
here. This like react knows this is an issue which is why they have quite an extensive thing right post request like this is so common
where's the key example it should be yeah here's the key example Oh, this is this is the general better approach where you like but even because
what this can do is React's smart enough that if you invalidate its own state in the course of rendering the component because this component
here is like the state is part of the same component, it goes, oh, when it go before it like renders the component and the JSX structure like the virtual DOM, but then before it actually tries to
realize it or reconcile it, it goes, uh, in the process of this, we came invalid again, don't continue, like don't go on to the diffing and patching stage. Rerun
this component with the updated state again. So, it's more effective. If you
again. So, it's more effective. If you
use use effect, unfortunately, you actually cause a full render cycle where it actually does do the diffing and patching and then comes back around again. So this is better to do inline
again. So this is better to do inline writes um during the course of of this.
Um but I mean this is also kind of weird because it does cause the component to rerender again. Um
rerender again. Um but because the component is the only how should I put it? Because the
component is the only unit of reactivity that react has it it actually like it doesn't have many choices here.
Rerunning the component is better than rerendering running the the render cycle.
Most of this article is just David's.
Yeah, David from Xate made this thing.
Anyways, I'm not here to necessarily solve React's problems for you. This one
is solvable. Uh, and I I I showed you how we solve that with Solid 2.0. Very
simple. You just derive the state. Done.
whole class of use effect just goes away. Um, but these two problems are
away. Um, but these two problems are trickier.
No, it's actually it actually stays working like create memo.
The reactive update overrides your local setters.
The idea is that the derived value is the override. So you you derive it
the override. So you you derive it initially, you can override it and then it can always be reset by the derived state coming in which is what exactly you want in all of those use cases. Now
you could be like well what if I wanted it only to initially work reactively and then um and then just override it. Well
I mean in that case you didn't need any of this mechanism. You could have just like unttracked the read or just like set the value like that's the default because our components don't rerun,
right? Like the default is
right? Like the default is like the default for all frameworks or like like React is this. It's like it's derived initially and then you override it and it's all the the hard part is
actually making the override re like or making it reset the override.
Right?
So, I I want to talk about both of these because uh the these are controversial because these are arguably the things that people love most about signals and
hate the most about React. I can just autotrack anything. I don't have to this
autotrack anything. I don't have to this delayed commit because I can literally just ask for the signal or the drive signal or anything down the chain afterwards and get the answer right
away. And the problem with async is
away. And the problem with async is those two things are no longer true. So
let le let's start with probably the most controversial truth even though it's the least deniable one, right? No one no one can argue with this first flush one and I'll
kind of explain a bit why. Um okay now this is this whole thing is just explaining uh just async. We we can talk about that in a a minute if we have to but I want
to talk about this commits thing first.
Right? I've covered this so many times in the past, but I wrote an article a while ago. Probably worth it. I was
while ago. Probably worth it. I was
really struggling around the time solo 1.5 with this.
Sorry. Is it possible to reset a derived signal's derived value after updating it? I mean, that's what it would be
it? I mean, that's what it would be doing right?
It reruns the memo and then that's what it ends up with.
Um, so this is an old experiment that I did where I I was showing this React example where I had state, drive state, and then a DOM element. And I was like, after I
set count, what the hell do we get if we log all three of these? So this is just a counter.
Oh, uh, we actually have that. It's
called refresh in Solid 2.0. Um, so yes, you could do that if you wanted to, but the the primary way of doing that is actually just updating the the prop the
reactive props.
No, like you don't even have to set signal. You can literally just tell the
signal. You can literally just tell the computed to to run again, right? Usually
it will automatically run because the props change, but if the props didn't change and you wanted to do a reset, we we have this specific mechanism. It's
very useful for async, but it could be useful in this case where you're just like hey like reset it to like just rerun the computation again or in the case of async refetch this again, you know, like
for invalidation. So yes, we we we do
for invalidation. So yes, we we we do have this mechanism.
I the big the big thing is like having extraneous set values are kind of the things that I I I kind of want to
avoid. I think
avoid. I think like when you h I think it's a lot cleaner to think about it like I need to reset this computation rather than like have to like write it back. Do you know
what I mean? Like cuz like there's there's more truth in like talking about the derivation of it than like just being like okay in this condition then write this and because I know that this is what the source is then it'll be
fine. I mean you can do that but that's
fine. I mean you can do that but that's that's not like as clean.
Yeah. As refresh is literally rerun this computation.
Yeah.
Truthfully, the value shouldn't have changed in most cases. But here's But with the with over Yeah.
Yeah. So, the reason I showed this is because this we were I was working on Marco. We discovered this and then we
Marco. We discovered this and then we realized that every framework logged something different. React log 0000, Vue
something different. React log 0000, Vue log one 120, spelt 3 or 4 logged 1 0 0 and solid was 122. And if you look at
this on in a in a in a in um in the abstract only react and solid are correct arguably because like they're the only ones that are
consistent like zero if if count is zero then double count is zero and then the DOM is zero consistent. If you look at solid also consistent if count is one
double count is two it's zero. spelled
mimics JavaScript um things because if you update count then double count and current count couldn't be updated. So,
like it makes sense from a JavaScript thing because the the stuff hasn't happened, but it is an inconsistent view. Like you're
view. Like you're like arguably I'd argue you shouldn't be reading after you set the count, but it is
there's there there's like it's hard to argue with this expectation because it like in a synchronous frame it makes sense. And then Vue was kind of like
sense. And then Vue was kind of like we'll do the reactive stuff but not the DOM stuff.
Now the truth is at the end of this article I was like maybe spelt is just right because and and the only reason I said this was because I'm like React is so painful. No
one likes React.
This is great but it's it can be bad for performance. Solid solid's granular so
performance. Solid solid's granular so like you can get away with doing this but like fundamentally speaking like as a general solution if you do like 10 updates you probably don't want to render 10 times you know. Sure, each
update is pinpoint, but there's going to be cases where that's not the case. So,
as a default, this is like putting a little bit more on the user to be like smart about performance. And like this, like it's okay. I don't hate it, but um
maybe not amazing. Um this one everyone hates.
This one I can at least explain even if it's like less than ideal. And this one is like this kind of magical happy place but also
maybe alive. In the end, what ended up
maybe alive. In the end, what ended up happening is everybody just ended up going to view uh more or less. Um solid is still on
this right now. Um unless you call batch explicitly, but generally my plan for solid 2.0 is this. My spelt five is
this. Um, and that's how I like we were
this. Um, and that's how I like we were all going to be here with Vue and React was going to be by itself. That that was the plan for Solid 2.0 like four or five
years ago. In the last year and arguably
years ago. In the last year and arguably in the last 6 months, I just realized that React's version is probably the only correct version here, which is a
really tough pill to swallow.
Yes.
Because the problem with with these models is one is doable or sorry spelt is doable but it's it's a
little bit misleading. I I I I could argue for this approach still like I did in this article. But the problem with async is you don't know necessarily
what is async when you're just like sitting here reading these values. Sorry, I don't need to go back to the original tweet.
Right? When you're sitting here reading these values here, like in this event handler, like sure the async stuff is is is defined over here, but here you're just like I'm getting count double count. like you you you aren't aware of
count. like you you you aren't aware of this and this could be in your UI under different conditions of loading. You
want what you're dealing with here to reflect what your user is actually seeing.
So like let me let me go back to the article here and basically the same example. I I didn't put the DOM in
example. I I didn't put the DOM in because that the question of when the DOM flushes um is a question but it kind of falls out of the other two, right?
Like the reality is the the actual question is what double count should show and what count should, right? If
you if you if you go back to this example here and you kind of crunch it down in if you ignore the DOM view and
solid are the same and then I and if you go to spelt 5 now um actually we're all the same except for React, right? So that that's why we're
React, right? So that that's why we're able to kind of do this compression. I'm
not going to worry about the DOM. If
you're React, clearly the DOM hasn't updated. And if you're the others, the
updated. And if you're the others, the DOM may or may have not updated. But
that is secondary to the actual concern here, right? Hopefully everyone's still with
right? Hopefully everyone's still with me.
So right in plain JavaScript, count and double count drift apart. Signals fix
this by updating double count on read.
But this still leaves the question, when does this update? The DOM just did that.
Okay, React was the only system that didn't update count immediately and people hated it. But the motivation was sound. React wanted event handlers to
sound. React wanted event handlers to see consistenc and it had no way to update derived values until the component ran right it's like the uh it's like the uh spelt example like
react has the same conditions like old spelt wasn't signals it was basically like react it was it wasn't a virtual DOM but like even Dominic from the st team called spelt 3 basically a virtual DOM like conceptually it had the same
component rerun model it just was heavily memoized you can it was almost like the react compiler That's kind of like how spelt 3 was. Um,
so the thing is when you look at the JavaScript of this, how could double count or the element have have actually updated when you just set the count?
It's not possible with old spelt and it's not possible with react. So you
have the choice either update the count immediately, which makes sense for spelt because they just they make it look like it's an assignment. They hide the set count thing. It's hidden behind like the
count thing. It's hidden behind like the compiler. So them not updating one
compiler. So them not updating one seemed really weird, right? Um so the move to from spelt three to spelt five was them being able
to now do this which made their story much more consistent. Um but this was kind of you know all they could do before. React was like no we want to
before. React was like no we want to show consistent value. That was the only choice here. React could not make this
choice here. React could not make this value two even if it wanted to. Neither
could spelt um three signals let you make this value two if you want it to be. The question is should it be two?
be. The question is should it be two?
And you'd be like obviously but actually the answer is not obviously. It's
actually probably no.
Calling flex occasionally is better than having to do batch. I agree completely which is why views kind of timing is what's kind of been where everyone kind of landed on
except for React and now except for solid. Let me explain why.
solid. Let me explain why.
Now obviously if we looked at books.length
length directly.
We could avoid this. But my my point here is I wanted to show an example where you have some derived value. Like
length is easy to derive. But how about something more expensive? Something that
isn't as direct. You have some derived value and you're basically nulling out the source, right?
If you null out the source and you haven't updated the dried value and you and you use that to interact with that source like you're going to end up out of
bounds or reading undefined or crashing your app probably, right?
This is why I never liked spelt's model react. I felt like if you can't update
react. I felt like if you can't update the second value, you shouldn't be updating count, right? Like if if you have no way of making double count updated, you you shouldn't be updating count because this will happen to you.
You will cause your program to crash if you put expectations on double count.
Now you can know that to avoid it, but it's just it's not consistent, right?
Like you understand here books length is five. You set it to an empty list. This
five. You set it to an empty list. This
hasn't updated. You go books books 5 - 1 is four. You read books four and there's
is four. You read books four and there's nothing there. Maybe you read a property
nothing there. Maybe you read a property off it. Oh, guess what? You've thrown an
off it. Oh, guess what? You've thrown an error like this is now frameworks that do do this have like
tick or a wait but to force the flush, right? But it's kind of like and this is
right? But it's kind of like and this is important to put in the other article.
Every framework has an ability to mimic those other behaviors if they want to.
But it's the question is like as a default should every time you set something cause you to call flush? Well,
maybe you do want to read these values.
So then the answer is yes. But if you don't call flush, should it break?
And I think React's approach is a sane one, which is if you set books here, books is still five. So when you pull out this book, you're actually seeing
the like the book listing at four. Now, should
you write your code this way? Probably
not, right? the whole read after write is
right? the whole read after write is just like a bad smell that you shouldn't be doing. The problem is that with
be doing. The problem is that with signals libraries, we we let people feel like they could do this. We were like, "Yeah, go for it. We don't care." It was
never a good thing to do, but we made it feel like it was okay.
Yes. Right. In view case, you never need to call flash unless you read from the DOM. But it's but the there's a problem
DOM. But it's but the there's a problem here.
And reading from the DOM is pretty rare.
Well, yeah. And you can conceptually be like, "Yeah, I need to read from the DOM. I'll call flush myself." Like, it's
DOM. I'll call flush myself." Like, it's it's an easy it's it's easy to get there. You can go like it's not like normal logic. Don't
need to I only need to call flush on anything or do we need still signal throw? Um, it
depends. It doesn't have to throw. If it
has a value, if it doesn't have a value, then it would have to throw. But if it has a value, it does not have to throw, right? Like as I said, like in React's
right? Like as I said, like in React's case, reading books.length being still five or whatever isn't going to throw,
right? So what does this have to do with
right? So what does this have to do with async? Well,
async? Well, we don't know if books.length has updated it or not.
if books.length has updated it or not.
You could write all your code like this, right? write all your code be like I am
right? write all your code be like I am synchronous everything is up to date I'm using signals don't have to worry about the stupid reactism and then someone realizes that this derived value of
books on length actually needs to be calculated from something on the server and suddenly you've produced this problem because
this updates right away and you're like sweet empty and here it's five it's out and it throws And it's not where you declared
your your async work. It's not happening in here. It's happening in the event
in here. It's happening in the event handler. It's happening other places.
handler. It's happening other places.
You know, because that async work might not even be in the same component.
A you you've basically broken the graph and you've basically because you depended on this behavior potentially have Now crash errors all
throughout your application.
Only a problem with color syncs to do.
Well no.
This is a problem. This problem is not what color because all async becomes colorless once you pull it into the into the system. At a certain point, you have
the system. At a certain point, you have to consume it, right?
The I will say that the other problem we can talk about it where color stay async makes it trickier. This is like if this was felt and I put a weight
count number two here double count like this isn't colorless async. I mean
double count like derived if this is derived a weight count times two or whatever. If if I if I did that this
whatever. If if I if I did that this here it's not colorless async in the same sense because I I needed to pass promises through in that. But as soon as I realize that value, I can't get it
right away. There's no way to get dibble
right away. There's no way to get dibble count from count synchronously. So
I this is not a colorless async problem.
It's a it's it's a realized value problem. At some point you you you're
problem. At some point you you you're going to have to convert the promise into a signal. And if anything or into like a value and anything downstream of that suffers from this
that that's not colorless async in the same way I'm talking like the the reason that we talk about colors as sync and solid is because 2.0 is because we really push that consumption point all
the way to the top. It's where it enters the graph and then we actually propagate it through all the reads. So, we get to this like very cool consistent system
where like, and I could probably draw it out for you, but where we can actually push the blocking all the way to the leaves while you can actually do the consumption at the top. It's it's
actually really powerful. But e even in a system that doesn't do that, makes you explicitly pass promises around, at some point, you're going to eat the promise and bring it into your system. And at
that point, you are no longer looking at the promise you are looking at a signal or a value it will happen somewhere in
the graph and anything downstream of that has this problem it's fundamental yeah I right okay so
okay you can solve this by yeah Okay. I
I see what you're saying. What you're
saying is like never consume it, right? But I like what I'm pointing out
right? But I like what I'm pointing out is like so yeah. Okay.
so yeah. Okay.
But you you you're going to have to consume it to get it into your rendering system.
I I like I could like I could say like, "Okay, yeah, well, fine. we should await books salt length. So instead of breaking it now, what will happen is um I mean
you I mean you're still going to have a challenge because you're going now have to go all through your app through all the places where books.length is and go okay actually books.length is a promise.
Um hopefully your your TS is going to complain because when you try and do bookslength minus one here it's going to be like uh promise is not a number. So
then you know exactly where to fix. But
as I said, it still doesn't change the fact that at a certain point you're going to actually consume it. You're
actually going to use the value, right?
You can push it down to the leaves as much as you want if if possible. But
this is there is something very fundamental about this, right? But you understand like we're in
right? But you understand like we're in an event handler.
If it are you suggesting that when we get into our component body we should fork it so that there's a consumable version that we can just stick directly in our UI and then a version that we can await separately in our event handle
like let's be practical here as I said I I' I've built this exact example in spelt and seen this exact behavior which is why I'm aware of it I you know I did in a weight derived right
I I think the as I said generally the spelt model is in the right direction I'm just saying like there's a certain truth here you have to address here that
there is going to be a point unless you're like unless you really fork the path down to every last read point here
you're going to at some point absorb the async into your graph and be behind that graph you are going to
break consistency if you if you if you flush the value immediately.
Like as I said, I we can think of ways of how you can avoid it like you're saying, but this is physics. This like
this is undeniable truth.
Um, and the and the funny thing is if if if we did do this like make double count async in the spelled example, it would show the consistent UI like it would show the like in the UI here I we would
see 1* 2 equals 2 then 2 * 2= 4 like it won't update it will actually hold the UI properly but in your event handler in
here you will see 2 * 2 equals 2 so to speak so you will break an exactly the way that I'm talking about.
I'm not I'm not doing this necessarily to poke at spelt solutions much more advanced and much better than 99%
of the solutions out there. But this is like th this isn't like like you're that's an option, but uh events are
are how should I put it? Events are um side effectful. So it's kind of
side effectful. So it's kind of dangerous to rerun events. You wouldn't
want that as a default behavior.
I can understand why you're concerned.
I'm just saying is you can't you're not going to avoid this in a signal system.
Even if you pretend like your async isn't colorless, once you absorb it, you've created colorless async. Now,
you don't need to worry about it a ton uh in certain scenarios,
but the reality is you block the graph.
You can't not block with async. So if
you block the graph, there's going to be part that is blocked and unblocked. This
is I said the reason why something like spelt will still give you the exact proper output in the UI. They they know you block the graph. They're smart
enough to handle that.
Wonder why I I'm not I you guys are going to force me to make this felt example just to show you what I'm talking about, aren't you? Like to sorry like to me this is so obvious like but
it's because I've been looking at this for such a long time. You have you can you can okay the the one way around it I suppose is you can choose never to
consume it like it just from a practical standpoint you're probably going to do a calculation at some time or like do a computed or something to consume it like the only way you avoid it is if as you
said you literally don't you don't do double count like this you literally await in here and maybe that's the answer never do an async derive like
like bas basically a weight like you you literally have to push the weight to every single call point which means that every derivation everything you calculate off it it has to go
through like a a then promise chain instead of like being able to just do something nice like count times two or double count three or format username you have to force the whole chain
through then then be very rigid to never resolve early or yes, this whole category goes away.
The reason I'm I'm I'm I'm I'm bringing this up is because is because so many of these issues
are based on like basically this kind of problem.
Like think about it. If you built built a system like React where it doesn't update after you call call it like you do you don't see it updated are you going to read stuff afterwards in event
handlers and setting state? Nope. You're
not going to do it like the the impact talks about pit of success. 0000 is pit of success if you think about it because
why if if you know the value is never going to update there why would you read it afterwards if you actually want to update it what you're going to do is you're going to take the value updated and use that
further down in your calculation right you're going to be like you instead of instead of using books length or whatever or or even read books you're
just going to take this you could be like new books and then go new books.length and this and you're not
books.length and this and you're not going to read reactively afterwards.
So React's API design actually guides you to do the right thing.
It's so like we're fighting this so hard when the answer is like kind of obvious, right? We have a real physical
right? We have a real physical constraint, something that we can try and work or hack around,
but it it's it's the it's the wrong mindset to to view these events as being inside
the system.
We have a synchronous system with events and uh side effects spinning out of them around it. If you view those as truly
around it. If you view those as truly external to the system, you can preserve the integrity of the system.
React hit here obviously because they had components and there's inside and outside the component means very very different things. But
different things. But the like the the the shape of the problem is real.
Yeah. Yeah. And to be fair, when we were working Marco, we we went even harder. I
I don't know if Marco 6 landed here, but we're like, I don't want to think about this. If someone tries to do this, just
this. If someone tries to do this, just throw. We're just like, just error,
throw. We're just like, just error, right? Which is like the the really like
right? Which is like the the really like nuclear option here. But the other option, and maybe like, you know, maybe
that's that's that's sane, but the other option is React's option is still very very um consistent.
Like I I I get it why people are fighting this so much because this is a big departure, but it's you
the the experience of what you have to force in order to get here and the impact of these changes in order to get here seems
seems incredibly extreme versus the simple truth of this like don't do this.
No, I'm not saying this has nothing to do with performance. This has to do with correctness.
Um, I'm not quite sure what this has to do with are you just talking like threading consistency model? I I mean I don't
consistency model? I I mean I don't think that's the case. Now I we have solutions with signals arguably which are not just vanilla JS things. We have
ways to force consistency that way. The
problem is these models fall apart under async pressure.
Can you throw at the D? No. Why? Why?
What are we throwing?
Also, I think I saw some of the reaction that people are probably Yeah. Like the
funny thing is the stream is like so hardcore on this stuff and it's really hard for reactive people to kind of uh stomach. But if if if I show this stuff
stomach. But if if if I show this stuff to Tanner, for example, he's just like, "Yeah, so what?" And you're telling me I just solve all of React's problems and this is the cost. It's like a
no-brainer.
You know what I mean? He's like, "Ract already has this and this is actually not even as constrained." Like it just seems like, you know what I mean? Like
Yes. Yeah. But that's that's what signals are. But I'm saying that doesn't
signals are. But I'm saying that doesn't actually solve it.
You can't have a value you don't have yet.
The as Robbie pointed out earlier, your only way out of this is make people await here. Like but it means that
await here. Like but it means that you're not consuming the promises ever basically. like you you need to
ever basically. like you you need to make sure that everything is a promise.
Like you you you're running with two systems, a promise system and a signal system which um
could be okay arguably. Um
but it it's like even spelt doesn't force you that hard down that line.
React doesn't. React has used there's always a consumption point because at a certain point people are trying to write synchronous UI and declarative things to make it easier. They're not they're not hoping to write yields and awaits
sprinkled through every single part of their code.
No, I I don't think I don't think this stuff has to be costly. What I'm talking about is completely consistently has nothing to do with performance. It's
about consistency.
I I don't see anything particularly expensive here. This is just like truth.
expensive here. This is just like truth.
It's not about performance. It's
literally about consistency.
So, this isn't like something for AI to solve. This is not a like can AI solve
solve. This is not a like can AI solve gravity?
We can build better planes. But like,
you know what I mean? Like we're talking about physics.
So So I I spelt's a great example here because spelt actually does all the right stuff in the UI. Well, mostly for the most part they write stuff in the UI, but it's still because of the the
fact that like their variables are like this that they they they still keep their original model here. I'm just
saying like in a I and I don't even think it's a big deal because as we all said just don't do this, but in in in reality when talking about the whole
thing like so basically spelt does most of this it just they have this one inconsistency in their event handlers which probably you shouldn't do anyways.
But generally there's this truth here, right? Like um I we hit this when we
right? Like um I we hit this when we were doing uh like transitions in solid 1.0 as well like where like
inside transitions solid worked like react like you'd do the right and then outside you wouldn't see the the the stuff until the transition ended. It's
just fundamentally to be consistent, it has to work that way because you're showing the user something. If they're
interacting with it, they should be interacting with what they're they see, not some future state that doesn't exist yet.
They have special spell events. Have I
missed that? I try and keep up on stuff.
I I I I don't know what what that is. Um and I don't think looking special events is going to find me on a query. I'm just
saying this is while you can ease up this constraint if you want to, you know, in small ways, it's hard to argue that React is the is
the is not the only solution here. that
it's completely correct.
It's arguably the most correct and honest approach, right? Like you we can we can we we we can like pretend it's otherwise and it will probably come to
bite us later. But even if we can this is this is the reality I had to face. I
I realize like I I could do this. I
could like force the reactivity through.
I could make it so that this was updated, but in some cases, but it's kind of a lie.
It's a convenient lie, but the problem with convenient lies are they will catch up with you.
Like I'm only thinking about the design space. I understand right now if you
space. I understand right now if you move to the future, you don't even know what kind of problems you're going to hit.
So like you kind of it's usually better to air on the side of doing the consistent honest thing than lying unless you are completely sure you can
get away with lying.
I know this not something we we love.
um dependencies of effects must be known at computation time. Now this is true that
computation time. Now this is true that yeah but that's not solving it. Sorry, I
if I haven't made it clear enough because people read this article and they're like, "Oh, yeah, view." No, it doesn't.
You can solve all of these using explicit APIs if you know to do that and guard them, right? As I said, uh I said
this in the other article like if um you can use await tick or uh or next tick in in a wait tick in spell next tick in
view. Um I think this might be a settled
view. Um I think this might be a settled thing now in spelt 2. Um in solid 1.0 you could get reacts behavior originally by calling it in batch later that was
just a way to get views behavior. Um
uh you can you know like in react you can use the callbacks on the setters as a mechanism to get something similar to uh views behavior. Um
like all the frameworks have escape hatches for the other behavior if you know to. The problem is if you start in
know to. The problem is if you start in one state, you don't know to change it.
Like it's not about like being able to do a wait next tick. It's the fact that you changed your code somewhere and now you need to do a wait next tick in like 10 different places you didn't realize.
I don't even know if I should read this one out loud. That's funny. The obvious
solution is using Remix 3. That's funny.
Um, so sorry, what is felt event delegation managing for here? It it delays running events while things are held, but then it wouldn't even be showing them. So I
don't Yeah, I'm not quite sure what I like I've definitely reproduced this bug in spelt like 100%. It's felt live.
>> I mean, I I get kind of asking the remix question. I get why people are thinking
question. I get why people are thinking remix. Um, I don't know. My gut here is
remix. Um, I don't know. My gut here is that Remix has changed their approach. I
don't know what Remix 3 is right now, but the version of Remix they showed at the unveil, I am very much in the camp that that approach is not
the way things need to head. I think
they've they've refined stuff since then, but I don't know. We won't know until they reveal it, so it's hard to say. If you're talking about the remix
say. If you're talking about the remix as they presented it a few months ago, then even it doesn't matter if AI can generate plain JS code because the
problem is plain JS code doesn't have all the edge cases encoded into it, right? Next thing you know, you're like,
right? Next thing you know, you're like, we did this on stream a couple weeks ago. You're like managing a bunch of
ago. You're like managing a bunch of extra states. Sure, they're not
extra states. Sure, they're not framework states, but they are effectively different states that you're writing to to manage like the the life cycles. And
cycles. And because they're not framework states, you're the one responsible calling update. Who cares? Your code is
update. Who cares? Your code is vanilla.js, but you didn't take into consideration all the edge cases. And
now you're talking about things like abort signals and stuff that could just be handled automatically from the shape of the graph. And instead, you're man manually managing this stuff.
Yeah, I mean you can create a debounce signal. I I I I
signal. I I I I steps you can you can almost view um the if you guys ever do you guys
remember the sirky's uh triangle problem that react did that prove concurrent rendering um you can almost view this as a form of
that because we keep our effects guarantees we can de debounce heavy work without impacting the rendering at all here because in a sense
How did I solve this terribly expensive thing?
I just made a memo request an idle call back to to propagate its thing. So there's no effect here. It's just an async derived
effect here. It's just an async derived value. So I'm kind of basically leaving
value. So I'm kind of basically leaving up to this the browser to schedule it.
And because this still participates as part of our graph, all the numbers update at the same time even though this is a hierarchical flush flush out like essentially like
now if you want to detach from the graph then you you need to do a little bit more work but that's like option something that you want to do like what this is basically doing is like like if
I didn't have this promise and I just returned seconds return seconds
Then things get really bogged up here. I
think if maybe Sorry. Oh, I have to actually put the freaking fake time out in. Sorry.
in. Sorry.
Let's before we return seconds, let's put the the the the hard let's put the work in. Okay. Now, now
work in. Okay. Now, now
we're freezing up the graph while we're moving because we're doing this expensive work that's blocking. See,
we're making sure that our UI is consistent, but like look, the even the hover state gets frozen. Oh, let me get it. Let me get the yellow away from my
it. Let me get the yellow away from my mouse.
But we can just inject async into the graph here.
And now everything is smooth even though it's doing stuff that basically takes the whole second to calculate.
Anyways, you could if if you break out a synchronous flow, you can and you would have to make it colorful like in a way that even spell doesn't make it
colorful. you literally have to like
colorful. you literally have to like pretend that like you you you you'd have to pass promises all the way down and never consume them by the framework. Um
and in that world but then the framework wouldn't be aware of like you would be resp I mean you' be what where things are today in most things you'd be responsible for consistency.
No, even then like how do you how do you make sure that one like when it's zero that it doesn't show one like you you'd
have to microch everything. So like
practically I don't think so.
That's the whole point of the video is not very economic.
You could color based on what might suspend versus instead of using promises. Yeah, you can maybe like I I
promises. Yeah, you can maybe like I I saw a really cool library this week. It
was called lazy promises where someone basically fixed all the problems with promises and libraries and wrapped the promise prim but it still involved like basically
abstracting something like a promise um like an async primitive um that was independent of the rest of the of the
reactive uh signals uh kind of graph which as I said it's a direction but it also doesn't give it's like the opposite bed it doesn't
give you that it's the opposite the bet that React and Spelt and Solid are currently taking which it doesn't give you this orchestration control. The
orchestration control is really really valuable because it lets us um write our intent in a clear way while coming up with reasonable rules to isolate change
which means that you don't have to worry about what something else is doing over here versus what it's doing over here which is very valuable in this age of AI in my in my opinion.
Huh. Of course it's you. That's why
that's that's that's why that's why you asked that leading question. Can the
framework wait the promises? Yeah. Yeah.
Yeah. That's that's that's that's ex there is a model there. It's it's not one that that
like we can do a lot more if and you could argue that we shouldn't be doing this. the framework shouldn't be taking
this. the framework shouldn't be taking that on. But if we can do a lot more if
that on. But if we can do a lot more if we absorb that.
Yeah. Yeah. I mean,
think about Okay. Can I can I can I put can I put it this way? Cell 3 was called the disappearing framework because it compiled all your JavaScript framework
code into vanillajs components. That was
the argument. I mean, it's it's not 100% accurate, but that was basically the argument.
And it did so by basically taking what you wrote and then generating a bunch of code that was very
specific to the update paths and inso was fairly efficient and it kept the framework small because the framework didn't need to actually worry about very many things. It didn't need very many
many things. It didn't need very many helper functions. But the problem with
helper functions. But the problem with this is is is this um uh to-do
MVC size comparison obviously another article I wrote but I I I I can't emphasize this enough.
What happened to our app when we added 80 to MVCs in it?
And now 80 to-do MVCs might seem a lot, but it's also not a lot when you say to-do MVC is basically like one medium size to larger size component. Like
maybe it's like four or five normalsiz components. So we're talking about maybe
components. So we're talking about maybe 300 components. Now obviously code
300 components. Now obviously code splitting and other things but you don't have to get this far to see see the scaling issue.
React spelt is is when there's one to do MVC is 3 kilobytes and you're like sweet right? We're react 37 back then and now
right? We're react 37 back then and now it's like more than that but it doesn't matter by the time we get up to 80 reacts 134 and spelt's 150 because all that code it generated because it didn't
reuse helper functions it wasn't as tight it this it actually got larger and actually when you added hydration to the picture it got even larger because of the special code paths it used to have for hydration. This is like one of the
for hydration. This is like one of the hugest biggest motivations I feel not the only one but one of the big motivations why they moved to signals and something very similar to solid and
spel 5 because spel 5 is like this it does not do that it right the and the problem was that to actually write the code it there was value in having a
shared library like and another way to look is the value of having like a like there's enough common patterns that abstracting it actually made a lot of sense now don't get me wrong AI could
also design the abstraction as Well, and and but in general a a general solution didn't kind of fit in and more so when you consider all the edge cases you have
to handle when say talking about something like async the race conditions like and you can picture this yourself by we did this on a previous stream by taking something like React 16 style and
trying to implement the proper async implementation.
It's not nice. I actually showed this off on stream where we actually came up with something last stream I think where we actually came up with something fairly reasonable actually it was the
stream before and but it still was broken and then we actually went through one an example that the simplest example ever and actually fixed it on stream and it was way more complicated than actually encoding that behavior in. So
my premise here and I I was going to talk about this a little bit when I talked about the AI generated article that uh is that these while higher level
abstractions opinions might get boiled away by AI being able to just junk this stuff together you know so to speak like meta frameworks you know everyone's going to have their own meta framework kind of deal what all this is doing is putting pressure to push the core
fundamentals into the language into the core framework more in a sense react or solid or spelt or view or whatever is more like a programming language than it
is like a library. Uh at the at this point because of the way it abstracts over the JavaScripted DOM and HTML stuff, we can talk about transparency, we can talk about differences of compiler, all this stuff, but generally
speaking, it's better to think of it that way. So while you know beat plus
that way. So while you know beat plus might release a new meta framework that's basically let you do spelt or solid react or whatever you know
generally speaking there we're not talking about replacing react in that equation. Do you know what I mean? So from that perspective, there
I mean? So from that perspective, there might be a reality of this, but until the AIs can hold what I have in my head that I actually can't even keep in my
head, honestly, cuz it keeps on flowing out when I work on specific problems, unless AI can keep more than I can keep in my head when solving every single problem it approaches, we're not going
here anytime soon.
Yeah, that makes sense to me.
So, wasn't this an AI question? It's
talking about tokens.
Sorry, did I did I misunderstand this? I
thought So yeah, in any case, um, a little bit of a tangent. Uh,
tangent. Uh, where were we? Um,
I don't even know where we were anymore, honestly. That got so deep down.
honestly. That got so deep down.
Yeah, I was going to start talking about effects. I think is where we we got we
effects. I think is where we we got we where we got to the the and I was saying that there are some different approaches
here.
The PEZ effect must be known at computation time. Okay, this is a a true
computation time. Okay, this is a a true story and actually let me let me pull something up here because Rich Harris actually responded to my article um
because he said he disagreed and I I think he has a right to disagree here.
Let me see if I can actually find it.
Okay, because interesting post I disagree. He didn't argue with me about
disagree. He didn't argue with me about the flush semantics, funnily enough, which is actually I think the trickier one. Um, but if async is only discovered
one. Um, but if async is only discovered during side effects, it's already too late, which is true. The solution is to update async stuff first, then run side effects once resolved. Repeat until
settled. So you have something like this and slug changes, right? Okay. Then the
post starts updating immediately. In
other words, while it looks like a derived, it's actually a special kind of effect that gets a jump on the queue along with the control flow. The
compiler creates these effects where they see a way. So he's basically describing what salt 5 does. Um, which
is is how they get this thing. So within
effects the world is consistent. You can
force inconsistency outside effects are right slug blah blah blah but easily avoided with the system could warn without necessary. Okay. So basically
without necessary. Okay. So basically
what what he's what he's pointing at here is because they have the compiler they can look scan for these await keywords and then do like a special
transform kind of hoisting to ensure that all of that is resolved before running any side effects
which contradicts something that I actually said in the article um which and he's he's right uh he's he's definitely right there there's There's
impact of this change, but it's it's not impossible. The the the actual invariant
impossible. The the the actual invariant is this one. This is true. This is the physics. This is what you can't actually
physics. This is what you can't actually argue with.
But the the the solution of using a compiler is viable in some cases where I said it might not be. So why is this important? I I I feel like this one's a
important? I I I feel like this one's a lot easier to understand, but it's if you pretend these console logs are effects, like each independent effects,
like essentially if if you have the ability to pause or halt or execution on any one of these, you have no clue what what's going to log here. Like pretend A
returns a the letter A, B returns the letter B, and C returns the letter C.
Initially, what gets console log? I've used this example on stream, but I really want to nail this down for people here. Can
someone tell me if fetch A returns lowerase A, fetch B returns lowerase B, and fetch C returns lowerase C in some kind of like async blocking kind of
system what what gets console logged by this effect?
Obviously, it depends on the system, but I I'm like very much open to to guesses here, right? I mean, you obviously have to
right? I mean, you obviously have to answer that with this thing like, do we assume that they're null initially or do we assume that they that they that they
throw or do we assume, you know, like I use signal semantics here. Now, if the if they were awaited,
here. Now, if the if they were awaited, granted, then you would the answer is fairly
straightforward. It would log A, then B,
straightforward. It would log A, then B, then C, right? Yeah. I'm saying that these three
right? Yeah. I'm saying that these three are promises. I'm just saying if you
are promises. I'm just saying if you have some sort of system that absorbs these promises, right? So, yeah. So for Robbie saying
right? So, yeah. So for Robbie saying like if you throw it's a ab ABC abc maybe it could also be a abc
and I think it can also be there's a world where it's ABC I think is there a world where it's ABC yes there is a world where it can be also ABC um
it see results first.
How would it be?
Yeah. And it can also be AB ABC. Yeah.
Yeah. That's the last one. I think we got them all.
Yeah. Yeah. Yeah. Yeah. Perfect. I think
I think we I think we captured them all.
So we got ABC A B C ABC and AB AB BC right and you might be like who cares a
console log but picture if this was actual side effects the work you had to do I I know that effect will run only when all the problems are you show long time ago right well here's the thing I'm
just saying in general We don't actually know. It could be all of those.
Yes, that's that's the Yes, the that's where I'm getting to here. It's even
more fun if these can get updated after the fact. So, that's initial run. What
the fact. So, that's initial run. What
if uh what if B triggers an update later? Um,
and then while it's updating, A triggers an update. Like the honestly,
an update. Like the honestly, you don't know.
And that's only one effect. What if
what if these were all separate effects, right? And you you need all the effects
right? And you you need all the effects to run at the same time to be synchronous, but each A, B, and C are each logged in a separate effect.
So, you know, A is there. So, you go and log it, and then you hit B and then you, oh crap, it's async, I can't log it.
you've now broken in the same sort of way because you weren't able to resolve all the effects, you know, like what if these are based on the same change like count, double count. What if these were all double
count. What if these were all double count, double count, triple count, quadruple count, right?
You you've now broken the chain somewhere. So now you show the count and
somewhere. So now you show the count and you show double, but you don't have triple or quadruple yet. So you show the old value or you show null or like the
UI affordances can always be figured out because you can always design around them. But I'm talking about like the
them. But I'm talking about like the consistency in your data graph. What is
it supposed to do?
See, it doesn't really matter until you get to the side effects where people can see though that you actually have a problem here because if AB ABC if the if
the I if nobody sees this progression there there's an efficiency question obviously but like for performance but generally speaking it doesn't matter cuz
you know if no one's you know tree falls in the woods no one there to hear like there's no there's no side effect but as soon as you add side effects to the equation,
you it's not just enough to know all the dependencies up front in a particular effect because like if if if we if I rewrote this example
to um to something like this like if I took this and I was like okay simple con a equals a
const B equals B con C= C and then I just went like
if I just did this and I was like okay no problem guys and you ask me what it logged it's actually really easy now because we can just say it logs ABC
if there's any kind of pausing or interruption value here no matter what the order is this will log ABC every right? If you if you make it a wait, I
right? If you if you make it a wait, I mean there's there there's one challenge with this which you already know is that reactive tracking is synchronous. So in
order to do that, you would actually also have to um wrap the wrapper with the context somehow or like async context or something. So,
and honestly, um, I'm not even sure how I feel about that.
I I think my perspective is changing a bit over time, but like traditionally, I don't even like the idea of tracking after a weight. I don't think it makes sense because now you're connecting two places in time that you shouldn't be.
Like I I actually think the sync constraint on tracking is actually a really really good thing because you don't necessarily like if you if you track before an await and then track after wait you don't want to necessarily start the whole thing over especially if you're doing expensive work. Now
obviously you can say hoist the fetching outside just to wait the thing but then why are you even awaiting in there anyways you're forcing a microtask on something that doesn't need to be a microtask like the whole shape of the
solution is awkward.
Yeah. So, because if if this throws or this throws or this blocks, we basically move everything down is is what I'm trying to say. But the problem with this is that's fine for one effect.
Now I have two effects.
This one depends on this and this one depends on this.
Tada. I have the same problem. It's not
enough to hoist it to the beginning of the function. I need to run all of these
the function. I need to run all of these before I run any of these.
Yeah. But you understand the the whole problem is throwing I am saying throwing but throwing is too late. If you
interle, if you have the initial problem that I have in my article, throwing is too late here. If you throw at B, you've already ran A.
Throwing doesn't solve this.
You know, a waiting does because it has true continuations, but now you are in an async world. Do you wait every value?
Well, no. you wait promises which means like there's consequences of being colored and we'll talk about those a bit more in a minute but what I'm getting at is th this is this is why there is an
important distinction here my premise that you have to like basically do what React does with dependency arrays is because it's colorless if you are
colored you have the ability to know what you're dealing with ahead of time like Rich was talking about like in with his compiler but there There's still like an awkwardness like if if there wasn't a compiler let's say you
were completely runtime you wanted this solution to work without any fancy compilers just be purejs signals library sound like a library you know right I'm
big on plain js from like the runtime perspective on that side I we don't compile your your your your syntax
we compile your templates that's it and what what I'm getting at here is in in that kind of world, it's a lot harder because yes, you can await in
here. You sorry, you can await in here.
here. You sorry, you can await in here.
Let's like don't get me wrong. Now, now
we're we're awaiting, right?
In fact, we can even await our original example, right? We can let's just go
example, right? We can let's just go back. Let's go back.
back. Let's go back.
Let's let's await our original example.
So now await await because we know that these aren't actually async signals. They're signals
of promises. Okay. So now we're awaiting them, right? This will log ABC
them, right? This will log ABC technically, but it'll also always log it as an microtask. It will never log
ABC, right? It'll never log even after
ABC, right? It'll never log even after the fact, even when updates happen or whatever. It never logs ABC. It always
whatever. It never logs ABC. It always
logs logs a b c.
Right and and and there's other consequences here potentially. I don't know if all if if
potentially. I don't know if all if if you're expecting like it to trigger like lazy.
Yeah. Like
the problem is and this isn't avoidable by you. The await keyword does this. Now
by you. The await keyword does this. Now
if you made your own thenables like made a special signal like this and then had your own read semantics
but even then you need it you need the this is this is actually actually tricky. I don't think you can do this
tricky. I don't think you can do this without a compiler because await means async function actually means 100% microtask and
if you if you wrap it you you lose that still there's no way there's no type of wrapping that avoids that microtask what
you can do if you look like go look at spelt compile code these awaits disappear they actually compile them out I mean it's clever Um, but there's there's other impacts of
this.
Do we need promise all? Um, you could, but promise all again only helps us in this scope.
You know what I mean? Like
promise all will at least push it on to I I think one microtask instead of multiple.
Yeah. I mean, we we need that as well.
We also need read a but I'm saying read a enough isn't read isn't enough here to avoid the microtask.
I mean monkey patch all side effects and then tire dominant defer them automatically. I mean what I'm getting
automatically. I mean what I'm getting at here is I'm hoping you're starting to see that even though we're working in a computer
world that there are real constraints to the system. there is
the system. there is physics. Um,
physics. Um, now in my article I I do I I I said that the solution was this, right? It looks like a dependency
this, right? It looks like a dependency array because it is basically a dependency array because if it doesn't have to be a dependency array, but I want I'll show you some key differences
here. But if you do this now, you
here. But if you do this now, you separate the tracking from this. You can
do all of this before you do all all of this. And more so if you do this
this. And more so if you do this and you know this one has B and C to go back to my other example and this one has A at which point it doesn't even
need to be wrapped. In fact, we can just do A and then this one can be A.
If we do this, we can run this and this before we run this or this. And our
system is consistent. And this did not take a
is consistent. And this did not take a compiler. It did not take any, you know,
compiler. It did not take any, you know, it does not force microtasks on you ever. Um, except for when it has to
ever. Um, except for when it has to wait. It doesn't force like after the
wait. It doesn't force like after the fact microtasks like if these values are available to you then that's exactly what you get.
The new syntaxes is so ugly. It's
probably a very good feature. Yeah. I
mean because really don't try and don't synchronize state with effects. Don't
use effects that you don't need to use effects on. Like I I actually even
effects on. Like I I actually even though this is uglier I almost view this as a fe as a feature.
Yes.
Yes.
Because generators don't have to go async. So as long as your primitive um
async. So as long as your primitive um go as long as your primitive exposes the ability to sync read then like you you patch something that isn't a promise and
you you could actually also handle your yield in one way. So generators are actually one of the cleanest solutions here because what you can do with generators which is really really really really
nice is and yeah I mean Milo actually tried to build a whole version of before there's reactively and there's R3 right
solid's based on solid uh 2.0 started on reactively which is R1 essentially and then is built solid 2.0 know now is built on R3. And you guys are probably
like, what happened to R2?
R2 was built completely on generators.
Um, so what's cool what's cool about generators is is you can do you can do this.
There's there's two things really cool about generators.
Console.log log yield a do it like this.
What's really cool about generators is some is is that we don't care.
First of all, you notice there's no function call here. It's because the yield can be just the read.
we don't we don't actually um need to call a function here and even if it's async it can happen after and so instead of having explicit recall we can
actually resume our context simply by by doing the yield here. So like we don't act even though this is like could be async not async we don't know we have the ability to continue without having a
special track function or read function.
Secondly, we don't care if it's async, if it's a promise, if it's async, whatever. We can handle it. That detail
whatever. We can handle it. That detail
is buried. So technically, this is like basically perfect except for you everything that you ever do from now on is going to be wrapped in a generator
function. And uh um
function. And uh um what what else is not great about this?
uh performance of generators is generally like when you try to make it like Milo basically had to just stop this experiment because of performance and now so this might be the question where someone asked earlier you know is
performance a gap on the reactive systems in this case yes uh we also played with this in Marco like on the server rendering this actually makes ton ton more sense because I was saying there's actually crankjs which is based
on generators which also um is an interesting experiment I don't think components should be generators I think that was the issue with crank crank like I think crank I think if you
had a run once model with reactivity as generators that would be very interesting but crank was almost like a react model in a sense like where like the
components were generators because they were trying to like do async flow I think with a small refinement generator is a very interesting place because yield hides all the async semantics in a
way that is consistent allows you to do tracking and completely works. So yes,
but there there's a couple gaps. People
don't get generator functions generally like it's it's like really hard. People
get like almost upset when they see them. And secondly, performance is
them. And secondly, performance is terrible.
Really? It's going to be the same problem as a wait.
Can't Can't I res No, I mean Oh, no.
Does it force It doesn't It doesn't force me into a microtask, too. I I'm
saying like what if my primitive still absorbs the fact that it's a promise.
Like I if if a is a promise and it's colorful, yes, but I I I think if this is colorless, this doesn't have the same problem.
I mean, we tested this less than like maybe six months ago.
I also think that this is a little bit too exotic as people are saying like it's pretty exotic. Like even we're testing the idea by bringing generators
into our actions. I I think Oh right right.
Well, no. I No, my point was that it can be synchronous. These can This can be
be synchronous. These can This can be synchronous.
Yeah, but I don't think it matters.
I don't think it Yeah, I I I Yeah, I I get what you're saying.
Like you're you're basically opting into a model where you're okay if some side effects show up later. Like this is this is not good for rendering like like the
DOM.
Yeah, you're right. The late discovery is still a problem. I was thinking that Yeah. You know what? Yeah. late. Yeah.
Yeah. You know what? Yeah. late. Yeah.
Yeah. This is this is this this isn't even 100% solution. This
is like good in the sense that like the the effect itself executing is fine, but it doesn't it doesn't actually again
doesn't help us really with like this either, you know, like this is still a problem because we don't discover this until I
Yeah.
Yeah, exactly. Thanks, Robbie. And you
guys are dead on. I got way too excited about generators. So, yes, supporting my
about generators. So, yes, supporting my This is physics.
That's not what impression I got. Maybe
there's some new stuff that I haven't seen yet and I'm excited too. My
impression is more that what I'm talking about is more like the Rust of JavaScript frameworks. You'll see when
JavaScript frameworks. You'll see when we get into Salt 2.0 for better or for worse because the way you constrain this stuff is through lots of errors and control mechanisms. And remix is more
like the jQuery like it's like lets you write as much garbage as you can but then it it can absorb it.
So okay well I mean so yeah so the our conclusion is actually generators don't solve this either. So you're you're forced to basically do some kind of
inscope compiler analysis or you know just freaking split the effects already.
Now is this I think this is better than reacts dependency arrays for multiple reasons.
First of all, first simple thing is we have prior art here. Vue watchers have done this for years. Even if it was for slightly different reasons, it proves that people can work with this. It's not
you. I don't remember people complaining about Vue watchers because Vue only got the combined effect like in some point in Vue3. I I think you had to do
in Vue3. I I think you had to do watchers all through Vue 2. Nobody cared
like it wasn't like React. And I I I think there's a couple reasons for this.
First of all, this stuff is dynamic still. It's not a fixed thing. You can
still. It's not a fixed thing. You can
conditionally subscribe. You can change the dependency
subscribe. You can change the dependency arrays. You can like it doesn't have to
arrays. You can like it doesn't have to be an array. It can be an object. It
could be a single value. It could be whatever the hell you want. It can be deep. It can be nested. It could be
deep. It can be nested. It could be whatever does shape, form, whatever you need to track. It can be done. Don't get
me wrong, there's pain point here around deeply conditional logic stuff that probably should be split into multiple effects for example um or like requires stuff like don't get me wrong there's
limits here but purely 0.1 compared to something like react is it is still very much dynamic it can still discover dependencies when
you call a function that isn't in scope right second difference values are passed through you don't read see in
here like as a function you read it from here which means that oh what if I miss a dependency you don't miss a dependency because if you try and read C in here
we'll tell you that you're reading in an unttracked scope I think I finally got that bug fix that it wasn't working um you know uh no I probably should uh update my
template here actually let's go stack blitz for a second and go what have we got uh beta template. Solid 2.0 beta template. We did a release today, right?
template. We did a release today, right?
That's what I was doing a few minutes ago. Let's update the template to beta
ago. Let's update the template to beta 4.
Oh, no, sorry. This one's beta 2 still.
I think it might be beta 3. Update this
one to beta 4 and beta 4.
Save.
Let's just refresh the whole thing.
Should an effect also throw when you when you read a signal in effect inside of an effect like inside the back half? Maybe
throw. I've been I've been playing with warnings, but let let's let's fork this and and play a bit because hopefully those things that I was trying to show in the previous stream actually work
now. Okay.
now. Okay.
So, let's let's go here. So, our first thing is let's gut all of this stuff for a
second and just give myself a hello. Am I
alive? Yeah. Hello. I'm alive.
Beautiful. Okay. Second thing we want to do, we want to
what is it? import
create signal and probably create effect from solid J. It's beautiful. Okay, so let's
solid J. It's beautiful. Okay, so let's go const count count. We're just making a counter
count count. We're just making a counter set count equals create signal zero. Beautiful.
zero. Beautiful.
Um, we can count in the UI just for fun. Um,
whatever. Let's just make it a button.
Get I'm glad HMR is working properly now click do the simple thing set count C + one
lovely okay cool counter working okay so let's create our effect create effect and let's make it depend on C but then do something funny like console.log
C sorry it's count on count and console.log log count.
and console.log log count.
Sorry, let me I don't know why I refreshed that. I didn't mean to.
refreshed that. I didn't mean to.
Is this going to work properly?
Reactive value read directly in effect callback will not update. Move it to the tracking scope JSX a memo or effects compute function.
There we go. Thank god. So,
and it's going to keep on bugging you about this. So right off the bat, if you
about this. So right off the bat, if you try to read a reactive value on the back half of an effect like this, it's going to tell you you
are doing bad things. Okay. Um, thank
you. Just like if you try to read count out here at the top of your component, it should also tell you that you're doing bad things.
Although I'm not thinking I'm not seeing it.
Why is that one still not working?
It's annoying. I I spent so much trying to fix fix this. It actually gives you the component name and everything.
Oh man, that's so annoying.
At least the backup the effect one's working.
I I fixed, you know what it is? Solid
refresh. I had to fix solid refresh.
That's why. Uh let's remove our node module. Remove our package
module. Remove our package lock the PNPM lock. And let's try this again.
Yeah, side dev4 side effect is much better than death side through react.
Yeah. Well, because you pass them through right?
All right. So, hopefully
this is this was just a module update issue.
Yes, I I a reactive valley red in directly anonymous will not update. Move it into a tracking scope.
It's anonymous because of this style.
Oh, that's that's that's unfortunate. It
can't tell the name. Like if this was called function app, it would know.
Like if I if this was instead function app, it happens.
reactive. Oh, but it's your compiled name. That's interesting. Reactive
name. That's interesting. Reactive
values read directly in app 2 will not update. Move it to tracking scope tsx
update. Move it to tracking scope tsx thing. That's okay. It's not perfect,
thing. That's okay. It's not perfect, but you get the idea. Effect red
directly and effect callback will not update.
So what what I'm but what you understand what I'm getting at here? Here we were talking about the rust of of JavaScript frameworks, right? The funny thing is
frameworks, right? The funny thing is you might be read this like does that mean solid has a bunch of hook rules?
There's still only there's now a second rule. There used to be a rule about
rule. There used to be a rule about losing reactivity, right? You don't want to read in a top level scope, right? Now
there is a second rule which is that you don't want to write in a tracking scope.
So but they they essentially are the same rules that f that filter out of this. But what's what's key about this
this. But what's what's key about this which as I said makes me really really happy is silly stuff now like um you know if someone does something like
um counter and and and does things like uh what do we want them to do here? Uh destructure.
And they're like, "Damn, why does this count? Never update." You know what I
count? Never update." You know what I mean?
Well, it starts by actually, you know, someone take some React code, right?
Fine. I mean, this is what count is a number. Whatever. Yes. Okay.
number. Whatever. Yes. Okay.
Sorry.
Did I do that? Bro, I I did something that broke something. It's funny. I'll
figure it out in a minute.
Um, let's make it this.
Make it this.
Go count.
Count equals count.
Did I break?
Okay, HMR is not perfect.
Hopefully what we will see here is Why am I not seeing the funny reactive value read directly in the
callback will not update? Where is
dstructuring? Should have found that one.
Uh, let me get rid of the effect callback one for a second.
There's so many other warnings in stack blitz. Yeah, reactive value read
blitz. Yeah, reactive value read directly in counter 2 will not update.
Move it inside a tracking scope. I I
guess it's solid refresh, which is renaming everything because it has to make a wrapper. That's
funny.
But you you get my point. Dstructuring
it basically tells you that you you've read an encounter and that and it's not going to update.
I I'm I don't even know. I I don't make opinions about stuff like this.
I just wanted to kind of like sanity check here um that this stuff works. So yeah,
essentially ignoring all the weird DAC blue issues, you can actually see that um
this doesn't update and it tells you exactly why it won't update. move it
reactive value read directly in counter two will not update move it into a tracking scope JSX a memo or an effect compute again so you might not know that you're dstructuring props to be fair but
at least there's a there's a hint I've the funniest thing is since I added all these warnings AI has gotten like I mean AI was already
okay at this stuff but like AI immediately like sees stuff and it's like oh there's a warning I shouldn't do this okay let me reenter this especially for like writing tests It's like almost like an immediate
signal for AI that it's doing the wrong thing. It's just like, okay,
thing. It's just like, okay, yeah, I I didn't see this because in test I don't see this. The the name mangling is happening like this is only dev warning, so it's fine. The name
mangling is happening because solid refresh. We could probably reverse the
refresh. We could probably reverse the name mangling so that the original component name is what gets put here and that the name like the the the mangling happens to the other one. Do you know what I
mean? Like there's probably a way that I
mean? Like there's probably a way that I can make this better in solid refresh.
No, what what's happening here is is that I'm I'm I'm dstructuring here which is doing a
reactive read. That's the problem. And
reactive read. That's the problem. And
and people hit this and they like we have warnings in our llinters to prevent this. But now there's a runtime warning
this. But now there's a runtime warning that tells you, hey, reactive value read directly in the counter component will not update. move it into tracking scope
not update. move it into tracking scope like GSX. So instead of doing it this
like GSX. So instead of doing it this way, if I change it to props count,
what'll happen is this warning won't exist anymore. Hopefully
looks like I have preserve log on. Let
me see.
Or stack with just preserves the log.
Okay, whatever. But if I refresh it, you'll see that there's no warning anymore.
and that this actually updates properly.
I still need this types here. Count is a number log log the function itself so it makes clickable to find the source.
Yeah, I need to do that more often. I'll
update that in the next version. Thanks.
I'm I'm not dstructuring a number. I'm
dstructuring props.
Right? Props is an object that has count on it. So what I was doing was I was
on it. So what I was doing was I was destructuring props.
This is perfectly valid. That's why you see a zero here. If if we initialized at five, you're going to see five here. The
problem is it just will never update.
People do this in React all the time, but it doesn't work in solid. And now we we we warn about it. But just a side note, I I
what I actually wanted to focus on here was that that the effects, the shape of effects here, like the create effect is actually kind of nice
from the perspective that People are always like, "I'm worried that I'm going to miss a dependency or something." It's like, you're not going
something." It's like, you're not going to miss a dependency because you wouldn't have it to use.
Like that's that that's not a concern here. You can't log count unless it's a
here. You can't log count unless it's a dependence. Like
dependence. Like this kind of flows out of it, right?
Because if you try and read it directly, then it's going to cause you an issue.
So this is this basically gives you the right guard rails because you're not going to miss dependencies.
You're going to maybe overs subscribe.
Yeah, getting into this is a is a is a godsend. I mean to be fair this a lot of
godsend. I mean to be fair this a lot of these can be found by ESLints but there's ones that can't be like the back half of effects is probably not easy to discover by ESLint. I guess it could it could look literally for the signature
but it might not find it in my custom effect or something you know like these can be anything. This can be a custom hook.
No. And I'm glad you asked because that we're in the next area. Can a compiler solve this? Um, and I'm wrong about this
solve this? Um, and I'm wrong about this in a certain sense, but I'm not wrong on the other on the other sense here because this is the first thing that people go to when the when they're
talking about this. And the thing is compiler can solve the general problem as rich pointed out to a certain degree if you have colored async but a compiler
can't undo the effects dependencies from a generic like colorless standpoint.
So could it a compiler extract dependency in a single effect function?
In a shallow sense yes reacts compiler does exactly that. So does felt 3. But
the compiler based extraction only sees what's in scope. You can't see the whole graph. If your sources or functions that
graph. If your sources or functions that call signals rather than signals themselves, the compiler has no way to know whether those functions are pure or whether they hide side effects. This
exactly why spelt 5 moved to ruins.
Compiler time dependency capture hit a hard limit. It couldn't track sources
hard limit. It couldn't track sources that weren't syntactically visible. What
I mean is if you've ever done this something like this in spelt, you'll know what I'm talking about.
This in spelt 4, this is like a reactive value. So if you put doubled equals
value. So if you put doubled equals count x times two, it will update. But
if you call a function that does the count x times two out here, spelt couldn't see it. Spelt doesn't like react moves would move like compiler
would like move get double count out.
Yeah, let me make this a little bit let me make this let me use react language and make or solid language and make this a little bit more visible for everyone so you can understand. So let's let's
make this solid now. So we want count set count. Okay.
set count. Okay.
Okay.
So equals create signal. Okay. So we're using
create signal. Okay. So we're using we're using solid syntax.
And then this here is a memo. Um, but
I'm gonna use an effect here.
I I'm actually gonna I'm gonna use a split effect for or like a react style effect.
Uh, how do I want to do this?
It's fine. I I will use split effect here. Like I'll use the new solid APIs
here. Like I'll use the new solid APIs for the sake of trying to show this. Um
um there's only one dependency so I'm going to but I'm going to still dstructure it for the sake of doing
this. Okay, cool. So
this. Okay, cool. So
console.log
effect. Okay
or count.
Now I guess what I should do is I should what I should do is actually write what you would think you would write instead. So let's go here. Let's
write instead. So let's go here. Let's
pretend our effects like this. So this
is in and this is compiler. Okay.
So the the difference um with spelt or solid and it it's kind of important here spelt doesn't have this
right and react doesn't have this. So
when they look and extract the the the uh the dependencies here, um their first thing would be
you'd have to have a special processing to unwrap signals, right? Cuz anything
that you saw here that was closed over, you would have to know like how to handle it, right? But the
the question is what should it handle because sorry if let's let's change this to get double count for a second. So
this is a function in react what you would do generally speaking is you'd extract the function right and then you would go okay so get
double count and then you could call get double count here.
This doesn't help us because you're still calling the function in the wrong in the wrong spot,
right? Like reason this works in React
right? Like reason this works in React is because um the component reruns. So the every time the component reruns this reference will
change. So like when you update count
change. So like when you update count you get a new get double count function which means that this will invalidate and then you will call your function but
but that that's not good for us for re on a reactive side because we actually want to track the reactive reads and this function never gets recreated again.
So what's your options? You could not call the function here essentially and like do something kind of smart where you're
like okay I see I see the I see the function I should call it here.
But the problem with this is how do you deter determine it like in something like spelt you can see that the reactive values are are local values I think um but what if
it's coming from somewhere else like it's it's a it's like what if this is actually a function um you don't know if this function is get
double count, which is what we want to do. Or if this function is do crazy
do. Or if this function is do crazy side effect, what's different between these two functions
that tells us which one should go here and which one should go here?
If it's just a symbol like React does, it doesn't matter because you're going to do all the work here anyways. But if
if if we have these two functions and we treat them the same because they're function calls.
Also not good.
What if you do create effect? I I think I already showed this that we we give you a warning.
I you might have missed that part of the stream. Um if if you if you do this
stream. Um if if you if you do this maybe it should throw or be a little stronger. Um but reactive value read in
stronger. Um but reactive value read in the effect call back will not update.
Move it to the tracking scope. Either
JSX a memo or an effects compute function which is the first function. So
we actually tell you you're doing something wrong if you do this.
So anyway, my key point here is unless everything is kind of treated top level um
like we don't like the compiler like this is the huge difference. React
reruns so when it looks at the dependency arrays they're not deep. It
doesn't really care. It just gets a symbol and goes, "Okay, if if it's closed over, like basically there's something smart it can do here. It knows
it can't read local state if it's not in the same scope. If if the function's global, so it like doesn't change. Like
the only way count gets into double count is if it's at in the in this below this component scope, which means that when you rerun the component, you're going to get a new function.
Right? This is why like what use callback does but it's kind of like funny in the sense that um like you can invalidate like if if in React if you if
you want to memoize a you memoize functions like you might go you might invalidate this function whenever count changes which is like makes sense but is completely bonkers from a signals perspective like a single run
perspective like you would never memoize a function like why why would you create a new function just because count changes is you just read count.
So in a sense a simple system like React which reruns components or like spelt 3 which reruns components could get away with this. But as soon as you have deep
with this. But as soon as you have deep discoverable reactivity, you can't differentiate between you have two choices. You have to force
this to only grab actual known signals.
So you kill composition or or you just can't do it like you you risk leaking side effects.
Yeah. Well, and the funny thing is the way we think is really weird. Like I I had guys from the React Core team like arguing with me about this stuff and they're like, "Well, how would you do this crazy case?" And they showed like this thing with function memorization.
I'm like, "I never thought of memorizing the function. I just
the function. I just read the signal like they they came up with like a pretty good con convoluted case and my solve was so simple. Um
and like because they were looking to try and solve it in a React way and I'm just like just the the the functions a stable reference like that's not what you should be invalidating on. You
should be invalidating on the actual things that change which actually made the code cleaner and smoother. I think
it was I forget who I was debating it with. I think it might have even been
with. I think it might have even been Seb himself.
My my point is from a pure like hoist the effect standpoint, React can do this, but it's but we cannot. And the same
reason why we cannot is what gives us that richness that we can do stuff like this where we can deeply discover stuff. It
doesn't have to be accounted. What if
it's a proxy with properties and stuff?
We're not looking for specific symbols that so we don't have to look in a shallow scope. The react this is why
shallow scope. The react this is why runtime reactivity is so freaking powerful.
I think I will stay with React. It gives
me job security.
So the react compiler and so no what I'm saying is the react compiler can't can't and they probably won't and spelt already is solid system. I'm saying old
spelt was different but salt spelt realized that they couldn't actually solve this with a compiler so they introduced ruins or runes.
They couldn't 100% solve it. you you the spel community was like very upset that they suddenly had the right state this and they couldn't just do let count you
know for example but this little bit of extra syntax gave spelt enough that it could it could basically solve this problem but you
know spelt isn't doing this spelt is doing it solid 1.0 O style where it just you you you write
you know you write count this this is the this is what salt 5 did 5 took you writing this
and instead outputs this more or less I mean, it doesn't use our syntax for dstructuring under the hood. It probably
just puts it on a on a on a thing, but it it goes through and goes, "Okay, where's all the references to count?"
Okay, count is here. Make that a get.
Where's this? This is already fine.
Nothing special here.
Um, yeah. And now there's no out here yet.
yeah. And now there's no out here yet.
Like the all spelts compiler is doing right now for the most part for the signal stuff is literally looking for where you your call site is. um taking the special
object there and then finding that symbol and just turning them into gets or sets.
Oh, confirm staying on react. That's
funny.
It's supposed to do the opposite. It's
Oh, no, no, sorry. Confirm this. That
always the only way to stay sane.
That was a joke. Ah, it's all good.
Basically just a solid rapper. Yeah, I
mean there there are differences in stuff and especially in the async solution, but like generally speaking, the move this felt 5 put us very much in a line and
view vapor for view as well. Like Vue
already had signals, but the actual rendering mechanics are much much closer. There's obviously differences
closer. There's obviously differences and stuff. I but like it
and stuff. I but like it I would say that I mean and this surprised no one. I'd say that spelt 5 is much closer to solid now obviously um
than spelt 3 was to solid spelt 3 was basically yeah how do I frame frame this right because spelt 3 is like react but it's actually like spelt 5 is more similar to
solid than spelt 3 was to react but that comes as a surprise to no one but probably comes to bigger surprise was that spelt 3 was closer to react than it was to solid that's probably the bigger
surprise to people like significantly closer to react than it wants to solid.
Um okay.
But my my my point is in a pure sense compiler can't solve this from the dependency. But if you attack this the
dependency. But if you attack this the way that rich has, compiler can solve this because what rich did is a little bit smarter.
So instead if if you recognize here that double count equals sorry con doesn't make sense
anymore whatever it doesn't matter but if you realize that double count is like dollar sign derived um await
count times two some effect of double count. What you
can do is like I'm not going to say this is 100% how spelt does it, but they can first of all they're not blocking your whole
component necessarily. What they're
component necessarily. What they're doing is they're probably uh kind of doing something like Async derived
like they're probably eating your await.
Remember to change it to a function. So
you call the count and then they're async derived. I I believe they has the ability to block effects. So
before Yeah, this one becomes a getter.
So this becomes a getter. So essentially
although it has to do more than that because how do they know that this dependency is on this dependency?
Okay, let's see what spell outputs.
Why guess?
Why guess? We don't need to guess.
Uh, wait, we have count already.
Let double count equals dollar sign derived await.
Um, I'm just going to do it sync. I I'm
hoping this still works.
There's no name here anymore.
I just want to see if if this picks up on it. Oh, okay. Yeah. Oh, it's Yeah.
on it. Oh, okay. Yeah. Oh, it's Yeah.
Yeah. It's even smarter than this. It
actually looks for the Okay.
What if I had another one?
That triple count.
What if I do something in the middle that's completely unrelated?
I'm I'm just I'm just really curious.
Count two. Let's make count three.
Whatever. It doesn't matter.
Oh interesting.
It tries to keep top level semantics through the async. See how
below is above is fine.
Let's let's do below.
So count let's make this three and let's make this two.
Okay, so everything above the first await is is not part of it. But then it
basically has a special runner to process these uh things and and guards the asyncness of it. Right.
Interesting. Okay. Just just aside I the details aren't here too important but the important thing to understand here is that these now are kind of tied together. This is like the consumption
together. This is like the consumption point is in the components essentially which is frees you up so that the like the rest of this can act independently.
You know what I mean? Like but there is definitely like a this is like using use in a sense um at the component level
which I think is what what Rich is saying here.
Pushbased reactivity for a for async push pull for everything else. So
obviously there are trade-offs everywhere and I'm not telling J but async forces effect splitting down dam the turn isn't isn't true. Yeah and he's right about that. Um
well he's right he's right about forces effect splitting. DX downgrade is
effect splitting. DX downgrade is arguable. I could argue his approach is
arguable. I could argue his approach is a DX downgrade. Actually we're going to illustrate why it is. Um
but maybe not quite yet. We'll get to that.
um in a minute.
But my yeah I think I I think the general idea still holds right in a sense a compiler can solve this if you look for the awaits and hoist the
weights. It can't solve this at a
weights. It can't solve this at a signals level um is is is is my point.
Um, so does this mean we're doomed to mimic react? No, not at all. This is copying
react? No, not at all. This is copying react. It's acknowledging the same
react. It's acknowledging the same fundamental truth, right? Async forces
commit isolation. Async forces affect splitting. View has had the split in its
splitting. View has had the split in its watchers for years. These aren't
reactisms, you know, like they're invariants of any system that wants to preserve consistency in the presence of async, right? So like
async, right? So like in my opinion, this doesn't erase the advantages of signals so much, right?
like we are still surgical you know we don't rerender it's and it's only the effects that require the se separation right that's a difference thing like react because the
the render model they need the the depths everywhere they have a compiler to kind of compile it away so but like it's it's important
that I think we acknowledge this anyways Um, let's kind of finish out this article.
I I think there's some important truths.
I didn't really get into why async forces consistent snapshot, but that was what I was trying to talk about earlier when I was talking about like the A then B then C. Like you kind of have to you want your effects to all flush at the
same time to be consistent. So when you have all of these aspects where you you know it doesn't I guess it's wrong to say async forces effect splitting isn't
correct async forces knowing the dependencies ahead of effects running but it does force commit isolation effects ahead and async and a consistent
snapshot these things are true right so I thank I I thank you rich for help like clarifying a little bit that effect splitting isn't an inevitability of the
problem space it's an inevitability that comes with being colorless. Um, I think the more interesting argument where we can go from here is kind of showing that
you can't avoid going colorless to a certain degree. So, you might as well um
certain degree. So, you might as well um embrace it is is is essentially where where my next argument is going. But but
my the whole thing is I don't think this suddenly makes us react if that's what people are scared of. I I I we did I did get a lot of feedback about this, but it we should recognize like I've always
said, React gets a lot of things right for really good reasons. So like
we should we should we should never be too quick to to judge reacts design decisions. I said you can judge their
decisions. I said you can judge their implementation stuff to the till cows come home but almost everything they do from like an API service side from like
a conceptual side is pretty infallible from like a theoretical standpoint. Um,
so I mean, take it through this. I
thought this was a pretty pro-react article. Um, because I'm basically
article. Um, because I'm basically admitting that signals libraries can't shouldn't hide or pretend or lie anymore. You know, this is a big step.
anymore. You know, this is a big step.
Um, I I think this is important.
I I don't think this article really hit.
I think it's well written. I think it's to the point. I think it shows great examples, but I'm not I I I I don't think people understand yet just
how important this is and the conclusions from this are. Um
but I mean that's like most my stuff, right?
Reacts stale closure is arguably a feature ning because it gives you perfect consistent snapshot. Yes. And
That is sorry where was it? Here that's
what this did. Sorry not count because we we error on that or we've worn on that. This gives us our consistent
that. This gives us our consistent snapshot back again because you don't read the count here.
This this this this essentially is what returns gives us the same guarantee. I
actually I I like the way you're you're phrasing that here because that is that is the key here. This count is in the past. You know, I had this problem when
past. You know, I had this problem when I originally um set up uh if we actually go back full circle to the the original article that
I did on consistency here.
Looking at this three years later when I first started thinking about I was really struggling with this batch behavior thing because
like I really wanted to be consistent at this point when you're outside of batches solid worked like one two two like like the way that I showed but when you were inside batches it worked like
react so as soon as someone wrapped something in a batch suddenly state updates weren't visible and it meant that our co code worked in two different modes. So if you wrote a function that
modes. So if you wrote a function that did some stuff and then someone read it under batch, it'd be completely broken.
And that was the biggest bug. I I just had to choose a direction essentially. Like
it didn't matter that much I guess in hindsight which direction I chose. I
think there's importance for correctness and stuff obviously, but in a sync world given that the capabilities of signals, it actually didn't matter. I could go the React way and be consistent or I could go the Vue way and be consistent
enough. Um,
enough. Um, I just had to choose a direction because having two different modes in solid was a death sentence for for for doing stuff
in composability. The fact that batch
in composability. The fact that batch completely changed how your code worked uh really messed with people. And in
solid 1.0, we run all the back all the effects in a batch function. That was
intentional because we wanted you don't want like in the middle of the effects run to like start triggering other stuff. You want to let the effects run
stuff. You want to let the effects run all the way through and then do your thing. If you do them in the middle like
thing. If you do them in the middle like the next effect will see different state from the previous effect if people are setting signals. And a bunch of people
setting signals. And a bunch of people tried to argue that was okay and they won because that's where solid 1.0 ended up. They're like what's the worst case
up. They're like what's the worst case happen? We just cue another effect on
happen? We just cue another effect on the back and we just eventually get there. But it meant that effects could
there. But it meant that effects could kind of like run multiple times within a single cycle depending on the order that signals set. And I never never never
signals set. And I never never never liked that. But I kind of accepted it
liked that. But I kind of accepted it here. But because in the original batch
here. But because in the original batch behavior, if you called set count in an effect, you couldn't see it on the next line. You couldn't see it in the next
line. You couldn't see it in the next effect. You had to wait like React does
effect. You had to wait like React does until all the effects ran. So if you're in your event handlers, stuff happened immediately. But when you're in effect
immediately. But when you're in effect callbacks, they would be stay in the past. And I love that because you had a
past. And I love that because you had a consistent snapshot. Effects run
consistent snapshot. Effects run consistently. They run to finish.
consistently. They run to finish.
They're always like run once, everything was good. People in our community argued
was good. People in our community argued so strongly about it because they're used to things like mobx and they and and they're like, "Look, it'll be good enough. Reactivity will settle." And I'm
enough. Reactivity will settle." And I'm like, "Yeah, but it's like you get in weird ordering states and all this stuff." And and the only reason I
stuff." And and the only reason I eventually agreed to make this change in solid 1.5 was because of the two mode things being bad. I had to choose a side. And if I wasn't going to choose
side. And if I wasn't going to choose React side because everyone hated it, I'm I'm going to choose View's side, right? Which is what I did.
right? Which is what I did.
I always knew that that was not a great decision that React was consistent and solid was consistent. going to views approach was
consistent. going to views approach was a compromise but it was a reasonable compromise one that in a sync world we can live in
but in an async world given that we can't live in it um yeah like look what I wrote here so honestly this all sucks enough that I feel the need to be aware of batching behavior and with this awareness I'm
compelled to offer consistent default that feels the sest thing to do for Many of you this is probably unsurprising.
I'm the author of SolidJS. So why
wouldn't I say that? See Solid's eager updates work well with its rendering model and are completely implanted by optin batching. But the real relevation
optin batching. But the real relevation to me was just how much my opinion changed in the last couple years. When I
first saw this problem designing Marco 6, I was all in on view's batched reactivity being compiled syntax having explicit optin felt out of place and mutation not updating is awkward.
However, I definitely would have put spelt's approach as my least favorite and right. But now I'm not nearly as
and right. But now I'm not nearly as certain. Working in a solid which
certain. Working in a solid which embraces explicit syntax, I have all the tools at my disposal. If batching is often and if I'm going to give up consistency for intuitive behavior and support mutation, I want predictability at least. And that's felt too simple
at least. And that's felt too simple model makes a lot of sense. So I
actually couldn't like even then I was actually trying to argue for spelt's model just to as I said to avoid reacts model. So coming from match
batching I don't know if there's a lesson here. I can't fault anyone for
lesson here. I can't fault anyone for coming to different collisions. These
tricky problems are why I love this work so much.
Skeptics might point out solid has all the update models in it and they'd be kind of right. I don't know. Can't beat
them. Join them.
Yeah. I
when I look at this whole old article from 2022 in hindsight, I already knew what the answer was. I just didn't want to admit it to myself.
I I think we all kind of know what the answer is.
Okay. So, let's continue here.
No DX stand or anything. Let's let's
talk about the color versus colorless because I think I think this is important because uh let's continue this discussion a little bit.
So there's some potential insolveny. We
could get rid of split effects again and whole community has migrated the causes to them. No. No, that's not happening.
to them. No. No, that's not happening.
Not too late to change course. Yeah. I
love how you guys make it sound like it's actually a bad thing when like split effects are so beneficial when you consider all the aspects.
Yeah. And the create async API is not that because create async for us is is not is not where the read happens. It's
not where the block happens. It's okay.
Yeah. So let let's let's start let's just scound all this for a second. Let's
let's see if I can pull this out and get to somewhere where we want to be. Okay.
So what's the shape of async? There's
three points when when when you're dealing with async. The first point is where the like let's pretend we're dealing with
fetching but like the the the first point in the in the measure is like creation i.e. like do do the fetch,
creation i.e. like do do the fetch, right? The second point in async in a in
right? The second point in async in a in a JavaScript framework or like framework is a consumption point.
Framework absorbs the promise.
The third point is is read where the value is actually used. Okay,
these are three fundamental stages in in when we're dealing with async um in JavaScript frameworks.
And I I think it's it's important to look at it like this because even if you if you're if you're trying to like compare different solutions, you're going to find you're still working
around in this space.
So can we can I give some concrete examples of of these APIs perhaps? Right.
I I I already did with fetch. Right. So
what's this one like? Fetch
user ID. Right.
ID. Right.
Concrete example consumption.
Actually, you know what? Let's let let let's do this a different way. Let me
let me like go like okay how does this look like in react fetch user ID. Okay
user ID. Okay let's do prop fetch user
um props user ID. Okay sounds good. Two
use.
So this is promise right I'm going to call it P user right two is use P user
and three is um actually let's get narrower than That three is H1
user.name.
user.name.
Okay.
No, I the whole point of the stream is is that this is basically science.
Even when we disagree a bit on the implementation all that there there is a certain science to this.
You can like avoid the problem but it's like it's there. Once you discover it, you can't unsee it.
Okay. So
this is an example of of how this looks in React React 19 actually if we want to be really specific.
Let's do the same for spel five.
First one is the same. Spelt doesn't use a props object, right? Or is it like dollar sign props now? I I can't remember. Seems like everything is a
remember. Seems like everything is a dollar sign. Let's Let's pretend that's
dollar sign. Let's Let's pretend that's right. Don't get me wrong, you can
right. Don't get me wrong, you can combine these. I I it's just it's
combine these. I I it's just it's important that we um that we see the separation.
Okay.
And then the this is the same. Okay.
Why is Solid 2.0 different? You might be asking.
Technically, you can do this, but in Solid 2.0, it's a little bit different.
Uh, and I have to fix the I have to fix the the spelt version in a minute because this isn't reactive.
So, it's it's it's it's a little bit I'll get I'll get to why this is important in a second.
Solid 2.0 the design is that creation and consumption happen at the same place.
Sorry, creation happens here. Sorry. And
consumption and read happen in the same place.
Okay, which is a little bit different here. See, React doesn't care because
here. See, React doesn't care because React rrenners the components. So
there's actually a problem here with React because our first problem here is actually it's probably fine if the suspense is below. Yeah, let's pretend
the suspense is below. Let's pretend
this use is not in the same component.
Okay, just makes my life a lot easier.
React gets a new user ID, fetches a new user, passes the promise through to where the use is, which is where it actually uses it, and then somewhere below that actually uses the user.
Spelt, if we wanted to react to the user ID updating, um, we actually have to change this equation a little bit. We actually have to, if
you understand the problem, right?
Because props ID has to be reactive. So
we actually have to do this if you think about it. I mean we could we could defer
about it. I mean we could we could defer um this await as well. Like we can keep both of them perhaps but I think it's
more it's let let me change the structuring here. Let me zoom out a
structuring here. Let me zoom out a little bit and kind of get to where I'm trying to get to because if you want it to listen to this, it has to be part of a reactive
expression. So essentially what spelt
expression. So essentially what spelt does is it puts one and two here and then does three here. That that it's
a it's a very like these two things look the same but they're different. Does
does that does that make sense? You guys
following?
Technically speaking, I can still separate one and two with spelt if I um
separate them across like different boundaries. But like like what I could
boundaries. But like like what I could do is I could hard because the fetch is based on the reactive prop, right? So it needs to be
derived, but I don't need to await it yet. So I I I guess
yet. So I I I guess I guess it's possible.
I think it's possible in spelt for me to do change this sorry this one's user to
change this to p user equals dollar sign derived.
Yeah, maybe this is better. Is this
better?
and then await e user like you.
Yeah, I think I think this is probably the most accurate.
Yeah. Okay. Sorry.
Yeah, there we go.
The reason I didn't put the function is is because like under the hood this is a function too like in spelt it doesn't really matter like yeah but if it's reactive you have to
listen to it in a in a reactive scope I think like they might have some sugar syntax here that I don't have to wrap it in a derived so like I like but conceptually What I'm
trying to point out here is the await is the consumption point for them you're kind of tempted to just put the await here, but if you put the await
here, you fetch too high or you block too high the consumption point, right?
So like you kind of want to like I I could be wrong about the exact syntax but mechanically this is the consumption the same way uses the
consumption here and in solid the consumption is actually here like I I
this is this is very on certain way this makes these things similar like the mechanics The way we hold is similar, but this
makes things very uh different and it's important for me to point this out because we were talking about DX, right?
You could you could argue as I said that that felt and solid can have the same dx essentially like at when you squint at it by essentially moving this
to here.
Right?
This is what I was doing earlier.
Now if if if we're like sorry let's move my my thing a little bit this way. Now,
if we're squinting, now if we're squinting, these two are the same, right? If I put them on top of each other, like create memo, fetch something, derived, fetch something,
username, username, like these are the same.
And the same way I was saying that these are the same, right?
But there's a huge there's a huge uh consequence of this DXY. You want to do this in my opinion.
DXY. You want to do this in my opinion.
This is this is where you're tempted to do. You're just like, "Okay, just
do. You're just like, "Okay, just freaking await the thing to arrive. Get
my signal." This is this is what you want to do. But this
splitting them is actually better for performance. You
mechanically you want to do this. You
you want to be able to because in terms of where these points go is this can be used in multiple places, right? P user.
So let let's let's talk let's talk some truths here. Actually first let me edit
truths here. Actually first let me edit this one. saying like
this one. saying like phases of of async is is it phases, steps, stages,
phases of async in JS framework.
Okay.
All right. Cool. And then we we we have this thing. And then what I want to put
this thing. And then what I want to put on here is there's some other rules around this stuff here. I I I can implement it here. You want to do this
as high as possible.
Not as high as possible, but as as high as high as needed. What I mean by that is if you
as needed. What I mean by that is if you use a user in like 20 components and down a whole tree, you you don't want to duplicate this necessarily. So generally
what you're going to do I mean there's caching solutions and stuff but generally you're going to fetch as high you might put in a global store you might put in a store that's happening you know like like you know like not redux but you know what I mean you
sustan whatever you you might you're going to do this as high as needed up in the hierarchy it might even be global maybe even global I mean I don't need to put that note you get you get what I'm
what I'm getting at consumption you want this as low as possible You don't want to block unnecessarily.
You you you don't want to cause waterfalls.
You you you you want to be able to like have the the the framework do as much stuff independently
without getting blocked by async.
And then here well that that is so I mean we we can we can another way we can read this as low as possible is the reading
you concept conceptually when you're designing the system you want to be able to fetch as high as needed but consume where you read that that that's the fundamental thing
here because if if you consume too high you can already see you block right you you're like if you're I If you're like if you're sitting there in your component, I I don't need to pull out
the spel example, but with the run, I like I don't know how blocking that is or how eager it is, but like they had to structure their whole async around it.
If if this is why I don't like like async components in general, like like forget this for a second. If someone was like, I think my framework should have async
components. Async component,
components. Async component, async function component component one, right? Lovely. Okay,
look at my awesome framework. response
user equals await fetch user.
So simple to write like this font user posts equals await fetch user posts.
Lovely. And actually, you know, let's let's put some props in here. So let's
let's go props. user ID
props user ID. It does not get easier than this. Like look at the DX and then
than this. Like look at the DX and then I just like return you know a couple components.
This is lovely DX.
I can go user user.
See this just I'll close it.
because uh we'll pass user here. And you
you might be like, well, why did you even do it here? Well, the reason is because user uh posts component actually
needs both. So,
needs both. So, you know, we needed both the user I could I could have put the posts fetch
below, but as you'll see in a second, it actually doesn't make any difference.
Um, lovely.
Good DX.
Yeah. Yeah. Which is which is good. Um,
I I I that helps a bit at least on a shallow level. It depends
on how lazily the discovery works, but as I said, I I I don't think this actually changes the math all that much.
I it does exist earlier. Sorry, going
back to that example. But let me get let let me get to the the gist of the problem. I mean, actually, chat, if
problem. I mean, actually, chat, if you're still awake, what is wrong with my picture? Why is this wonderful DX
my picture? Why is this wonderful DX about the worst thing you could possibly do?
Yeah, waterfalls. Yeah, like
you're waiting for user to wait for user posts and they don't need the waterfall because they actually depend on the same thing. You don't need user to get user
thing. You don't need user to get user posts. And I and I'm not even like I I'm
posts. And I and I'm not even like I I'm actually preventing my ability to even show anything too. The waterfall is the the obvious one, but async component
makes it even worse because I I how I can't even show a fallback unless it's like above it like like
I I I I can't proceed further than this.
But waterfalls are great. It looks like RSC's. Yeah, about that.
RSC's. Yeah, about that.
Well, the smart person will come in and say like, well, solve the waterfall.
[ __ ] It's not hard, Brian. Seriously,
you can you can come up with this?
Not hard.
See, our perfect DX is saved.
Yeah, I'm completely joking. Um,
promise all doesn't solve your problem.
I mean, it is a a solution to the problem. Now, they're not waterfalling,
problem. Now, they're not waterfalling, but you still have a bigger problem.
It's still as slow as the slowest fetch.
Now it's it's quite possible that this doesn't matter but look user doesn't need user post. So why the hell should user wait for user posts?
Like promise all is not the solution.
When people start when people pull out promise all in their components like when that's their solution you know you're in the wrong model like you're doing the wrong thing. Promise all is
not the solution to this. Nor is like on promise settled or any like the interesting like split promise race or
what what? No. Um
what what? No. Um
just use caching. Yeah. I mean that helps with the rerender problem with React, but that or just use caching from the perspective of like never fetch
anything and have it all be cached.
What I'm trying to get out here is this is why you don't want to consume or block high. Now, it doesn't have to be a
block high. Now, it doesn't have to be a definitive block to be fair. Like,
there's ways around this scenario, right? Like, this is the definitive
right? Like, this is the definitive block. Um,
block. Um, let's not definitive block.
Right. Uh actually, let's just not definitive block now.
Uh or maybe I forget how this works. Do
I Where does the use go? Can I promise all with a use? I doesn't matter. Maybe
I'll get rid of the promise all.
Yeah, let's get rid of the promise all.
Okay.
Now I've invented my own keyword so I don't definitively block.
Right. This is better.
Definitely better.
I also have to have a caching system or some kind of concern with that built in now because like I I actually have a problem here because if if if my component reruns and it fetches user
again, I'm actually in trouble. So, uh,
using like this doesn't really work well in a rerun system. This is this is kind of what forced React's hand here. It's
like why React is. So, you you need to separate this React like says like you basically should separate the creation from consumption. You basically have to,
from consumption. You basically have to, which is good because you actually do want them. These actually should live in
want them. These actually should live in two different places.
The the challenge is because of shared state it's difficult to make this as low as possible once you start forking if you
want to derive it. I mean don't don't get me wrong like go ahead we can we we can make a component tree where like
we have you know we pass something all the way through like and like if you if we want to derive something we could use promise chains right you could you can
always like uh u not this one this one you know going back to our our lovely example here right we have to pull this out now Um,
so realistically this is our user section component. So we could go
like props dot user P user promise and then we can go somewhere up here.
We'll make another thing like let's call it app for now.
And I'm going to assume the app knows about the the the ID the ID here from its props. I mean it could be like
props. I mean it could be like I don't even know what to call this.
It's not even an app. It's like user page has the routing information and then we we
yeah we can do something like this and then make user pro use user promise.
I mean this isn't an actual real app. I
just and props dot user posts promise, right?
And then we can have user posts promise equals fetch user post. I should have just copied
user post. I should have just copied this before.
And then we could this g this gives us a good place to put our suspense boundary by the way.
Why not? And then
now we can uh make our user section um user promise
or and then we just go user promise equals and we can also do um user You know what? You know what the problem
with this is? We should actually make this user.
I'll continue with this direction for a second, but I I I I don't like this for a reason. I'll get I'll get to it in a
a reason. I'll get I'll get to it in a minute. We can make this user posts
minute. We can make this user posts promise.
The reason I don't like this is because as it turns out while this works um our user section
actually also works in a place where the data is available and doesn't actually need to be a promise, right? Because
like right now um our prop types are kind of like what are they? Um
are they? Um user promise is what uh promise of user let's say
and user posts promise is a promise of user
oay probably and then that will work. And actually,
while we're at this, let's let's fill out this example a little better. Let's
let's you know, let's user posts.
We don't actually we can we can move this use down here, right? Because you don't actually need
right? Because you don't actually need it up there. So, let's move it here. Um,
that's not is and we can go props dot user posts promise because we actually have to yeah so our prop type here is we
actually want um user user posts promise
which is a promise of promise of user sorry like that. This is
just I know there's a lot of plumbing here. I
just have to make sure that all my um prop types coming all the way down are the right ones because Oh, and it's also
takes a user which is not a promise.
It's just type user, right? Okay, cool.
Um I could make it actually you know what though? I could I could make it
though? I could I could make it um I mean for now we'll just do this and then
that that roughly looks right, right?
Yeah. Yeah. Yeah. We should we we should make it actually support both. So we
could make it user or a promise of user in case right and then this could be user and then our local user could I can you use on a
synchronous user probably they probably support that I don't know someone react will will know user will
know better so then we can make it user posts or array or promise of user post array.
And then we should do that down here too because now we we can go either way now.
Which if we go either way, we actually should probably bring this down here too and call the use here just in case, right? And then
because we might use user post somewhere else. So
else. So I just I really want to make sure we're capturing the DX here. Okay. Really
really want to make sure we're capturing the the awesome DX here. Um
yeah yeah. Okay. So yeah, this is cool because this supports both and we can read them both here and then this is fine. We started here,
we pass them here. So these are actually sorry type user. Yeah, that's good.
Okay. And then so this might be of type user post. So it can be a promise or not
user post. So it can be a promise or not a promise. And then
a promise. And then I mean there is I guess to be fair
now that we do this we can actually remove this right because now our user could
we don't need the block there because we can defer the blocking here. Um
right. And now Yeah, exactly.
I And then our props will be of type user.
I think I got it.
Okay, this is not bad.
I I would I would argue that at some point like we we this is still simple. There's
no conditional logic. There's no like like there's no like like if there's further conditional logic then the use might like we can get
the use pretty far down right if we want to. I mean it's not into the template
to. I mean it's not into the template level here. Although I think you can use
level here. Although I think you can use use in the template in React but we we'd have to worry about where our suspense boundaries are. Like I I think probably
boundaries are. Like I I think probably in this case we'd probably want because we have to either use a post here, we'd probably
want to wrap this one in a suspense boundary too to make it uh separate boundary.
Um right wrap that one in suspense boundary too.
Yeah, I I like that. Yeah, we we we can make maybe maybe promise is is nice.
Yeah, let's go through here.
You know where I'm going with this, Robbie?
No the maybe promise um is T or promise T.
I like that.
Maybe promise. Yeah,
nice.
All right. Okay. Cool. Um, and as I said, the the proper solution in spelt five
probably looks 90% the same as this.
All right. I'm missing the T.
Yeah, I mean to be fair, this level of prop drilling is not that bad. I I made it seem really painful because I sit there and and did all the promise. It's
not just a prop drilling. I also have to actively consume the use in the places as well. And I I mean
as well. And I I mean It would have been a fun exercise, I suppose, if we had started with this the system being synchronous and then added the promise to it and then basically went through and rewrote all the
components because the the difference with a colorless system is I could make the change right here and
not touch any of these other components and they'd all work.
Right.
It would be just as bad with synchronous. You're right. But if it was
synchronous. You're right. But if it was but the but changing from sync to async um is involves touching every single touch
point and then actually the use is actually and and the awaits are actually additional overhead over synchronous too.
Well, I mean, we we like the reason that I'm trying to show this off here is this is mechanically what you you you want this separation
here mechanically, but how tempted when you have a run component are you going to be just to do this? Because Picture
I did this in React syntax, but picture if you like you could picture if your component structure
wasn't like this. All these maybe promises weren't there. Right.
Right.
Right. So, I'm going to remove all the maybe promises for a minute. And you
didn't have any of these uses either.
Okay.
Okay.
Let's let's look at this a little bit more practically, right? And you're just starting here and you have this conceptually right?
And someone came in like okay well this is simple we have an async primitive for this. So all you have to do is do this
this. So all you have to do is do this user and then you go okay um I'm going to do uh derived
use I'm going to use like a solid like syntax here but I'm going to do drive await pet chooser or let's call it memo doesn't really
matter memo demo await fetch user.
Tada. Guess what?
This is like a reactive library. So we
don't need the like you know like this this sorry this should have been a wait or some cash out. It doesn't really matter. But so we we we know that we can
matter. But so we we we know that we can read this underneath here. So
technically I didn't need to change sorry user posts. I didn't need to change any of the components. I just
wrapped it in an async derived at the source and everything works and you're like sweet except there's a problem actually. Um
the suspense boundary doesn't go here.
Actually the the the suspense boundary goes out here now. So you're like, "Okay, whatever. I'm just going to
"Okay, whatever. I'm just going to I mean this is not hard return suspense.
I know this is a weird hybrid weird component system but I'm just like this is not real. This is not spelled.
This is not solid. This is just user page and we're going to pass in user ID
ID whatever doesn't matter.
So what did I manage to do here? I I I saw that I had some async and I was like sweet. All I have to do is create a
sweet. All I have to do is create a boundary around my async and then just async derive it and everything I have
automatically just works.
That's great. That's great DX.
Um I'm missing a comma somewhere. I don't
feel like trying to figure out where I'm missing that comma though. um
because because it's really easy. I can
just take my whole app that did a bunch of stuff, right? Um I probably didn't even have this suspense component down here either yet. No. And I I can
basically just add some async fetching up high where I was doing my fetching would do my fetching and then wrap it in a boundary and call it a day.
No.
I yeah, that's not my only point here.
My actual point is the DX that you want is solids DX, but that's not what you get.
This if you give people the ability to do this, they will do this because this is what you would do in solid, right?
The difference between this and solid is that this blocks here, not down at the leaves. The solution, it works,
leaves. The solution, it works, but it blocks at the wrong place. This
is great developer experience. This is
easy. Unlike React, you don't have to worry about the components rerunning, per se, like in whatever system this looks like. you know, you just make it
looks like. you know, you just make it an async memo or async derived value and you just wipe your hands clean it. The
rest of the system isn't aware of the asynchronicity. It all loads and it all
asynchronicity. It all loads and it all it all works.
This is the path of least resistance.
It's also the path of least performance.
people will gravitate towards doing exactly this.
I mean wouldn't you you just saw that what we had to do we had to go through update all the props add all the use or weights all the way down through go through every single component in this
tree and do this migration or we could just freaking fetch it at the top so that we get rid of our waterfalls.
Guess what? This this maybe this is a route loader, you know, like this is, you know, we already do this.
And then basically like look, there's no waterfalls here from a from a from a data fetching standpoint.
But I mean, from a UI standpoint, there are like if you were streaming, uh, you you you you're not getting what you want out of it.
This is you you you are naturally going to go this direction right like and this is what I'm getting at React the the confusion was people
wanted to put fetch user directly in use right you want to put await fetch user in derived Yes.
Now, the height isn't determined.
Sorry. Which feels even though the collective behind the scenes the API service feels correct.
Yes, we we basically turned our app into a promise all and you are Rob, you made my point. Yes,
this is exactly what I'm getting at.
Like you we have the natural tendency in our imperative thinking to turn things into promise all.
So React doesn't let you do this very easily because you need a caching solution components rerun. It's it's
it's kind like a saving grace that the system completely explodes if you try and do this. It's not convenient, but it's it's kind of like a saving grace.
But when you have a reactive system that's actually reactive and can update this stuff and can be fine grain, you you just almost you just gravitate towards doing it this way.
you know the right solution. You know
the right solution is pass the promise through all the components go through all the the types and check if the differences are and push them to the leaves. I I was arguing that people
leaves. I I was arguing that people probably wouldn't move it into event handlers. I good luck moving them into
handlers. I good luck moving them into component proctoring patterns or whatnot. And the funny thing is, okay,
whatnot. And the funny thing is, okay, you said yourself, how often are you moving from sync to async, but even think of the process of new development, what people are going to do while
they're developing new features. Maybe
it was just a user page and then maybe over time you added user sections and user and split it out and started these things got bigger and started adding
maybe nested fetching or just like they they started naturally expanding out under their own weight as tiers come in and increase.
You everyone could picture this.
you start here.
I mean, I don't even know how anyone can make the like I know there's no science to developer
experience, but like this seems very obvious to me.
So the whole question is what if you could write this and have it behave like what we did before with all the uses.
Actually behave even better. Pretend the
uses are in every single reactive expression.
Pretend the awaits are pushed down.
Pretend that in between here if you decide to make a full name like think about the what if somewhere in here you needed to do something like make a full name. you'd have to consume with the
name. you'd have to consume with the use. If you didn't want to consume with
use. If you didn't want to consume with the use, you'd have to go like promise then user name to full name. You'd have
to compose the promises if you didn't want to use high, right? Like I don't know why you'd want to do that in this case, but what if you want both of these to get user full name and you like it
was expensive calculation, not something you want to repeat in multiple places.
If you wanted to do it at this point in the tree where you're holding promises, you either have to block here now or you
need to actually like make promise changes on derivation.
Like you know what I mean? Like how do you deal with it? You're like, "Okay, well user then you u do uppercase." My my examples are dumb. But
uppercase." My my examples are dumb. But
my point is that you're not if you're not dealing with user you don't get to just go like that. I mean you you could make more you
that. I mean you you could make more you know you can make more async drives right but if those drives are blocking
like if if the pure presence of a weight causes the behavior like is the use how do you do like then you shouldn't be
awaiting you should be like if the compiler is looking for a wait and you don't want a weight behavior then you can't use a wait then you're probably going to use it then do you know what I mean
It's it was like what I was talking about earlier when I was trying to figure out how to to write the example uh in the Excal where I was like I I don't want to await here. I want to
await here. I I I want to pass the
await here. I I I want to pass the promise here. But what if I actually
promise here. But what if I actually have to drive something from the promise before the point that I want to await it and I want to await those in two different locations? Well, then you you
different locations? Well, then you you basically promise chain without using a wait right?
Well, it works like promise all in a system where the consumption or the blocking or like the like the trigger of saying like where is my suspense
boundary or whatever happens where the await is or where the use is. I I like The suspense has to be above that. You
know what I mean? Like that's why it's like promise all. Again,
in this phase, I probably would have started with either drilling down user ID or adding it to context.
Yeah, I mean adding the context is helps in a sense, but like what I'm getting at here is like it removes the proper linking but doesn't remove like completely remove the structural thing.
At some point like you could, you know, just make context for little clusters of like three or four components, but other points you're just like look this is a small tight area and it grows over time.
Maybe it was one component, right? like
uh sorry where I want to get back to my example here.
The truth is you probably when this was all the same page you probably did this not even derived used the what what I'm trying to get at here
is if if I made this example in solid 2.0 And I wanted to do the use the name here.
Me simply doing something like uh upper name or whatever upper name equals create memo. First of all,
there's no await here. If I just go user dot name to uppercase not blocking
this is not blocking it's blocking where upper name gets used somewhere else down in the DOM.
It's literally by design optimal.
This this is this is what I was trying to show in in in this in this thing. See
the difference here? One and two happen here solid. Two and three happen here.
here solid. Two and three happen here.
Right?
And by almost enforcing it this way where there is no separation between like one and two
can't go together by design. I've I like I like you want to separate one and two as far as you can in the hierarchy
but they don't go together by design.
These ones give you the you have the option to separate them. But that that option takes work.
Whereas in a colorless system, two and three are tied together by design. Which means that one and two
design. Which means that one and two can't go together by design. Which means
that like essentially you go in and you do the most straightforward thing and that is exactly the optimal solution. To
me that is DX.
I I know like people like arguing the DX case, but like I mean would you trade that for split effects for something like effects you wouldn't
even use? Hopefully like
even use? Hopefully like yeah waiting inside the component seems too restrictive to me. So wait of course the whole point of this is that components can manage their own data and more realistically inner would be responsible for creating it own promises but you can do it either way. We're not
it's yeah waiting inside component seems too restrictive to me. I just think of how people tend to model their data in one place. While we try to push them
one place. While we try to push them into some means of collocation and it makes sense to it isn't something I can make a hard constraint. So, and so composition has to flow.
I consider it much less constrictive since you get to choose where the waiting happens and it's nice explicit.
Yeah. But it
if a weight always means blocking, do you know what I mean? Like in a sense, have we we overloaded the term await? If
we make await mean use, have we actually constricted the language? Right? Like
have we actually made Have we actually specialized? Is
actually await now a subset of what it was originally instead of a superset?
Like are we actually limiting the language in a way that gives us less capability? Because await I mean await
capability? Because await I mean await always meant blocking in JavaScript don't get me wrong but in our case awaiting because we can wrap stuff in wrappers. Awaiting doesn't mean blocking
wrappers. Awaiting doesn't mean blocking we because we don't hoist it. Awaiting
just means it's awaiting a promise. It
doesn't mean blocking the render flow.
So if we if we equate a weight with with blocking the comp component or render flow, then we're basically actually producing something more restrictive than something that's like
more expansive.
The spice must flow.
Yeah, don't get me wrong. There there's
a couple trade-offs that come with come with colorless async. um mostly around initial load scenarios um which we've talked about before but generally and actually it mostly comes out with
interaction from outside the system.
That's a better way of of putting it because I I mean we've actually talked about it today. There's there's there's this
today. There's there's there's this physics that the trade-offs are what where we started the stream from this whole this physics but the thing is
these trade-offs should exist anyway. Do
do you know what I mean? like aspects of it.
The more concrete trade-offs is is like if it's colorless, you might not see it.
So like creating the affordances might not be as as obvious, which is something that like you you have to get in the pattern of. But the funny thing is when
pattern of. But the funny thing is when you're building UIs, you're already creating affordances. That's literally
creating affordances. That's literally what your job is, right? You're like
someone's going to be like, "Oh, I need a loading state here." it this this emerges from design rather than needing to emerge from technical programming constraints.
I as I said I have a very different view of what DX is from from I perhaps because I it's not about like how easy it is to type or like how many less
characters you you type. It's it's about aligning correctness or like not even correctness even optimal model with what you write.
I want when you write some code, I want it to be the most performant code. I
don't want that to be a question. I
don't want it to be like, oh, well, you can do this optimally by doing this. No,
it's like literally the only way you can write it is the best way to write it.
Like that's developer experience to me.
If it if if it meant even typing twice as many characters, that is still developer experience.
I mean, okay, I I technically speaking, I it's not in my graph. You can always box value this. We could pass the
promise around.
It's not easy because we absorb promises naturally here. This is one of the
naturally here. This is one of the debates I had when I was working on solid 2.0. The fact that create memo can
solid 2.0. The fact that create memo can just absorb it was like a debate because when it was create async it was easier to do it the other way cuz like it is possible to pull the fetch out or like
store it in a a memo kind like do this like what spelt is doing here um and then only like absorb it in the create async lower down but it's not even
absorbing it. I it felt really pointless
absorbing it. I it felt really pointless because the switch from memo of promise to create async of value had no meaning
in solid because it would did not represent actual consumption and it didn't or the read. So it's like we just like two-step creation for no particular
reason. Um, of course, as I said, the
reason. Um, of course, as I said, the promises can come from outside the system and you can absorb them into memos in multiple locations or whatever.
Like you you creation doesn't have to happen inside the memo per se. But um
the benefit of it happening in this kind of directive flow is like this is this is why I like modeling uh async is state graph because you there's a tie between
this and from props user ID. It goes all the way through the async. It's it's why React has changed their their model for async and why everyone's kind of flip like don't use affect the fetch because
that breaks the chain. So
technically yes if you want to do extra stuff for no reason.
Yes.
I don't know if I made this clear enough, but like the difference between one and two and three separate versus one and two, one and then two and three separate, but it it has profound impact
when you your temptation is to actually always write it this way anyways even in those colloccated cases. Sure, it won't make as big of an impact. You can be like this is not that big of a deal.
Like let's be fair, you you're blocking up X here. So technically speaking, you don't necessarily have to block propagation through graph. was really
cool with solids approach was that I think I've shown this demo the stack blitz demo uh several times now but let's let's pull it up here um again uh
the nested component example right nested fetching example uh and rich remade this with spelt to actually prove the point here naturally when spelt first five came out they couldn't do
this easily because they they had to like decouple a couple things because of the way they did it but like This was just automatic assault. The idea is each component like A renders B, B renders C,
and each one fetches its own thing in 3 seconds. So in theory, if this was at
seconds. So in theory, if this was at the consumption point, like if this was the await in in these examples, like if we were blocking here, then this whole
thing would take 9 seconds to load, not one, two, three, right? So like
the the whole thing is under a single loading boundary. So like it doesn't
loading boundary. So like it doesn't matter. We don't have the ripple down
matter. We don't have the ripple down effect. And because it fetch in parallel
effect. And because it fetch in parallel doesn't really matter. It's loading as it's coming in as slow as the slowest one in this case in terms of the boundary. But my my my point is that
boundary. But my my my point is that like this is just a natural outflowing of the thing. It doesn't require any special
thing. It doesn't require any special compiler consideration any kind of thing. It's literally just how the
thing. It's literally just how the system works because um this isn't the consumption point. The
consumption point is inside here. So we
can render B without being blocked by A.
And I said other there are other ways around solving this problem because the whole detection consumption only really matters probably on boundary locations.
But it does make as I've shown in previous demos boundaries really really permissive. We can just move them around
permissive. We can just move them around or whatever because like this aspect is you don't have to worry about where consumption happens. You
don't need to inject those uses.
It's just it just it's just a result of the system.
So making a point you should assume everything can be as additional loaders around everything. See, and and and the
around everything. See, and and and the the thing is this is the the result of why people are skeptical about the DX on this, right?
Because they're like, "Oh, well, now I have, you know, everything." The thing is you you get this naturally falls out of responsibility.
Would would your component give affordances to show async? If it
does, like if if you if you make a button and it h and it should have a spinner as part of its design, then you're responsible for show showing those affordances. You would have been
those affordances. You would have been doing that anyways.
If it doesn't, then that's not on you.
Yeah.
More like try the after loader. Yeah.
Component library. Do if I go look at Cobalt or look at one of these component libraries like you know pull it up are they providing loading affordances in their components?
If they are then this affects them. If
they're not then this doesn't affect them. Someone else should be blocking
them. Someone else should be blocking that. Like if if
that. Like if if like if if if it stops being it's not about handling
async, it's about UI affordances.
Think about it. If something's loading, you can't click on it.
It it's not necessarily the responsibility of the of the button in that case.
It's the responsibility of who whoever is loading the data.
or like like in terms of like grouping this. The
thing is once you get past that initial state, everything flows naturally anyways.
That's not that's not really a problem.
As long as you don't do stuff, you know, like read after writes in your events, you know, like that kind of stuff. Like
as long as you you structure stuff that follows the rules that we've been putting into the warnings, then you're fine. I I I think people worry about
fine. I I I think people worry about this way too much because they they want to poke a hole in it. Because you're
right, if you try, you can find examples that can poke a hole. Definitely. But
the the the real question is you're you you shouldn't be responsible for anything more than you already were responsible for.
How do I know the component supports async in such way with color, dude?
it. Okay.
You never used color in in Solid 1.0.
You never used color anyways. Did you
guys Did do Did Did your components accept promises in solid 1.0?
They they I I'm assuming they didn't like I'm I'm thinking that they might have done something like like if this isn't provided like if I don't have a
value here show a fall back and you would still do that. You're like
if I don't have a value here show a fall back. But you weren't passing promises
back. But you weren't passing promises around before. So why would that change
around before. So why would that change now?
I like I I think it I don't think the math has really changed here.
I I I I I I realize this is the thing where everyone gets like really hung up on this because they're like, "Oh, if anything could be async, then it could be async. And how do you do it?" Now
be async. And how do you do it?" Now
there are places where async reads could break like top level of a component then you I mean like it's kind of it's becomes kind of awkward because then you're rerendering the component you
know there's no thing but as I said if we if you follow some specific rules in terms of how to guard reads the same as our you know like as I said now we're a
little bit stricter on reads and warnings the rest of the system just falls out of Well, I mean people because it suggests that it can take an async value. I'm
kind of arguing that it Yeah, I'm kind of arguing that it doesn't it doesn't matter.
Yeah. Solid was always this way. Yeah.
Yeah. So, like
I I mean, don't get me wrong, this might be like famous last words kind of thing and there's going to be like big pie in the face moment, but my suspicion is those pie in the face moments are going
to be people trying to break the system rather than trying to actually um follow the patterns. And I think that the challenge here is that there are
some pattern differences. So like you do have to be a little stricter. Um and I'm hoping that the warnings and the setup
around the errors can make that happen.
Yeah. Value or null. Yes.
This the the one gap and this is it on the initial loading.
If you if you read a value in an event that is not used anywhere in the DOM, it is possible that an async error can be thrown.
So as in it because if it's read in the DOM it'll be caught by it'll be caught by uh loading boundary. So if it's above a
loading boundary. So if it's above a loading boundary or like not read in the DOM, it is there's there is a small window at the
beginning of of of on the very first initial load of the page that you could read something that throws and in the past that would be null. But since we were not allowing nullable values that
will throw. This is basically the only
will throw. This is basically the only gap in here.
And the the reason this gap is concerning is because it's not you have to hit it to to hit it. Like it like
it. Like it like you might not realize it until you know in theory someone went to production and they clicked the thing really fast um
during the initial page load um before the rest of the content loaded in.
Afterwards, anything above will be caught likely in a transition. But there
is this like there is this window this this window on initial load where it is possible if something isn't used.
To be fair, if you weren't null chucking checking the value in your event already, you would have this exact same problem,
right? If if it was user and you didn't
right? If if it was user and you didn't check if that user was null, you'd have you know can't access name of undefined.
So in a sense we can't guard you from that. What how would you have solved
that. What how would you have solved that in the null case?
you would have null checked, which nulling everywhere is is also not great.
It's one of the the stinks of of of representing async as like as being nullable. This is something that I talk
nullable. This is something that I talk about a bit in the article.
The better fix you would have done is disa disabled the button if if the value wasn't present.
Note the funny thing about disabling the button is it puts an attribute on a DOM element which puts it in the DOM which means it gets captured by the loading boundary.
Have you thought about making all signals within the scope of ownership of the component be registered with loading boundary?
You're blocking again. That's the spelt problem, right? The
problem, right? The how and or it's the dependency extraction problem. How am I supposed to
extraction problem. How am I supposed to how am I supposed to look at the event handler? What if that event handler gets
handler? What if that event handler gets passed in from a parent?
Yes. Yes. It's stale in flight.
Yeah, which is actually consistent. It's you
they they interact with what they're seeing.
Yeah. We Yeah, sure. You can we can create an explicit uh depths API for for uh for callbacks.
if you if you really wanted to.
I I don't think that's really foolproof though because I I think what where it gets really more interesting for a component author is that the parent not only
renders you and might be passing you async data. They're also the one
async data. They're also the one providing the like onclick call back. So
you and your local scope can't even see it. So that doesn't solve the problem.
it. So that doesn't solve the problem.
This this this doesn't really solve the problem. they at the parent scope could
problem. they at the parent scope could make that call. But if they at the parent scope are making that call, then they could also, you know,
pass a disabled to your button because you expose a ready not ready condition.
You your button has a disabled prop.
Like if you weren't handling the affordance anyways, you probably, you know, if you were handling it, you probably exposed a way of triggering it.
And if you weren't handling it, they they're responsible. Like nothing has
they're responsible. Like nothing has changed here.
TypeScript made null checking common.
And it's also nulling is one of the most painful thing to do with signals too, right? Like because the function calls
right? Like because the function calls are item potent. So
like it's kind of it's kind of awkward because every time you call it like you're like this is definitely a value and then the next call like it's like I don't know that. And it's like, no, I
just freaking we know it's a value.
I think if you click anywhere on the page before it's loaded, you deserve the error. I mean
error. I mean a a little a little I I I I think if you build well designed APIs this stuff will flow out of the
language of like the affordances you built into your AI UIs. I understand how this stuff can be missed but we're talking about like the edge of the
corner of the corner of the corner and mechanically speaking this enforces that you do the right thing. I I I I I'm
hoping this makes sense ourselves. I I I get the push back a bit, but like I really think we're on to something here. Like
here. Like this is this is this is I don't know.
This is really powerful stuff. We we've
kind of taken these physics, these these rules that are true and reimagined them through a kind of place where like we've actually pushed the
a lot of the harsh realities to places where you would expect to deal with them already anyways. And what we've done is kept the
anyways. And what we've done is kept the inside kept your graph kept your experience the way you would hopefully
expect to to to see it. Um, I I I it's it's why I still love this not this one, sorry. Why I still love this optimistic
sorry. Why I still love this optimistic data example because the difference between
the synchronous app here where you just show your to-dos, do all the stuff. There's no promises in here. I can't even see any async in
here. I can't even see any async in here. I just wrote a to-do app that
here. I just wrote a to-do app that works and I've managed to put all the actions, all the optimistic updates, all the
all the I thought I thought I fixed this type issue.
This an old Yeah, it's probably an older version. Doesn't matter. um
version. Doesn't matter. um
we pushed all that into the data layer essentially, right?
That's an option. We don't have to push it all in there. We can break it up, modulize it how we need, but the the key part is that
the the act of building the UI of describing what you want on the screen.
For me, that's always been, you know, the the uh maybe it's cuz I have a hard time with like CSS or whatever. Like this is the part that I've always wanted to be
able to model easier, you know? I mean,
the data modeling is straightforward, too. It's very powerful here. But I what
too. It's very powerful here. But I what I'm getting at is we've kind of isolated the async from the UI design.
Like if you need an affordance, it's not you're not asking about async.
You're not like, "Oh, what's the timing of this?" You're not you're not going,
of this?" You're not you're not going, "Oh, am I am I like is there this race condition?
Do I care when I set loading and don't set loading? Do I need to cancel it with
set loading? Do I need to cancel it with an abort signal?"
that that is not what you're doing. What
you're doing is you're like, "Okay, well, this is basically the same app as I had before, but now I need to consider if I oh, if I'm if something is pending,
then I should show it like this. If
there's an error, maybe I should give a retry button."
retry button." Um, okay. Or if it's pending, maybe I
Um, okay. Or if it's pending, maybe I should show this. Okay. Okay, cool. like
we've kind of isolated time from the equation. We haven't isolated the need
equation. We haven't isolated the need for establishing affordances for when things are available or not available.
We've actually strengthened that. We've
we've we've given it like like you ways to query like is it pending, is it not?
you know, we've given you ways to to look at um you know, time as flattened onto your UI plane, so to speak. We've
we've kind of collapsed that dimension in a in a in a you know, queryable way, but there's nothing nothing here is like
I'm worrying about race conditions.
It's literally like just I have some data. It's either errored or in flight
data. It's either errored or in flight or like pending or whatever. and just
show the thing that I want to show.
Everything else takes care of itself.
Dude, you want something? In the future, we're going to wonder how we ever lived without this. Yeah, we'll see. Maybe
without this. Yeah, we'll see. Maybe
it's Maybe I'm Maybe this is too late.
Maybe AI will just have do everything and no one will even care about this kind of stuff.
Okay. Well, there's a couple mechanical things I I spent longer on this than I expected to, but there there was a couple more mechanical things that I actually want on the show, but we're actually already at like 5 hours, which is kind of unfortunate
because I I I actually wanted to I mean, I don't have that much this week in JavaScript to be fair. I don't care about Versell versus Cloudfare. Honestly, most
versus Cloudfare. Honestly, most developer news just doesn't interest me even remotely these days. No one's
talking about actual stuff and approaches to building things. They're
all just saying like AI blah blah blah blah blah blah, you stole this from me, blah blah blah. Like
really just like drama.
I can't hear.
No, what I what I want to talk about a bit here is uh I I want to pull up the repo and I want to I want to I want to show an example here uh because I think
it'll help not solj because I I want to get into some more uh mechanics here and I think it will be
interesting to do. So these should be fixed now. Um, but
fixed now. Um, but I've showed this on stream, but I think this example that was made by uh uh
Missoulu uh is actually really relevant.
It's called the double like a lot of these were bugs that I fixed, but there is one of the ones that was actually not a bug and I was like this is not obvious and we should talk
about it. Um,
about it. Um, is it this one?
Oh, yeah. Beautiful.
All right, let's let's let's let's dig into this one for a second.
Uh or it's broken.
Lovely. Okay, that's fine. Um I I can demo this in a different place.
Yeah, let's let's demo this in a different place. What's the best way to
different place. What's the best way to demo this? Yeah. Okay.
demo this? Yeah. Okay.
Okay. Let me take my my multiply divide example because I I I want I want I think this is really important to understand about the model
and I I want to let's use my divide example. Yeah, let's do this.
example. Yeah, let's do this.
Okay, I think some people have seen this before. You click, you go
before. You click, you go and you can click it multiple times. It only
settles once. These are all separate async reads, but they all get entangled and you get the smooth thing. And the
the key for why this example is so cool is I literally started an example with no promise here and it just is a bunch of memos and then I just decide to make
the it async and I essentially I don't have to worry about null checks like a is actually an accessor number so
on n is always going to be held where I want it to in the past arguably here I'm actually purposely tearing so like 12 gets ahead of 12 because I use latest
end. But let let's do this. Let's remove
end. But let let's do this. Let's remove
the latest for a second. And I want to show show you all something.
See, if I if I if I if I do that, it's not going to move. And this is the default behavior. It'll stay on the
default behavior. It'll stay on the number until it's consistent. Now what
what Mazulu did in their example was they move the button outside of the loading boundary.
And I I think this is important to understand because so far this is the same and I click it like 10 times. But one thing that I'm
doing here, if you've noticed, is I'm actually passing a setter function. So
I'm I'm incrementing it by n plus one, which means it's actually getting the latest value. Incidentally, that's just
latest value. Incidentally, that's just how we work. If I changed n to actually read things, so it reads the stale value, right? So it's actually the
value, right? So it's actually the reactor read. It's not like applying a
reactor read. It's not like applying a callback function on its previous value.
You'll see if I click it multiple times, it can only go once. So
I I click it three times, but it only goes up once. This makes sense because it sees the same stale value and it can only go one. So if it's on two, it's only going to see three. And it tries to click it again, it's going to see three,
it's going to see three. This this makes sense, right? You you if this was latest
sense, right? You you if this was latest end, then then it would be the same as the callback form. But essentially
now if I make this this timeout longer let's say like not random. If I actually make it actual 500 milliseconds
for each one.
Let's make it even longer. Make it a th00and 1 second.
You see as I'm clicking here, it stays on two even though I click it like a bunch of times, right? But the the what and this should make sense to people,
right? Okay,
right? Okay, we're loading and then we show all the state consistently. Like obviously it's
state consistently. Like obviously it's a nice affordance to get latest but but the interesting question is what do you think happens if I click the
button while the page is loading like a bunch of times? Does any anyone want to guess what happens in this example?
Should it behave any differently?
So here we know.
But my question is while it's loading right now and I click it a bunch of times, what do you think is going to happen?
Chad, I am going to wait for you guys to respond because I don't want to ruin it.
It'll Okay, Robbie says it'll go up faster. Why will it go up faster,
faster. Why will it go up faster, Robbie?
It will go up and I know. Yeah. So, is
it the people who know the answer are the only ones responding? That's fair
enough.
It's not about replaying events. The
page is h This is client side hydrated or whatever. Everything will crash.
or whatever. Everything will crash.
No. Are you guys ready for me to do it?
I'll give it a moment longer to to guess if you want, but let's let's let's do it.
All right. Last chance.
All right. I'll do it now.
It went up to 11. In fact, as I kept on clicking here, I could actually hold off the the loading going away. Cut to 30.
Why is it like this?
It It updates right away. It doesn't
hold. See, here we're holding and then it updates.
Isn't that weird?
There's There There's actually a really good explanation for this, but I because AI saves consistent. Yeah,
there's nothing to contradict it. The
back end will handle it. No, it's
it so so secret little goblins counts the number of clicks during hydration. No,
this isn't hydration. This is completely client side. Um
client side. Um the app is fully hydrated by the time like the the like there's no hydration.
the the the reason that this happens is because there's nothing to contradict it.
We only need to show we only need to hold the the the count because there's something to contradict it because we need to be able to show that 10 divided
by two equals 5.
N itself is not async. it gets held up because you can't update the number while showing a otherwise you'll get
tearing but when the it's loading like there's nothing to tear essentially so it can just process it immediately
right there there's there's no there's no dot dot dot on this either when I'm clicking on it it's not pending while while I'm clicking on now it's pending but there's no there's no pending while I'm clicking on it right
and it defers loading because it does load it a number of times. It cancels
the previous ones. You know, we have built-in promise cancellation essentially but but um
that's basically the gist of it. Now,
obviously, it's weird that I click this five times and it only goes up once. And
here, I click it like 10 times and it goes up faster. So, arguably the behavior you want isn't n plus one. It's
it's latest n or you know, simply this.
As soon as I change it back to this, then you get the five right away. And
when I click here, you know, you get the six right away. Like, so now it's consistent. And when I click it a bunch
consistent. And when I click it a bunch of times, I still get the the number of clicks aren't lost. And if I go back to this being latest,
so you want to show the updates right away. There's no inconsistency between
away. There's no inconsistency between this and this because that's the importance you want to do.
That feels much smoother. obviously,
but I did actually have to make some considerations here, right? Cuz the
default, but like what I'm getting at is I made this decision based on like like a local
decision. I decided that I my affordance
decision. I decided that I my affordance is like I could with the button increasing faster, I could choose not to show the is pending. Like my affordance could be just the fact that this
updates. That could be my decision.
updates. That could be my decision.
But what I'm getting at here is that like it is important to understand that loading boundary is a boundary that
guards if the async read from ABC here doesn't escape the loading boundary on initial load which means that
N is not pending or like and can update right away.
Yeah, this makes sense from a consistent way of verging on being counterintuitive. Yeah, and to be fair,
counterintuitive. Yeah, and to be fair, this is how React works too.
Um I think this probably spelt works too, I imagine too.
I'm not sure. Yeah, I'm I imagine.
I mean, I h I've already been doing demos that were closer like the to-do MVC type stuff where you're managing a list. This
demo is is not going to I I don't think real world case is going to actually help explain this demo
anymore. This like this is another one
anymore. This like this is another one of those ones where what are you doing jamming the button while the page is loading?
if you know what I mean.
It's it I I this is the this is the f the funniest I have to test and make small examples to show edge cases because in the real world you
just don't tend to hit like you will on occasion hit these edge cases which is why we have to account for them but like we're not setting ourselves up to try and hit the edge cases you know what I
mean I I have to account for them so that like when your app scales when you get to a point or you hit these things that they're handled properly. And this
is why I'm very thankful to the beta testers because the type of people who hang around the solid discord are exactly the type of people who want to break everything and poke holes in everything. Um they want to create crazy
everything. Um they want to create crazy demos so that really show off like the capabilities and they also um
want to show their cleverness. So like I get great great examples of people trying to break stuff. So
break stuff. So yeah, I mean what what what's what's a what's a real example? I just said something like
example? I just said something like to-do MVC with affordances is very similar to like like a Trello board conceptually. Um which could be a real
conceptually. Um which could be a real use case. A lot of times the funny thing
use case. A lot of times the funny thing is these little cases that we're focusing so hard on in making these demos are like so on the edge of the
thing. What I the real win is just being
thing. What I the real win is just being able to write the code like normal and not have to worry about these edge cases.
Uh like let let me see uh give me a second here. I'm going to I'm going to
second here. I'm going to I'm going to open Discord in my other window for a second and see if I can pull out an some examples that the community have been making using Solid 2.0. I think uh I
think Gabriel's still here.
I think we just everything stays the same as mind-blowing. Yeah, the the two NBC examples is really great. What I
wanted to actually grab was that Gab Gabrielle had an example uh that was like a chat app that was built on on
this and I think it's in a working state. I I need to see if I can find it.
state. I I need to see if I can find it.
Is it the sync engine chat?
Yeah, let me see.
Yeah, you guys can't see it. Yeah,
sorry.
It's all good.
Hopefully, this demo is working. I might
have grabbed a bugged version of it.
I love I I I love I love this example. What what's this example?
example. What what's this example?
Format temp world zone. So what are we doing here?
Chat app create projection which is an async iterator querying messages push store create optimistic store.
I don't I I don't have enough context probably to to to look at the implementation completely in here. Um
chat pane. What's in here? Badge, scroll
behavior, message list, message bubble.
I just love that. Like most of these look like they're just dumb dumb UI components. Do you know what I mean?
components. Do you know what I mean?
like they're just doing stuff like synchronous. Nothing too fancy. Props
synchronous. Nothing too fancy. Props
children. There's a wrapper. Yeah. Okay.
So, almost all the logic this is some special scroll behavior.
Almost all the special logic here is is a for loop which is keyed false. So,
it's by index. Wonder if repeat would be good there. It doesn't really matter. Um
good there. It doesn't really matter. Um
this probably this might not even be the latest version all the all the logic is basically the chat app component right so it's basically we create a projection which
is an async iterator and then it just gets the messages and yields off and then the optimistic store mechanism
messages see how does that where are we setting our optimistic messages is we have an action that sends the messages, sets them optimistically,
pushes them on an array and then it waits on the API to send the messages and then it looks for the message ID.
Yeah, I get it. So basically when it gets an act from the server like it gets the message back it knows that it's done its action and I hear that some things like convex automatically like hold your
request till they know you've received it on the client. But this this is cool.
So this this is basically a fully streaming chat example that's just using async iterator protocol. Like it's fun like there's no imports here, right?
like this is literally like just built purely using our primitives um to basically have two chat apps. They work
both ways. So I go hello Yeah.
What's up?
Yeah, I mean I did a bunch of fixes since last time.
So now we can actually have the streaming async iterators work and they they have multiple modes which is really cool. Um for hydration you can you can
cool. Um for hydration you can you can either choose to do the default where it just streams from the server all the way through the hydration or you can do hybrid where it streams the first promise from the server and then picks
it up from the client. I mean I actually got a demo I could probably show off here to that effect.
Why is this still here? Um,
the weird part is did I close one of my windows? Feel like I accidentally closed
windows? Feel like I accidentally closed like where? Yeah.
like where? Yeah.
Oh, it's cuz it's full screen. It's
fine. Um,
uh, I'll just copy paste this into chat in case if people want to check it out.
I don't know how presentable it is. I
know we've been working in bug fixing throughout this whole demo. So, you
know, but what I wanted to actually look at was um uh quickly look at a couple of like silly
little demos. Incremental SSR
little demos. Incremental SSR incremental iterators.
I I made this example on stream last time and it didn't work. Remember? um
where it it pushes um into a list and this is actually kind of a a cool API just on a side because what
I did was the projection is a stream right that pushes values on. So, it's
actually incrementally. It's not sending the whole list over the wire each time.
It's literally just adding an item to the end from the server um at once a second and then the client just appends the the item on the end. So, we're not actually sending the full list. We're
actually doing incremental pushes from the server during initial SSR. There's no additional requests or anything. If
and and what I did to actually prove this fact is I put is server. See,
Stacklitz has this funny uh it's not I guess not funny, but Stacklitz uh will show you server and client console logs in the console. That's how they forward them through. So, I actually had to like
them through. So, I actually had to like prove that see chunk true, it's actually running on the server these these chunks coming in. Um and what we're actually
coming in. Um and what we're actually doing um if I look at the uh maybe I can put this in a different tab.
Sometimes I have problems with stack blitz from security standpoint.
Um, oh, it looks like my computer is low on battery even though it's charging. It's
charging slowly.
Cursor is killing it. Okay, let's let's kill cursor for a second. Sorry. Maybe
that'll help it recover. I was trying to build a signals library from scratch using solids tests. I wanted to actually see if
if I could uh do the V-neck thing against myself. Um, we can worry about
against myself. Um, we can worry about that on a on a different stream.
So, um hopefully that that'll we can our computer could start charting. I'm only
at 7% left, so that's kind of bad. Let's
quit.
Why is Chrome being weird?
Oh, there it is. Okay.
Okay.
So, it's still telling me that Chris is using a lot of I think cursor is done now. Do we Is it still that sitting there in the
background? Okay. Anyways, uh
background? Okay. Anyways, uh
let's bring this back cuz Okay. So, but
one thing that we can do that's kind of cool here is instead of doing this, we can do we can change the SSR source to be client. Let's hope this works in this
be client. Let's hope this works in this version. But if I change it to be client
version. But if I change it to be client now, same in demo. And what you're going to see is false. Now it's the client side making the connection. There is one difference though. There's no loading
difference though. There's no loading boundary because it never suspended. It
literally just picked it up on the client and made the request on the client. So I mean this is good for like
client. So I mean this is good for like tapping into async local storage or so like like async storage like local storage type stuff, but it's probably
not like typical for this use case. But
the the real fun one is hybrid because with hybrid if this works is it should be true for the first one and then it should be false. Okay. And I
have a hydration error in this example.
Hopefully I've fixed that now. But see
how it said true and then false uh and then picks up the stream. So it actually serializes the first value from the server and then continues the subscription from the client. Um, and
this is all just a matter of of choosing what your your sources for your your data fetching.
Um, and make font bigger. Uh,
the font's actually already kind of blown up. What do we add here? 125%.
blown up. What do we add here? 125%.
Usually I have a hard time reading my screen if I get any bigger than this because the code doesn't fit.
Um anyway, just kind of showing some of the the stuff that we've been doing with uh the async boundary
stuff. Okay, so um there is
stuff. Okay, so um there is how was I skipping? That was a fun part because you have to understand it's doing incremental updates. So I actually had to I had to eat because if it was yielding
a value that would be easy but if you look at it's not actually yielding a value it's actually mutating it. So I
actually have to eat the uh the the the proxy has to actually eat the updates on the first iteration.
So it takes the server serialized state and then replays the first one. But then
like basically when you push or do any mutation, it just basically eats it. Um
it it it it gives you an object that is mutable and you can read and is self- refferencing and all that kind of stuff, but it doesn't actually apply it to the
underlying draft.
It doesn't. I mean, there's not much you can do with the async uh iterators.
There's not much in their protocol.
You're you're going to error out and you're going to get an error boundary and you're going to do what you need to do.
Yes, we we can't skip it. Yeah. So,
technically, yeah. So if there's a log next to push, you'd still see the first value repeat.
Yes. Yes. Exactly. Yeah. There's we
can't stop the first thing from happening. But this was a good example
happening. But this was a good example because it was a push. Um if it was a yield, this would be really easy, right?
You just skip the results. But because
it's mutable, um yes, it does run on the client, but it's kind of like the way create async runs on the client. uh like
or not create async but like for promises we also run in the client and we kind of like dummy out the promise so that we don't refetch because we have to collect the dependencies. So it's a
similar trick basically that during hydration the the we sort of we we have to run the code but then we kind of patch it so it doesn't do the the the
thing we don't want it to do. In the
case of async iterators, I can't promise that it's not going to run the promise like normal data fetching, but I I I
think but generally that's that's the kind of tact I've taken here.
That's so funny. It's still showing cursor using significant energy even though cursor is not opened.
Anyway, it's fine.
Okay. uh what I wanted to talk about next related to this stuff. Um yeah, so we I think the main one there was is is kind of what I was showing before which
was like this idea that if you have a if you have a graph, right, and you have uh let's make it screen,
write something on it. So here's your like signal, right?
And then let's make this red.
And then we have something like async derived from it.
Uh how does this show this? Yeah.
white.
And then let's put blue, which will be our effect.
Like if you have this kind of chain where the where the loading boundary happens the the I'm trying like I'm trying to think of the best way to show this but
essentially we don't cons let me delete we don't consider things having
I'm going to I'm going to draw something up here or use a word. I'm going to write transition. Okay. And transition
write transition. Okay. And transition
is going to be brown. I guess it's going to be like a have any more shapes of a diamond.
Yeah. I don't know.
Bring to front.
I don't know if my my diagrams here are going to be very useful here, but conceptually
the way this flows down is when we when we hit our async update or async signal at that point until we hit something async there, no
transition exists. We just kind of
transition exists. We just kind of collect the nodes in in in a global queue. And then when we hit something
queue. And then when we hit something async, we we go, okay, create a transition dot dot dot this. Let's make this a
little bit get you. We're like, create a transition. But the transition doesn't
transition. But the transition doesn't do anything concrete.
And then when we finally hit our render effect and it holds at that point it goes it it
starts bubbling up its owner graph. So
this is a dependency graph here. Okay.
So um dependency graph is white. Let's say
then the it it's it looks up um a different graph. It looks up its owner.
different graph. It looks up its owner.
So let's go here.
Let's use blue. So, it looks it looks up for its owner. And in in our case here, like these might be the same owner. They
might be a different owner. Uh we're
going to make this trans these can be where these owners don't matter, but it walks up its ownership
graph and it goes, "Hey, I'm async."
And if if nothing gets in its way, it'll get to the transition and the transition will go like okay what like why did you error? You errored
because of async. We actually
communicate the node along here. So then
this async node becomes registered with the transition and we know how to to wait for it. However, if
if on the way up it hits a wall and by wall I mean like loading boundary.
That communication never gets up here and this loading boundary goes haha. I
will hold on to this async. Um,
yeah. So, let's get loading. You'll be
there. You Yeah, sorry. The green arrow is going to be. So, this then goes to here in D. Yeah, this my arrow drawing is
in D. Yeah, this my arrow drawing is terrible because like essentially if if it hits
the wall here instead this goes to here and it never makes it to here.
And that that that's like mechanically the core of the of the of the transition mechanism. Um,
mechanism. Um, and the key part is loading um, only happens initially generally. I
actually added a new prop that if you want to trigger loading to to start again from above, you can. The biggest
problem with with with with suspenses, if you have some random async down below, it'll just keep on unmounting on you. But, um, one thing that I that
you. But, um, one thing that I that occurred to me is that sometimes you actually might want to isolate the change. Yeah,
that's that's actually what I wanted to do. Do we have the divide example
do. Do we have the divide example anymore? Um,
anymore? Um, I think I undid all the changes in it.
Let me go back to it.
So, do we Let's undo all the changes in here.
Whatever. Save. Let's go back in the divide example we're doing earlier where we were where we were um
you know locking it up. So let me let me show let me see if I can do this.
And now it should lock up. Yeah, this
sorry this older demo doesn't have HMR and then Oh, but then I'd have to update it to the latest solid, wouldn't I? This is
like experimental 16. Uh, let's actually let's fork it.
Um, yeah, let's fork and then let's move to beta beta 4.
Beta 4.
Beta 4.
Beta 4.
It's funny because now that I have beat plugin, this one seems like a little bit outdated. Um, but okay, let's go here.
outdated. Um, but okay, let's go here.
Let's make this n.
Okay, good, good, good. Um,
if we wanted to, we could say on N and it No, I hadn't tried this yet, so I was I was
hopeful that this would do what I wanted, but maybe maybe this is not working yet. Okay,
lovely. Not working yet. Okay, that's
fine. The idea is that if you said on N, it means that whenever N changes, we reset the loading boundary so it can go loading again. What's cool about this is
loading again. What's cool about this is you can control it from above. So you
can make the decision like let's say you want to kind of key it by page or something. And that way you can isolate
something. And that way you can isolate these changes that happen above and not wait on the stuff below. So you can keep the stuff faster that way. Um but the the the key is the the important part
would be that um random async happening below unless it was triggered by this change of end wouldn't cause the loading to reset. Basically other async is
to reset. Basically other async is doesn't matter. This is you controlling
doesn't matter. This is you controlling it from above. Um of course demo's not working but what else is new? Um, I'll
I'll look into that. But yeah,
I'm guessing a lot of the changes to signals must make them very open to sync engine. Yes. Yes. Like I I saw sync
engine. Yes. Yes. Like I I saw sync engines and I'm like this is fine grained over the network.
Solid is fine grained on the thing. This
is a this is a this is the perfect pairing. If you care about sync engines,
pairing. If you care about sync engines, you should be using solid like no doubt.
So, I wanted to uh a lot of this thinking is to make that seamless essentially.
Errors in green. Yeah, I I don't know.
Whatever.
It's fine. I'm I need to work on my way of explaining the model better, but essentially boundaries have the ability to stand in between. Transitions are
global. Boundaries can stand in the way.
Boundaries are resettable. But generally
they only run once unless as the default behavior which is where you kind of want to be. Um just because you don't want
to be. Um just because you don't want things jumping out on you out of nowhere. Um
nowhere. Um and optimistic updates are just another layer on top of the trans transition.
But I I don't think I'll get into a good graph of drawing them today. I thought
maybe I would like explain how optimistic updates optimistic lanes layer on. But I if I can't visually show
layer on. But I if I can't visually show this properly, I'm I'm pretty hopeless to visually show that. Let's move on.
Okay. Um I think I think it's just time to wrap up with a little bit of uh this week in JavaScript. Um chat's getting quiet. I I can tell it's the end of the
quiet. I I can tell it's the end of the day for all you all. Give me give me give me a second as I split modes.
All right.
I have so much open stuff right here right now.
Just closing all the crap. All the crap.
All right. So, what do we got? I'm
actually like seeing if I actually have anything. I feel like I literally
anything. I feel like I literally released the article and Okay. Yeah. Is that
Okay. Yeah. Is that
And sorry, two seconds chat. I'm just
getting Everything opened up.
Okay.
All right. Cool. Cool. Cool. Um, let's
go back to here.
Let's go back to here.
Beautiful.
And then let's go back to here.
Yeah. Okay. Yeah, I don't have much this week, but that's good.
All right. Um,
let's share my screen now.
talk about this week in JavaScript which honestly isn't going to be that this week in JavaScript oriented I don't think um general because I honestly I mean I
highlighted that story with multi but I don't even know want to talk about it that much okay so yeah I'm going to start with solid stuff
it's easier saw this, thought it was really cool.
People always ask about solid on native.
The native script guys are very on on the you know like they're very quick to to uh kind of jump on these things and make
sure that they happen. uh tanstack
router solid with vit which is a very cool story for us obviously because tanstack router is very cool given it's typescript routing and here you go this this probably could
be a really awesome way to develop on mobile um using solid uh then there's the my hackmd what's this
one here managed to get v uh solid js and spacetime db working the instant sync is so fun feels like convex Yeah, I like Convex a lot. I I saw their
uh Sorry, this doesn't go here. I saw I saw I saw a demo of it a ages ago and I've always been really impressed with it. It
just it's the challenge has been people like as much as uh as much as like uh companies have a certain reality they
have to deal with actually I think Jamie actually had a tweet that I saw uh yeah because it's a pity the comics enter still for
react blah blah blah Uh, my favorite is Solid. I'd argue it's better designed
Solid. I'd argue it's better designed engineer than anything I've seen, but at last, responsively to focus on support our customers use. I'd love to be able to invest more in attention in other cool frames like Solder Solid. So, yeah,
big fan of Convex, big fan of Jamie.
I would love to see better solid integration, but we got to prioritize. I
think I think I think with 2.0 coming out and the push there, this will this thing will naturally kind of come out come come out of it. Um, but um, big
shout out to Jamie um, and comx just as an aside.
Um, sorry, I know that had nothing to do with anything. I just
with anything. I just um, what was I looking at? Yeah,
the the key point is you saw in the chat app, we're getting to a point where build your own sync engine might be a thing and it could even start from like not even a sync engine. the kind of
optimistic UI that we're building in solid irregardless of the uh transport layer essentially doesn't literally matter how the data gets thing can give
the sync engine feel without even having a sync engine. So like um yeah I mean we're kind of we're
definitely on our way there.
Um yeah. Okay. So that's it other than that
yeah. Okay. So that's it other than that other story. Um,
other story. Um, let me go here. What do we got? Yeah.
Uh, yeah. A lot part of advocating for solid
yeah. A lot part of advocating for solid is having to defend React first. A lot
of the allowed us to anti-react takes fix it on ergonomics or vibes, not the actual architectural issues. You can't
explain solids advantages until you clear that fog.
This was a precursor to this article. I
knew I was I was writing this article when I when I when I when I wrote that tweet. I was just like, it became really
tweet. I was just like, it became really obvious to me. I was like, I'm I'm going to have to write a post where I basically point out why React was right
and defend it. At the same time, show where the shortcomings still are, but be very clear that, you know, the things that people like to blame React for aren't the right things. It just it's
it's it's tiring after a while when people are arguing over stuff like syntax or like how many characters you have to type or whatever. It's just like I there was an interesting actually uh I
saw on Reddit where someone was showed that like the best the least tokens used framework was Marco um and then like spelt was like third and then I and I
looked at the list for a second. I was
like this is like syntax compactness.
It's not it's not actually probably saying how easy it is or hard it is to actually um create the examples. It
looks like someone just took like party component partyjs or whatever where you have all the examples and they just counted the number of characters of it.
It doesn't actually suggest if AI has a harder time or it requires more thinking or whatever. It's basically like which
or whatever. It's basically like which framework has the least syntax and as everyone knows Marco is the most compact JS framework, right? It it you type the least in that one compared to any other
framework even spelt. So like of course it won. So,
it won. So, um, yeah, it's interesting. We're going to, we
it's interesting. We're going to, we don't know what metrics really hold up, but I I I definitely feel like we don't have the right measurements yet. Um,
uh, let's talk about my actual AI article, the one that was actually written by AI for a moment here because I don't think I've talked about it too
much. Uh, it was after my last stream.
much. Uh, it was after my last stream.
I I basically asked AI why um Solid was a good choice. For all those guys earlier who were like, "Oh, what about Remix 3?" This is this is my response to you. I guess I could have
brought this up earlier, but this is what AI told me. You guys can decide if it's relevant or not, but software is entering a new epoch. The area of writing code is giving way to the air of systematic orchestration. As AI agents
systematic orchestration. As AI agents pour unbounded amounts of imperative logic into our repositories, the limiting factor is no longer human output is complexity absorption. In a
world where machines can generate infinite working code, the frameworks you choose become only your defense against temporal drift, race conditions, and slow gravational pull towards technological entropic collapse. The
question is no longer how do we write code, it's how do we ensure that code, human or AI remains correct over time.
Solu answered this question with a single principle. Determinism must be
single principle. Determinism must be structural, not stylistic. I mean, it's a good summary of what I was covering on the stream in terms of the shape of the APIs. The ending of the loading boolean
APIs. The ending of the loading boolean error. This is kind of like direct
error. This is kind of like direct response to like the remix thinking. As
I said to be fair, I didn't write this.
AI wrote this. This is completely AI generated.
Most frameworks still treat async as an afterthought. A promise resolves
afterthought. A promise resolves somewhere, a boolean flip somewhere, and the UI is expected to stay in sync. This
is the root cause of modern UI instability, a temporal disynchronization zone where data and interface drift apart. This model was fragile when humans wrote all the code.
It is catastrophic when AI wrote most of it. Solitude replaces the entire class
it. Solitude replaces the entire class of problems with a new primitive. the
temporuple. It's a funny name. What all
they mean is that we have like um we have latest and value or we have optimistic and value like we basically view every all state as now and the
future. They they he they chose to call
future. They they he they chose to call it a tpple. It's not a literal tpple.
It's just the idea that you that you can declaratively show something through.
Let's see let's see what their explanation. Every reactive value
explanation. Every reactive value carries both the now and a future. Async
is no longer a side effect. As part of the value's identity, this eliminates the need for ad hoc loading flags, effect cleanup heristics, and the endless patchwork of fixes that accumulate around async code. The
runtime owns the timeline so the UI cannot fall out of sync with reality.
Determinism by construction. The gap
between actions resolutions where bugs live. Traditional frameworks ask
live. Traditional frameworks ask developers or AI agents to manually bridge that gap with effects, guards, and cleanup logic. This is not engineering, it's gambling. Solitude
removes this gap entirely by elevating the future as a first class part of the signal. The runtime constructs a
signal. The runtime constructs a timeline projection architecture. The UI
becomes a pure projection of the value's temporal state, not a reaction to its events. This makes the entire categories
events. This makes the entire categories of bugs structurally impossible. Stale
closures, race conditions between overlapping requests, flickering due to mismatch loading states, UI tearing during async transitions. Where other
frameworks rely on discipline, solid relies on invariance, a runtime that can absorb AI generation code. AI does not write elegant code. It writes maximally literal code. In virtual DOM system,
literal code. In virtual DOM system, this leads to over rendering, hook chains with hidden dependencies, effects that accidentally rerun, states that drift because the framework cannot see the graph. Humans eventually lose the
the graph. Humans eventually lose the ability to reason about the system.
Solid fine grain reactivity turns this dynamic on its head. Even if the code is sloppy, repetitive or overly imperative.
The runtime constraints put into transparent observable graph.
Computations become explicit, dependencies become explicit, updates become surgical. In other words, even
become surgical. In other words, even bad code becomes predictable code. This
is the only sustainable architecture.
Future AI is the primary contributor.
Four, stability is strategic assets.
Frameworks often chase features abstraction or syntactic novelty.
Solitude takes the opposite path. Invest
in permanent primitives. these
primitives signals timeline boundaries those aren't our actual primitives but good try AI form I guess boundaries are and signals are I don't know what timelines are I I guess they're talking about like the pending stuff form stable
contract between your logic and screen they are not patterns they are not conventions they are mathematical guarantees about how state flows through time this stability is not conservative it's forward-looking as code bases grow beyond human comprehension stability
only becomes the only way to maintain velocity without collapse solitude is 2.0 0 is not designed to help you write code faster. It's designed to ensure the
code faster. It's designed to ensure the code you write or the code your agent generates remains correct by default.
Yep. The future belongs to deterministic systems. The next decade of front end will not be defined by JSX versus templates or by compilers versus runtimes. It will be defined by whether
runtimes. It will be defined by whether the system can guarantee correctness under exponential code growth.
Frameworks that rely on human discipline will fail. Frameworks that rely on
will fail. Frameworks that rely on runtime invariance will endure. 2.0 is
the first frame built on this reality.
It's not a UI library. It's a temporal contract. to guarantee that your
contract. to guarantee that your interface will always reflect the true state of your system no matter how much code is generated above it.
I hope so. AI seems pretty positive. It
tends to be.
How's your overall feeling so far? I
think I think I think there's a couple places where I I get kind of discouraged at times where I'm just like, "Oh man, I can see why that wasn't intuitive." But
then when I go back at it and I go, "Oh yeah, but it is actually the reality."
My biggest concern is making sure that the education is I I I actually don't I think the API shape and stuff are generally good. Like I I think in a
generally good. Like I I think in a sense it rolled out like it's as I said it's not something invented. It kind of like was discovered. It's kind of like
following the physics. So like um while there's small pieces you know like adding on to loading or things where we can like do these kind of like slight adaptions that can fit some patterns
generally I generally for the most part I think we've actually gotten to a really good place really nice design. um
like stuff seems consistent like over and over again I hit like these issues and stuff and I'm like that's why we have split effects like literally just like I'm like I'm like oh this would have been a
problem except you know the place where it becomes awkward is like legacy APIs and stuff like stuff like actual uh like tracked effect like I I had to fix a whole bunch
of like do a whole bunch of special casing just so that we could keep like on mount or unsettled as it's called um or keep like effects not being split like stuff like that is the biggest
source of my concern because as I think it's important to like still continue to support people in certain ways but like those the things those things are doing are really terrible. Um and it's hard
because they're like people like I want to be like this and you're like no you don't like everything like and it's not like something like oh just because of this one reason it seems like everything flows out of the system that way. you
start doing more work and you're like, "Oh yeah, split effect saved us again.
Save like and it's almost like a hammered repetitive message as the design progresses that just supports the thing." Now, obviously sometimes that's
thing." Now, obviously sometimes that's self-fulfilling because like you set the constraints in the first place, which means you come to that inevitable end.
Um, so I I recognize that as a thing, but it it feels incredibly consistent um and and reasonable uh from where I'm sitting at least. I most of the bugs are
there's a lot of bugs which makes it hard to kind of see the full picture but then some of the other stuff but behaviors are just weird behaviors like
where you know um uh like people are doing stuff that is unex unexpected and really should be forbidden a lot like there's a lot of
the bugs I looked at them and and I was like we should just throw an error there which is odd but it's kind of like
my picture of the behavior of the system has never been clear.
Okay, I guess that's the best way to put it.
Like a lot of the ambiguities are gone.
Uh what else we got here?
recently attacked. Oh, Sublime.
Oh, okay. Let's go into the bookmarks the last little bit. Um,
there's not much to say here.
Theo actually covered in his video and I thought he did a really, really good job cuz like anyone who knows Sunil knows how awesome of a guy he is.
Um, but basically long story short, Verscell had kind of like a bash thing layer that they set up on top of their
infrastructure um uh that so that AI agents could use bash in a safe way without like getting to the underlying infrastructure and then cloudflare or saw it and was like hey
you know this is actually really useful we should do something similar but obviously they don't work on no they work on worker D or whatever their underlying thing on their workers. So
they had to uh the it a straight point won't work.
The challenge here was that just bash was is it this article still here.
The gist of it is just it's basically not stable. It's like
literally experimental like it it's not in a place where someone should like copy and fork it so so to speak but it's obviously the need is there and Sil was just testing stuff but he released it
through a public Cloudflare official repo and they they basically he removed all the stuff that wasn't necessary for you know
their environment and you know because of the whole Verscell Cloudflare thing going on the whole thing kind of got really blown up like
is this Cloudflare trying to steal Verscell stuff and remove the security and all this stuff and everybody chimes in. I I think Malt and Sil talked and then everything
cleared up. It's just funny like like
cleared up. It's just funny like like whenever there's these dramas things get like way blown out of p perspective you know's like oh's mission is to fork the entire
development ecosystem destroy open source v-ex was an excuse to swindle developers into does anyone take this guy seriously anymore it's fine whatever it's kind of like
when I read Donald Trump like I I just I I just can't do it anymore I'm sorry Um, let's just continue. I The the gist of it is that these guys made up and it was
just a misunderstanding.
I The thing is it's always like the It's always like the It's always like the overreaction things where people end up saying the thing that they like should regret. It's
usually not the original thing. It's
like the way everything blows up. Like I
remember when the whole remix doc scandal stuff happened with us and like the the guy from one of those like venture capitalist companies, you know, that scooped up all the open source
companies was like trying to like flag like net like Matt Bilman and then and then be like, oh, you know, blah blah.
It has nothing to do with Netlefi at the time or anything. So it was just like people trying to like stir up crap when they have no business to because they like getting on the drama. Um,
I it's unfortunate this scenario and that's all I really have to say about it. Um,
it. Um, I think I want to leave on this last AI note because I think I I saw this from Dev today and I thought this was funny.
So, this is going to be injected into every coding agent system prompt. So
much for AI is good at React because training data sets. I mean ensure page for react code prefer modern patterns include use effect start transition and use deferred value when appropriate if
used by the team do not add use memo use callback by default unless already used follow the react compiler guidance sorry if I didn't like this obviously we will they will always like
being the new dark finger but AI still works better rack than new fraud React is more native to JavaScript.
I don't even know if I want to read these responses. I feel like I might
these responses. I feel like I might like just insult people that I just forget it. Let me just focus on
what I actually wanted to the the thing is there the a react is still evolving and these patterns including the compiler
including all this stuff means that react code is changing the to the point that I don't think this change is hard to absorb. I think AIS have no problem
to absorb. I think AIS have no problem absorbing this sort of change. So I like I I think just the whole I think this whole AI is good React training set data
thing is complete garbage. I' I've been saying it for a while and I if basically if React can absorb the or if the AI can absorb this easily then it can absorb
solid or something else just as easily and people pushing this thinking are are just yeah I mean I don't even know
what to call them. I I don't it depends on what their motivations are, right?
You know, it's a spectrum between swindler and ignorant. So,
I I I think I I think this I actually I think Ben Davis just did a a video about this uh recently talking about like spelt and like how AI is no issue.
I've found the exact same thing with solid, you know, like there this whole this is like this is not the argument to make. And I I love seeing it
make. And I I love seeing it crystallized like this one. Like
basically Reacts introducing multiple new uh primitives that replace other primitives not to use and also
following different codew writing standards thanks to the strictness of the React compiler. Like these are all good things to do. It just suggests that React now is not the same as React was 5 years ago when the or when like these
models were trained, you know, generally speaking. So like
speaking. So like the there there's probably more React code using these proper values than there there are some other frameworks codes,
but the I think the numbers are a lot closer between this stuff and like say picking up spelt or some other framework. Uh definitely Vue. I mean
framework. Uh definitely Vue. I mean
when did Vue switch the composition API?
2020. Yeah. So that fits in like you know what I mean like this is much rarer of a breed. So
obviously if React keeps on winning, React keeps on propagating but like at this point it's your own self-fulfilling pro prophecy. Don't think it's anything
pro prophecy. Don't think it's anything else.
Recently AI wrote me a React class component. Well, there you go. Still
component. Well, there you go. Still
works.
Current LMS are quite good at writing code in a total loable language with minimal examples. I don't think this is
minimal examples. I don't think this is a real thing anymore. No, it it isn't.
Uh it's funny that we have to call this out though because I mean I mean there's people who think this, right?
Dev actually humor him? No. Good. Um,
one thing is then yeah the one constant here is change. I don't know how often we have
change. I don't know how often we have to like debate this with people.
Every doesn't know how to use your deferred value. I agree.
deferred value. I agree.
Yeah. Someone's from Spell Community.
No, the reality is is this is just not a thing anymore. AI is generally good.
thing anymore. AI is generally good.
All right. Yeah, I'm done, too. I got to go, too. It is almost 4:00. I've
go, too. It is almost 4:00. I've
streamed for quite a long time. Um, only
went a little longer because I started late, but um I'm actually going to look and see if anyone else is streaming, see if we want to raid
anyone. But to be fair, except for last
anyone. But to be fair, except for last time where strangely Theo was streaming right started streaming right at the end of our stream. Usually there isn't much
for the Friday night crew. Yeah, it's
all good. Um,
you guys all have a great weekend and uh hope you learned something from the stream. Uh, it's going to be a couple
stream. Uh, it's going to be a couple weeks. Uh, oh yeah, there's one one more
weeks. Uh, oh yeah, there's one one more little bit of news. Uh, going to be doing a Solid Start stream coming up in a in a couple weeks. Uh, Solid Start 2.0. 0 uh is close to release. It's
2.0. 0 uh is close to release. It's
going to come out before solid 2.0 and it's going to be update for solid one.
Uh Ailla has like a a whole thing he posted, but I probably missed I forget if we were going to publicly announce something.
Let me see here. Actually, you know what? The discussion is public. Let me
what? The discussion is public. Let me
just throw this up as like one last little thing before I go. Um, let me throw here road map
start V2 and ecosystem. Hey folks, long time no talk. Our last announcements was done at the beginning of Da Vinci work.
Uh, we have successfully um completed and I'm happy to let you know that Solstar version 2 is used in production already in real world apps like open code console. Yeah, nice. As
for the last announcement, our plan to maintain start and solid inversion lock step. It seems possible the works in
step. It seems possible the works in nitro v3 solid v2 and start v2 convergence to a similar release date.
We are now deciding against this plan in order to provide a better developer experience and migration plan for existing start version one and v solid v1 apps. Yeah, exactly. Like you could
v1 apps. Yeah, exactly. Like you could tell that we were all converging around the same time. For us, the ideal support for solid v2 would also need breaking changes in router meta packages.
However, since the team has managed to keep the Da Vinci effort with minimal breaking changes, we believe it's worth the effort to create a stable release in the new architecture in order to lay down incremental migration steps toward the future solid. Creating for start V1
to V2 requires a small change to Vconfig TS TS config JSON and optionally create middleware signature. Although the
middleware signature. Although the internals are much different improved, there's no change impacting your server functions, actions or component code. I
you give a try and follow these migration things. Update timeline
migration things. Update timeline remaining block start alpha new directive plugin built-in server only environment variable support beta once these merge release beta zero collect
feedback uh solar recommended server runtime from nitro to v3 plan release candidate by the time we're confident up ships 2.0 RC effectively
deprecating start P1 and create solid CLI will official doings solid B2 as the ecosystem adapts to the new APIs and updates in solid R solid meta we will start working B2 though likely is not
certain supporting solid V2 means V3 for start yeah though likely it probably will be V3 start V2 will not drop support for V1 that's the idea if there's a chance to support an
incremental migration from V1 to V2 within start V2 we'll try that but at this point we're not trying to make any promises Fair enough and I think it's good that you didn't uh we are also working on developing plug-in based
system ecosystem first package long awaited image component awesome was open thing blah blah blah migration yeah so gist of it very exciting um I'm not
logged in so I can't do anything here but um we solar v2 is probably going to be coming out in the next month or so I
think somewhere along that lines we're going to talk about it we're going to do a stream on it uh in two weeks and uh then uh we'll see how the beta continues
going, but then the support for um like we're we still have some time on solid 2 beta at least at least a month. So um
we'll we'll you know solid start support will come a little bit later after that essentially. It might be a quick V2 to
essentially. It might be a quick V2 to V3, but I think it's important that we have the updated basis and until it as well that for solid start so people on
solid version one can continue to like get updates and use the latest technology where it is today and not be stuck in like where we've been in the past with Binci
and whatnot. So bit of news. I just
and whatnot. So bit of news. I just
occurred to me I wanted to get this out early now because um uh you know by the time I we have the stream in a couple weeks you know the
this stuff will be well underway. All
right. Anyways,
you you you all have uh you all have a great one. All right. Um
great one. All right. Um
Oh, yeah. Actually, you know what? Sure.
I don't know what he's doing, but let's let's let's uh let's raid to see him griffing. Why not? It's been a while. Uh
griffing. Why not? It's been a while. Uh
on my channel Bing, I think he's working on something in Rust right now, but you know, it's all good. Anyways, um you all have a
all good. Anyways, um you all have a great one. Uh till next time. See y'all.
great one. Uh till next time. See y'all.
Loading video analysis...