Transcript
00:00:00Solid 2 just shipped to release Canada, and this update is a big one.
00:00:03It completely reworks how async is handled in the framework, making it a first-class feature,
00:00:07getting you a way better developer experience for data fetching, loading states, and reactivity.
00:00:11Effects have been changed, stores have changed, boundaries have changed,
00:00:14and loads of SolidJSX syntax has changed, and if that wasn't enough,
00:00:17there's a new compiler toolchain written in Rust over 20 times faster than before,
00:00:21and the plugin now comes with a start mode, which completely kills the need for Solid Start.
00:00:25They actually released Solid Start 2 a couple of weeks ago,
00:00:27and in this update, you can say goodbye to it.
00:00:29This whole update actually feels like a real innovation in front-end frameworks,
00:00:32so let's jump in and see everything that changed.
00:00:39So the big headline in Solid 2 is that async is now part of the reactive graph.
00:00:44In Solid 1, you have to use the special create resource primitive to manage your async data,
00:00:48like we do with fetch user here, and from that resource,
00:00:50you could then access the latest resolve value, loading state, and errors.
00:00:54In Solid 2 though, this becomes much simpler.
00:00:56Computations can now just return promises directly, so we can use fetch user
00:00:59inside of create memo, and now user is simply a memo that happens to be async,
00:01:03and everything downstream understands it.
00:01:05Create resource has been removed.
00:01:07You may have also noticed that our suspense boundary got replaced with loading.
00:01:10They've actually reworked all of the boundaries,
00:01:12so suspense has now been removed, and you use a loading boundary,
00:01:15which renders the fallback if there's no data yet, so no first result,
00:01:18and then after that, you can use isPending if you want to track whether new values are being fetched.
00:01:22Error boundary also got replaced with erud,
00:01:24although this largely seems like a rename and a rework under the hood,
00:01:27and the same goes for suspense list, which has now been changed to reveal.
00:01:30Now those examples might make you think the async work is basically just renames,
00:01:34but under the hood, it's a complete different approach to handling async in frameworks.
00:01:37Ryan actually posted a diagram on Reddit to try and explain some of this,
00:01:40so I recommend reading that for a full deep dive,
00:01:42but the TLDR is most frameworks block UI with a suspense boundary at the same time they consume a
00:01:47promise, so use in React or await in Svelte, but Solid 2 consumes the promise on creation
00:01:52into its graph and blocks where the value is read.
00:01:54We can see this in React, where if I have all of my promises in my parent component and I click replay,
00:01:59I only ever see that first suspense boundary fallback as these requests are blocking the UI,
00:02:03and it waits for all of them to finish first.
00:02:05You can obviously solve this in other ways, like passing promises or co-locating,
00:02:09but it was always a trade-off between developer experience and user experience.
00:02:12Solid 1 did partially solve this already, I have all of my promises being consumed with
00:02:16create resource here, and when I click replay, the user profile shows when the data is read,
00:02:20and then we see the team skeleton until its data is ready, and the same goes for the member
00:02:24component. So the user experience part is solved because the UI immediately updates when the
00:02:28data is ready. The problem in Solid 1 though is we've had to scatter null and undefine checks
00:02:32everywhere when we're working with that value that we get from the resource. So Solid 2 fixes all of
00:02:36this, when we consume our promise with create memo, the promise goes into the graph immediately,
00:02:40and from that point on we only ever deal with a plain value, not the promise. So all of these
00:02:44nested components can be purely presentational, and the value also doesn't have the undefined
00:02:49state anymore. So we can remove all of those checks from our code, and at the same time we can use a
00:02:52loading boundary, and Solid will handle whether the value is ready or not. This gets you the best
00:02:56user experience, as UI shows when it's ready, and the code is cleaner so it's a better developer
00:03:00experience too. You could get a much better developer experience by subscribing, it keeps you up to date
00:03:04with AI and dev news like this. Now everything I've mentioned so far about async has been about
00:03:08reading, but what about writing? Because there's been some changes to how you do optimistic updates.
00:03:13In Solid 1, optimistic updates use the resource mutate function, but that's actually been removed and
00:03:18replaced with a much nicer flow with action, create optimistic, and create optimistic store.
00:03:23So if we wanted to have optimistic updates for our to-do app, first we create an optimistic store with
00:03:27our source of truth, which is going to be the server fetch, then we create an add to-do action,
00:03:31add the to-do to the local store instantly, fire off the save API, and then call refresh from the
00:03:35server when that's complete. Action actually gives the mutation a lifecycle, so the local changes we
00:03:40make to the optimistic store only exist for the lifetime of this action. That means if this API
00:03:44call were to error out, the optimistic override would disappear and the UI goes back to the
00:03:49authoritative value. So we now have automatic rollback, which is a pretty nice change from
00:03:52doing things manually in Solid 1. Now for those solid devs paying attention, you may have noticed
00:03:56something special about optimistic store. It actually handed us a draft here, which we mutated
00:04:01directly. This change has been made across all of the stores, so there's no need for the
00:04:04produce function anymore. That's been removed along with create mutable, as it's now just
00:04:08the default behavior. There is still a store path helper if you want the old pathway back
00:04:12though. Moving over to effects, they've made some big changes here as well. In Solid 1, an effect
00:04:17was one function that did everything, tracking whatever you read and also the side effect. Solid
00:04:212 splits this in two, separating dependency tracking from the side effect. The first function
00:04:26computes a value and gets tracked, and the second function is untracked, receives the value,
00:04:30and does all of the actual work. This creates a separation between what you depend on and what
00:04:34you do about it, and it replaces the need for the on function, as this is handled by the compute
00:04:39function now. And if you want the defer option that the on function had, you can simply do that as an
00:04:43option on the effect instead now. Alongside this, create computed was also removed, as you can simply
00:04:47use a memo if you want a derived value, or a split effect if you want a side effect. When it comes to
00:04:52cleaning up your effects, this also changed as well. Instead of calling on cleanup inside the function
00:04:56body, the apply function simply returns its cleanup function, kind of like React's approach. The same
00:05:01change has been made to the on mount function, which is now on settled. You return your cleanup
00:05:05from the callback. On settled actually fires when all of the async work under it has resolved,
00:05:10not just when the component mounts. When it comes to signals, not much has changed about how you use
00:05:14them, but the difference is under the hood. Solid 2 stages, writes, and commits them on the next
00:05:18micro task, so if you read a signal on the line right after setting it, you'll get the old value,
00:05:22but you can use the flush function to force the value through if you need it right away.
00:05:26This change has also meant that batch has been removed, because consecutive writes already share
00:05:30a batch by default, so there's nothing left to wrap. I think that's just about it for the async
00:05:34and reactivity changes that I wanted to cover, so let's take a look at JSX, which they also reworked,
00:05:39aiming to get a DOM model that's closer to HTML. If we start with classes, class list is now gone.
00:05:44Instead, class itself now takes strings, objects, or arrays. For conditionals now,
00:05:48you can simply use an object, so there's no more concatenation, filter, or join tricks.
00:05:52Attributes also got the same treatment, the attribute and bool prefixes are gone,
00:05:56you just write standard attributes, and booleans follow normal HTML presence and absence rules,
00:06:00so the attribute only appears if its value is truthy. On and on capture are also gone,
00:06:04just use the camel case event props now, and use a ref callback and add event listener if you need
00:06:08the native listener options. For directives, the username space is gone, it's been replaced by ref
00:06:13callbacks and directive factories, and ref now takes an array so you can stack multiple directives on
00:06:17the same element without wrapper function. Staying in JSX, lists also got simplified. In solid 1,
00:06:23you had two components for rendering an array, 4 and index. 4 was keyed so each item got matched by
00:06:28identity, and index was the opposite, it was mapped by position. In solid 2 though, index has been
00:06:32removed, so there's now just 4, but you can get that index behavior back by setting the prop keyed to
00:06:37false. And lastly for the JSX changes, there's also a new component called repeat. Instead of taking an array,
00:06:42this renders by count, you give it a start index and a count, and each row reads its own slot in the
00:06:47store, so updating one row touches nothing else. I think that is finally everything noteworthy from
00:06:52the framework point of view, so now let's focus on the tooling because the v plugin got two big changes,
00:06:57and the second one is why solid start doesn't need to exist anymore. First up, the compiler. Solid 2
00:07:01ships a brand new compiler toolchain written in Rust on top of Oxy, and the v plugin defaults to this,
00:07:06so you shouldn't have to make any changes. According to that benchmarks, they saw a speed up on
00:07:10our test project from around 440 milliseconds to compile down to just 19, and on a larger 1 megabyte
00:07:16single module, this came down from 25 seconds to just 70 milliseconds, so 355 times faster. The second
00:07:24change is the bigger one though. The plugin now has its own start mode. This gets you a full app build
00:07:28on plain v with no index HTML scripts or entry files needed. By default, this will be in client only
00:07:33mode, so building will emit purely static files, but you can also enable SSR if you want to ship a
00:07:38server bundle with the build and get server side rendering, and on that note, if you like server
00:07:42functions, use server is now a core feature. On top of that, you can also get file system routing
00:07:47with a router neutral package, giving you solid start proven conventions, hot module reloading, code
00:07:51splitting, and more. I really like this setup because deploying is either static files or a server module
00:07:56that exports a web standard fetch handler, which Cloudflare workers, Netlify, Nitro, Bun, and Dino
00:08:01already speak, so you deploy with your platform's own tooling, and there's no solid specific adapter in
00:08:06the middle. This does mean that solid start is no longer needed though. As that blog post says,
00:08:10solid start did its job. It was a meta framework meant to fill the gaps of solid, but now too brings all of
00:08:14those capabilities home. If you are running solid start, nothing changes today. It will continue to
00:08:18get maintenance updates, and you can check out that migration guide if you want to switch over.
00:08:22That's about as many updates as I can fit in one video. You can see this was a seriously big update
00:08:26with loads of changes and removals from the APIs, and there would have even been a few that I didn't
00:08:30cover, like start transition and use transition being removed, so I recommend checking out that
00:08:34migration guide from solid 1 to solid 2 if you want the full list, and it's also a great resource
00:08:39to point your agent at and ask it to migrate for you. I was going back and forth between solid
00:08:43one and solid 2 a lot, and Claude Code seemed to understand from this document and pick up all of
00:08:47the changes. I really liked diving deep into this update, and I'll be honest, I haven't used solid
00:08:51in a while, but solid 2 let me pick it up really easy, and I actually enjoyed using it quite a lot,
00:08:55so I think I might use it a bit more in the future. What do you think? Did you use solid before,
00:08:59and do you like this update? Let me know in the comments down below while you're there,
00:09:02subscribe, and as always see you in the next one.