skip to content
Video cover art for SolidJS with Ryan Carniato
Video

SolidJS with Ryan Carniato

Ryan Carniato discusses SolidJS, demoing how to port a Hacker News clone from Rollup to Vite. Explores data fetching, reactivity, and benchmarking frameworks

Open .md

Episode Description

Anthony Campolo and Ryan Carniato explore SolidJS by migrating a Hacker News demo from Rollup to Vite, discussing data fetching, routing, and framework benchmarks.

Episode Summary

In this episode of AJC and the Web Devs, Anthony Campolo is joined by Ryan Carniato, creator of SolidJS, to walk through a hands-on exploration of Solid's Hacker News demo application. Ryan explains why Hacker News serves as an ideal demo app — it showcases data fetching, routing, and page rendering without excessive complexity, and its collapsible comments page naturally highlights the benefits of partial hydration techniques. The pair then attempt a live migration of the demo from its original Rollup setup to Vite, which turns out to be surprisingly straightforward, requiring only a router API rename from useData to useRouteData and a CSS import fix. Along the way, Ryan explains key Solid primitives like createResource for data fetching, the Show component for conditional rendering, and how Solid's non-blocking, fine-grained reactivity differs from React's top-down rerendering model. The conversation shifts to Ryan's work at Netlify and his involvement in Builder.io's meta-framework benchmarking efforts, where he discovered that performance bottlenecks often come not from UI rendering but from overlooked meta-framework overhead like asset insertion and server-side tooling. The episode underscores how Solid's primitive-based architecture allows the same patterns to work across client-side SPAs, SSR, and islands, and closes with reflections on the importance of community education and open discourse in the framework ecosystem.

Chapters

00:00:27 - Introductions and Ryan's Background

Anthony Campolo opens the second episode of AJC and the Web Devs and introduces the topic of SolidJS. After some brief technical difficulties, Ryan Carniato joins and shares his background as the creator of SolidJS, describing how he also worked on the Marco framework at eBay.

Ryan explains how he got into streaming and content creation. He found that when he tried to share his work on JavaScript performance and frameworks on Twitter, there was a knowledge gap between foundational concepts and the advanced topics he was exploring. This led him to write articles and stream deep dives into the underlying mechanics of how frameworks work and the design decisions behind them.

00:04:00 - Why Hacker News as the Demo App

Anthony praises Ryan's educational work on newer frameworks like Qwik, Fresh, and Astro, noting how few resources existed for these tools beyond their documentation. The conversation turns to Ryan's choice of Hacker News as his go-to demo application for comparing frameworks, a tradition tracing back to a Vue 2 implementation by Evan You.

Ryan explains that Hacker News is ideal because it represents a common real-world pattern: a mostly static page with data fetching and minimal interactivity. Unlike TodoMVC, it demonstrates how frameworks handle page rendering and data loading. The collapsible comments page is particularly valuable because it creates a scenario where single-page app approaches cannot easily optimize their way out — you either handle it the classic SPA way or leverage newer techniques like islands architecture, making the performance differences between approaches clearly visible.

00:08:49 - Examining the Solid Hacker News Codebase

Anthony walks through the existing Solid Hacker News demo, noting it still uses Rollup, and shares his plan to potentially migrate it to Vite. He describes how he simplified the project structure by consolidating components for the stream's purposes. Ryan provides some history on the demo's origins and iterations.

The pair discusses the project's deployment setup, including a Cloudflare KV asset handler that Ryan had hacked together for static asset serving. Anthony shows that the app deploys easily to Netlify as a standard single-page app with just a build command and output directory change. Ryan notes this simplicity is one of the advantages of SPAs — the output is just a static folder of assets — though the trade-off is the build tooling complexity required to produce them.

00:13:35 - Router, Data Fetching, and Solid Primitives

The conversation dives into Solid's routing and data-fetching patterns. Ryan explains how Solid's router allows each route to define a data function that runs in parallel with code splitting, fetching data and loading components simultaneously. He walks through the createResource primitive, comparing it to tools like SWR and React Query.

Ryan details how Solid's fine-grained reactivity means components don't rerender from top to bottom, which is why constructs like the Show component exist as anchor points for conditional rendering. He explains that createResource provides built-in error and loading states accessible as properties, and that Solid supports suspense and error boundaries for more declarative error handling. Anthony draws comparisons to Redwood's cell pattern, and Ryan notes that Solid's non-blocking approach means the framework begins building the DOM immediately with whatever data is available, filling in gaps as async data resolves rather than throwing and rerendering.

00:29:26 - Live Migration from Rollup to Vite

Anthony begins the hands-on migration by cloning one of Solid's official Vite starter templates and copying the Hacker News demo files into it. Ryan observes that the migration might be surprisingly simple given that the core Solid code stays the same regardless of bundler.

After installing the Solid router package and discovering that the only API change needed is renaming useData to useRouteData, the demo comes to life in the Vite environment with minimal effort. A quick CSS import fix completes the migration. Ryan highlights how Vite's built-in capabilities like CSS module support and its index.html-based entry point eliminate much of the plugin work that was necessary with Rollup, making the developer experience significantly smoother.

00:39:13 - Solid's Approachability and the React Mental Model

Ryan reflects on an interesting observation from the migration: a React developer can get surprisingly far with Solid by applying familiar mental models around JSX and component structure. Anthony confirms this, noting he was able to refactor the codebase without breaking anything despite never having used Solid before.

Ryan acknowledges this is both a strength and a potential pitfall. Developers can be productive immediately, but Solid's fine-grained reactivity means there are fundamental differences from React that will eventually surface. He emphasizes that Solid's primitive-based approach means the same patterns — createResource, routing, data functions — work identically whether you are building a client-side SPA, doing server-side rendering, or using islands architecture, which is a core design philosophy behind Solid Start.

00:44:10 - Builder.io Benchmarks and Meta-Framework Performance

The discussion shifts to Ryan's involvement with Builder.io's framework benchmarking efforts. Ryan explains Builder's background as a low-code site builder and how performance concerns with e-commerce Lighthouse scores led Steve Kramer to create Qwik and Partytown. Builder began benchmarking meta-frameworks to understand hydration costs and loading times.

Ryan shares a surprising finding: the biggest performance bottlenecks were not in the UI rendering layer but in meta-framework overhead — things like how assets are inserted into the document head or how servers handle compression and file serving. This led to concrete improvements in Solid and underscored the need for better measurement tools beyond arbitrary Lighthouse scores. Anthony draws a parallel to Redwood's experience discovering that serverless function cold starts created an unavoidable one-to-two-second floor on response times, illustrating how architectural decisions can embed hidden performance costs.

00:51:19 - Community, Mentorship, and Wrap-Up

Anthony asks Ryan to share links for viewers to learn more about Solid, and Ryan points to solidjs.com and the Solid Discord as the best resources. He describes the Discord as a vibrant space where framework authors and contributors openly debate ideas, sometimes spontaneously creating new libraries to prove their points.

Anthony thanks Ryan for being an accessible mentor in the community, noting how Ryan has reviewed his articles and provided feedback. Ryan emphasizes the importance of teaching and lowering barriers to understanding complex topics. Anthony closes out the episode with scheduling notes for upcoming streams, including a planned solo stream and a future episode on CSS with Travis from Bedrock Layouts, wrapping the second episode of AJC and the Web Devs at roughly 55 minutes.

Transcript

00:00:27 - Anthony Campolo

Hello everyone. My name is Anthony Campolo. Welcome to episode two of AJC and the Web Devs, where we have Ryan Carniato on here with us, and ideally he'll be hopping in any minute now. I think I did not communicate that. It's always nice to hop on a couple of minutes before the stream starts to actually get it going, but that is on me. A new thing to add to the docket when you bring on a guest.

All right, but I can talk a little bit about what we're going to be doing today because we're going to be talking about Solid, SolidJS. And if you don't know what Solid is, that's okay. There's a lot of new things out there in the web dev world all the time, and they're very hard to keep up with. I run an entire podcast based around keeping up with this kind of stuff, so it's one of the ways I've been able to stay hip with it. But it looks like we actually got Ryan here, so I'm going to go ahead and add him to the stream.

[00:01:21] Ryan? Hello?

00:01:22 - Ryan Carniato

Hey, hopefully my audio is working.

00:01:25 - Anthony Campolo

Your audio sounds good. How's my audio sound?

00:01:28 - Ryan Carniato

Sounds good. We're good. I had some technical difficulties. Just as I was joining, my camera in OBS decided that it was in portrait mode or something. It was really weird. It just wouldn't get out of portrait mode. I don't know how that happened, but anyway.

00:01:46 - Anthony Campolo

This is why I don't use OBS. One day I'll get there. Thank you so much, Ryan, for being here. You are the second guest on this new stream that I'm starting, and you are quite a professional streamer at this point. You do some of the longest streams in the industry that I see. I find your average is usually three to four hours, and you do a weekly roundup of content. You bring on a guest and then you hang out and debrief after. It's a bit similar to what Theo does. If I find myself with far more hours in the day, I may find myself in that format one day as well. Why don't you give a little intro on who you are and what you do?

00:02:30 - Ryan Carniato

Yeah, sure. My name is Ryan. I am a JavaScript front-end developer who ended up creating the front-end framework SolidJS, and through that process ended up working on other front-end frameworks as well. Like Marco, I worked at eBay on that for a while.

You mentioned the streaming stuff. Basically, I found myself in a position where I was working on new ideas and I had no framework. I came into certain spaces like Twitter and tried to tell people about this, and no one knew what I was talking about. Part of it is because I'm deep down my path, so to speak, very into JavaScript frameworks and performance. So I'm deep there. But part of it was that I realized there was a gap between some of the base-level knowledge and this more detailed knowledge.

[00:03:31] So I started. I'd already been writing some articles, but I started writing articles and streaming to give a deeper look at some of the tools we use every day and maybe don't think about. My content usually isn't very much about what you do on the job or advanced techniques like that. It's about the actual underlying tools, how the frameworks work, and why the decisions are made behind them.

00:04:00 - Anthony Campolo

That's great, and your stream is one of the inspirations for this stream. I have a range of different streams that have inspired me, and what I really enjoyed is that you were leaning so heavily into newer frameworks, both by building your own and by bringing on Qwik, Fresh, Astro, and frameworks that are less than two years old. When you look at the timeline of frameworks, people have a hard time separating them. When you first enter, you see there are ten of these things and you're like, whoa, what's going on here? Some of them are five years old, and some of them are one year old. It's very hard to tell that difference on the surface level until you really dig into them.

So I really appreciate that you were going out and creating really intense educational material around these brand new frameworks that almost no one knew anything about beyond their own doc sites.

[00:04:52] There are almost no resources available for any of these things, and that's the same approach I took with FSJam. You actually got me in touch with Dylan for Marco. Marco was a framework that is seven or eight years old and had never had a podcast episode about it. No one had ever gotten on a podcast and just talked about Marco, and I thought that was pretty amazing. Since then he's been on Pod Rocket and more people are starting to talk about it here. Matt Billman mentions Marco, and I talked to him about new frameworks, so that's super cool.

People who are okay leaning into the learning-a-million-tools thing because they want to compare different tools and weigh trade-offs, this material is really useful for them. And what you do is the Hacker News clone. Why do you choose Hacker News as the baseline app for all of these frameworks?

00:05:44 - Ryan Carniato

Yeah, I mean, the thing is there are a few demos that we end up using over and over again because they're simple enough to reproduce, and they are illustrative. The most common one is probably MVC. Doing MVC is great because it shows you list management and the mechanics of doing mutation and stuff. But the one thing MVC is missing is a concept of data fetching. To be fair, data mutation isn't in Hacker News either, so it's not the full demo per se.

But I ended up using Hacker News because the simplest task of a website isn't necessarily the interactivity. It's showing something, right? It's like, give me a page, put some data on the page, and show it. That's what the Hacker News example does.

[00:06:46] You get to see data fetching. If you're opinionated, like a full-stack framework, you can see the back-end part of that as well. It gives us the ability to see what it takes to put a simple page up. There were some other, more technical things that came out of that demo that I didn't realize at first, but they were relevant to these new frameworks because the Hacker News demo is a mostly static page with just some, you know, I mean, don't get me wrong, the listing of content makes up the majority of what you see, but it is a very simple app. So it shows the difference between these techniques because, let's face it, a lot of sites are fairly simple: you have a few points where data comes in and otherwise you have this shell. So Hacker News is really representative of that.

[00:07:40] And what I ended up liking in the long term is that the comments page has this kind of collapsible comment thing. As it turns out, that is the perfect scenario to show the benefits of things like islands and whatnot, because there are a lot of tricks, imperative code, and hacks you can do. Any framework has escape hatches. So you can go back to using vanilla JS. That's what's awesome about the web platform. If something isn't performant enough, you can go a bit lower level.

But the comment page on the Hacker News demo doesn't let you go halfway. You either do it the classic single-page app way or, with these islands frameworks, you can do it a different way. But the single-page app way can't cheat to get performance; they're stuck with the approach.

[00:08:36] So it served as a way of showing, quite visually, the difference between some of these partial hydration techniques versus not.

00:08:49 - Anthony Campolo

Yeah, and that's what we're going to look at today: the Hacker News demo in particular. I was looking for the canonical Solid implementation of this, and I found one. I was surprised that it was still using Rollup. So part of what we might do, if we have time, is migrate this to Vite and get you a pull request to update that. It worked in its current form, but I never really learned Rollup. When I use it, stuff gets wonky and there's weird localhost stuff.

The main thing we're going to do is look at the project first and the structure of it. I actually even took it and simplified it further, so there are fewer files and I shoved some stuff together. So it's more like a single-file component thing. This is not meant to be the perfect way of organizing the project.

[00:09:41] I want to show how you could do this in the most concise way with Solid. So I made a couple of opinionated decisions on how I checked out the components directory and stuff like that. But that's just for the sake of this stream.

00:09:56 - Ryan Carniato

Yeah, I mean, for a little bit of history, I didn't create the original version of it, and I think I actually mentioned in the README. There are a lot of Hacker News examples, and there was one site called Hacker News PWA that was up and great for a while. But if you go on the site now, literally every link is dead. Not every link, but a lot of them are dead.

I finally found one that I liked, and that was the one that Evan made for Vue 2. That's what we've been porting around here forever. It's this old JS thing. What ended up happening was I made the first example, and then every time I got Solid Start involved, tried different deployments, and different things, I just kept on building on it and never really went back to the original.

[00:10:47] The first time I actually went back to the original was for the Solid Start stream that I did a few weeks back, kind of introducing it, and I did a similar thing. But what was funny was I made that mistake. I assumed I was on Vite and I was like, I'm just going to carry it across. Then, two minutes before the show, I'm like, oh, crap, this is in Rollup, right? And it's not in TypeScript or anything. So I tried to scramble very quickly.

00:11:13 - Anthony Campolo

That's fine. We don't need to put it in TypeScript. We're not going there.

00:11:17 - Ryan Carniato

So yeah, this example is very old, probably dating back to 2016 or 2017 if you go back to what Evan did. But okay, that's cool.

00:11:27 - Anthony Campolo

What's awesome, though, is that it still works. I clone it down, I spin it up, the site is running, and it does all the same stuff you would have wanted it to do before. People talk about the JavaScript world always being fast-moving and breaking, and it's like, no, actually some of this stuff can stay stable and will just run if you don't mess with it.

I was able to move stuff around and get it to where I wanted it to look very easily. This is me not really having used Solid previously, just knowing how these projects are structured, understanding the conventions, and knowing how JSX components work. I was able to move stuff around. I was able to refactor it in a way where I didn't break anything. I was able to pull out a couple pages, and it was very simple to do.

[00:12:09] That's a testament to the simplicity of what you've built to a React developer who's never even used Solid before.

00:12:16 - Ryan Carniato

That's awesome. I'm glad to hear it. There's always little things here, little differences, little decisions we made in trade-offs. But structurally, you can take a React mentality and apply that to Solid from a high-level structure point. People do other stuff as well, but there are a lot of similar concepts. So I'm glad to hear that went smoothly for you.

00:12:44 - Anthony Campolo

Yeah, definitely. All right, let's get some screen sharing going and start looking at some code. I'm going to have to change things on screen real quick while I get the chat in here. One day I will have Ben Myers on here, and he will show me how to build an actual chat.

But what I do is throw the chat on my page while I share, and then you can all see it. Let me close this out for now, and let's look at this project real quick. So how does the Cloudflare stuff work before we get into any of this? I'm just curious: there's an index.js in the root here that has the Cloudflare KV asset handler. What is this file doing?

00:13:35 - Ryan Carniato

Yeah. Now I'm actually looking at this because the funniest thing is I must have gone in here at one point to change the deployment, because when I originally did this Rollup example, I was deploying it probably to something like GitHub Pages, right? Because this is the single-page app version of it. I was probably hacking it around a bit, and I must have changed it to use KV on Cloudflare. My guess is KV serves all the static assets for this site.

So if we're going to do something like Cloudflare, it shouldn't really affect much because we don't use KV for the actual... The way I did this was I probably used a serverless function to serve the static assets. So if you deploy to Netlify or somewhere else, I don't think you will need to worry about this. This was just something I hacked together so that I could basically just deploy it.

[00:14:37] Yeah, this is just a hack.

00:14:39 - Anthony Campolo

Yeah, I was actually able to get this running, not on Cloudflare but on Netlify, very simply. It was the Solid Hacker News Rollup Netlify app, and you just need to have a build command. So that could be npm run build. Then you had to change dist to public because when you actually build it creates a public folder. That's the only thing that you need to do. And you can do that if you just create a Netlify TOML file.

00:15:17 - Ryan Carniato

Right. That makes a lot of sense. I mean, the thing with single-page apps is that, in some ways, they're kind of simple. You just have an output folder and then you're back to a static set of assets. So as long as you have a way of doing it, there's probably a better way than this. I never really used static generation or CDNs, and I probably built this while I was in the middle of making Cloudflare adapters for Solid Start. So I probably just thought, okay, I was literally just making a serverless function; I'll make another one. It's probably not even the best way of doing it.

But yeah, in this Netlify thing, you are just publishing that folder. Make all the assets in the public folder, upload this folder on Netlify. Done. So that's always a nice thing about single-page apps in terms of simplicity from that side.

[00:16:09] It still requires this whole build tool thing, which I think is the non-simplicity from the other side. Some people are like, oh, if I just have a server and it serves some files, that's simple in the opposite way, whereas here we do all the building ahead of time.

00:16:24 - Anthony Campolo

Right. Yeah. So now we're actually running it locally. And for some reason, when I had it on the original 5000 and tried that, it was giving me this. I have no idea why. I opened an issue on the repo, but I just changed it.

00:16:45 - Ryan Carniato

I suspect it's something local on your computer in terms of what your localhost port can handle.

00:16:53 - Anthony Campolo

It's an Apple thing, as far as I know. This has come up before, and Apple has something running on 5000 by default. I thought I had turned it off, but that was probably on my old machine. So whatever it is, I would need to go look into it. But you're going to have a lot of random Apple users who have no idea what to do about this.

00:17:10 - Ryan Carniato

Yeah, that's absolutely fair. This is the old setup. I did my primary dev on Windows, running the Linux emulation under Windows for years and years. I actually only got my first Apple for home use when the M1 Airs came out. I'd been using Apple at work, but that was my first Apple for home use. So yeah, this demo was definitely made when I was doing everything in Windows.

00:17:40 - Anthony Campolo

All right, Ben just gave us a resource here for this. That sounds about right, but just changing the port number is probably going to be a quicker solution for most people anyway. But definitely nothing to note. Okay, so let's actually get into the components here. So there is a Solid router, correct?

00:18:03 - Ryan Carniato

Yeah. Oh yeah. This is old. This is going to be fun. I mean, this is fine the way it works, but I'm pretty sure the router has gone through a few iterations since I made this demo.

00:18:14 - Anthony Campolo

Yeah, so we don't have to dwell on the router too much, then, because the router layer is going to be handled in Solid Start. So my question is, will Solid Start be including the Solid router and then you building a meta framework on that, or is there a new router being built along with Solid Start?

00:18:32 - Ryan Carniato

No, it's just Solid's router. The file system routing that we do in Solid Start is just on top of the router. That was one of the coolest things about using Vite. We've built an ecosystem on the exact same libraries you'd use without Solid Start or with Solid Start. It's all the same stuff.

00:18:52 - Anthony Campolo

Okay, cool. So what's happening here is we're creating paths and then we're lazy-loading the components.

00:18:59 - Ryan Carniato

Yeah. And one other thing: you see this data thing. This is a pattern that we've had in Solid for a few years now. It's kind of like loaders and things people have been talking about. I think TanStack Location also has a kind of load idea, but we had this idea that, for each section of the route, even though this app isn't nested, you can set a function that's almost like a component itself where you set the data requirements for that route or path. If it's nested, the router will fetch them all in parallel, and in parallel to the code splitting. So you can pull the data and the code, even nested, and it all stitches together.

And what you see here is interesting because I'm trying to think of how old this is, because of how useData is used.

00:20:03 - Anthony Campolo

So is this not the best way to demo Solid, or is this just something that kind of needs to be refactored?

00:20:11 - Ryan Carniato

Yeah, I mean, well, useData here. Is this being called anywhere, this useData function? Because I'm not seeing it.

00:20:21 - Anthony Campolo

So let's look at the structure here. We've got pages, and then we've got the API here. These APIs are pulling in the stories and the user data. Then you have these data.js files that are hitting that API, and that's being displayed for each of these components.

00:20:46 - Ryan Carniato

Yeah, that makes sense. Oh, interesting. Oh right, this file has multiple components in it, doesn't it? That's why I'm not seeing it.

00:20:54 - Anthony Campolo

Yeah. So you have story, and then you have... okay.

00:20:57 - Ryan Carniato

This hasn't changed that much. There's been a slight bit of renaming, but yeah.

00:21:00 - Anthony Campolo

The story component is here.

00:21:03 - Ryan Carniato

Yeah, okay.

00:21:04 - Anthony Campolo

I'll do this to make it a little easier to follow what's happening here.

00:21:09 - Ryan Carniato

Yeah, okay. This is fine. We'll be good here because, basically, I was thrown off because I was trying to find useData. We still use these exact patterns. I think over time things have shifted a little bit, but this is actually fine. So I can speak to this. If this is where you want to start, we can start here.

00:21:32 - Anthony Campolo

Yeah. Okay. So this is our stories component. And then what is the Show component?

00:21:39 - Ryan Carniato

Right. One of the things when you have fine-grained updates, the components don't rerun again from top to bottom. And we need anchor points for deciding where to swap things out. For something like showing or hiding something, we could have just used an expression to do that. Because the way reactivity works is it looks at reactive values, like our signals and our data. Whenever that changes, that part of the code changes. Show seemed nicer, at least to me, ergonomically, than having helper functions for reactivity. So we decided to do stuff as components because it fit into the tree a lot slicker.

00:22:32 - Anthony Campolo

So Show is a data-fetching component?

00:22:34 - Ryan Carniato

No, it's a toggle for visibility. It's like a ternary operator.

00:22:39 - Anthony Campolo

Okay. So where's this useData stuff coming in, then?

00:22:42 - Ryan Carniato

Right. useData comes from the root. And if you look, you imported it from the router. The router will know that, when this page is getting rendered from the way we set up our root config, we're like, "on this path, render this component." It will know that that data refers to the data function that we registered for that route, which, by convention in here, I think is the one right next to it.

00:23:12 - Anthony Campolo

Which is this one. Yeah.

00:23:12 - Ryan Carniato

Right. So what ends up happening here is, when we resolve the root, at the exact same time we fetch the data for the component and run this function. What this function is doing is a bunch of setup stuff for us. We can return really anything from it. But I want to point out this is not an async function. This is not blocking. This is just a mechanism for setting up some data fetching and reactivity.

The first couple things are just convenience-based wrappers. The reactivity is based on access, like when you access a property or call a function. So to do some basic formatting, I wrapped it in a function here with page and type. The reason I did that was because we're going to pass it back out again at the end. There you see page and type are getting returned. And I wanted the ability to have these useful things, because if I calculate them here, I don't want to calculate them again in my component.

[00:24:14] They're going to come up a number of times, like what page I'm on and what type I'm on. But the big one here is this createResource. And what createResource is, is a primitive kind of like useState or createSignal. But this one is built in and designed for data fetching. Signature-wise, it looks a lot like something like SWR or React Query, which gives you an indicator of what it does.

Because what we're doing here is the first argument, again a function, is basically our query. It's a reactive expression where whenever type or page changes, we regenerate this query and then call the fetch API with that data.

00:25:00 - Anthony Campolo

Yeah. This is super interesting to me because in Redwood we have data fetching conventions, and there's data fetching conventions now in Remix and SvelteKit. Building some sort of hook to do data fetching is something lots of libraries and frameworks have now. And it's interesting to me: is there any error handling built in here? What happens if there's an error? How does the error handling work?

00:25:31 - Ryan Carniato

Yeah, to be fair, this example, and all of them, were very simplistic for my purposes of handling it.

00:25:38 - Anthony Campolo

So the createResource does not have an error-handling convention built into it? [00:25:43] - Ryan Carniato Or it does. I just didn't use it in these examples.

00:25:46 - Anthony Campolo

So I would just throw in like error and then I would have an error.

00:25:50 - Ryan Carniato

Well, there's a couple things. The resource itself has these two patterns. And this is where the complexity comes in, because the general pattern we use quite often is something called suspense boundaries and error boundaries. Those are harder to explain but easier to use, in that you just use the code as regular and if you hit an error, the error boundary will catch the error and display an alternate reality where that error is.

However, if you don't want to use the error boundary and you want to do something more fine-grained, if you go stories.error, there's the error there. Like the story, that primitive.error is the error. And there's also .loading.

00:26:34 - Anthony Campolo

Okay, that's really cool. Because if you have that stuff just kind of on hand that you can pull out easily. This is what I really like about Redwood cells, is that you have a cell and the cell literally generates a success, an error, a loading, and an empty state. It just gives that to you out of the box.

00:26:54 - Ryan Carniato

Right.

00:26:55 - Anthony Campolo

And I find that very few other data fetching conventions kind of include all of that. They usually include maybe two or three of those pieces, but never all four.

00:27:04 - Ryan Carniato

Yeah, we've been slowly extending it, but there's loading, there's error, and the question of whether it's resolved. There's some changes and updates in 1.5 to have a state field which actually has all five different states of the resource. So you can introspect it, type-safe type narrowing, all that kind of fun stuff.

But the reason we built a primitive might not seem very obvious to people at first, because a lot of these patterns usually have an async function. But because everything in Solid is about these signals that propagate in a granular way, async functions are blocking. You have to wait for them. And well, that's convenient in a certain sense because then you don't have to worry about things being undefined at different points. You'll see a bunch of question marks in here if you actually noticed. There were optional chaining operators in a few places, I think.

00:27:54 - Anthony Campolo

Yeah, right here.

00:27:55 - Ryan Carniato

It's because we don't block. We literally just go ahead and try and do as much work as possible immediately. So even with things like suspense, we don't throw and rerender because we don't rerender in Solid.

If the code loads before the data, we'll start building your DOM ahead of time with what we can. And then when the data comes in, we'll just complete it, just fill in the gaps. If the data comes before the code comes in, then no worries. When the code comes in it'll just render it. Essentially there's no worry about it. We can do as much work as soon as we can this way.

00:28:36 - Anthony Campolo

Cool. Yeah, this is very interesting. I get why this is a good real world example of Solid because you're getting into both using a router, you're getting into data fetching, you're getting into a lot of the stuff that an actual front end app is going to have to do.

It's not necessarily the best Hello World example because it's all there already, kind of for you. And so the idea I originally had is that we build this up piece by piece. But I don't think that would be particularly simple to do because of how this particular example is set up.

But what I did want to do is figure out how to migrate this to Vite. And you were saying that mostly the whole project stays the same, we have to change the index.js file. So let's dive into that and see if we can get that working. I feel like in the next half hour that shouldn't be the most impossible job.

[00:29:26] And I know that you have a Solid templates repo that includes a bunch of stuff here. And so we're going to grab the JS example in particular. So I'm gonna clone this down.

00:29:44 - Ryan Carniato

While you're doing this, one of the cool things I want to mention here is we've been talking about this and you're comparing Solid to Redwood. And I just wanted to put out there, this is just the client side. This isn't even the meta framework. This is just the client side, normal using, you could build it and host it from a CDN side of the story.

And this is why I like the primitive approach. Because moving to SolidStart, sure, there's some stuff like file-based routing and whatnot, but for the most part, it's the exact same experience. The data functions still exist and they still work in an identical way. When you resolve a route, whether on server or client, they do the same thing. You create resources and it's all the exact same pattern, whether you're doing client-side rendering, server-side rendering with client-side pickup, whether you're doing SPAs, whether it's even the same pattern doing islands. It's literally always the same.

[00:30:46] It's my belief, if you create the right primitives, you have the right foundations to kind of build upon. And it's about being adaptable to different situations rather than being too flexible.

Although I have to admit, createResource kind of breaks my cardinal rules a bit because it's the most advanced primitive. It does almost too much. But data fetching is a tricky thing, and I found that the only thing I could actually break out of it was the caching level. createResource does not handle caching, so if people want that React Query cache invalidation kind of thing, you generally build a wrapper on top of createResource in Solid.

But on the positive side, if you use createResource in Solid, it just works for your own stuff. It works with suspense, it works with error boundaries. Basically, the whole rest of the ecosystem is just going to work with you.

[00:31:41] It works with SSR. Yeah.

00:31:45 - Anthony Campolo

Yeah. Okay, so I'm going about this in the most naive way possible where I'm just copying and pasting stuff from the other project into this one.

00:31:53 - Ryan Carniato

The funniest thing is this might almost just work.

00:31:57 - Anthony Campolo

I know, right? I was like, well, he's made a couple tweaks, I'm sure, but if this can get us most of the way there, that'd be hilarious to me. So there's also some CSS here we need.

00:32:09 - Ryan Carniato

Yeah. I mean, first thing is, I don't think the starter template is going to have things like the router.

00:32:15 - Anthony Campolo

It will. Yeah, and I talked to Dan about this ahead of time. And so that'll be one thing we'll need to figure out. So I'm just getting everything into the project so I can kind of throw out the other one at a certain point. I think that's most of the important stuff. Copy pasted the index.js and the CSS. And then they'll already be in index.html.

So let's see what starts happening here. Let me first start by not actually doing any of this. Let's comment everything out so it just runs the actual base example that you would expect it to do.

00:32:53 - Ryan Carniato

Yeah. To be fair, if you didn't hook up the router and you kept the app in there, it probably should be running the base example unless we deleted something.

00:33:02 - Anthony Campolo

Yeah, no, I haven't deleted anything. So I'm only adding stuff at this point. So everything should be mostly good. And looks like you're using pnpm. Good job there.

00:33:14 - Ryan Carniato

Yeah, that was a more recent update on these templates.

00:33:18 - Anthony Campolo

Yeah, man. Oh yeah, dev. This one. Good. Yeah. All right, sweet. We're up and running there. That's good.

00:33:27 - Ryan Carniato

I love how Create React App is like... I think I forgot it was even Eleventy, or maybe not Eleventy, but a lot of this spinning logo thing is...

00:33:38 - Anthony Campolo

This is hilarious. I have not seen this Hello World example from someone who just literally takes the exact thing with a rotating logo. I love it! Oh my god, I love it.

00:33:51 - Ryan Carniato

Yeah, but what I was getting at is we're not the only ones who have done this. Create React App's opening spinning logo is almost iconic now. Yeah, it is.

00:34:01 - Anthony Campolo

Yeah. Good for them. Yeah. Okay. Let's see what happens.

00:34:06 - Ryan Carniato

So yeah, I mean right now, what's the entry look like? I guess like index.

00:34:12 - Anthony Campolo

So the entry point will be pulling in index.js. So this is where we need to figure out the... Let me post this up. Let's see what people are... People are messaging us. Let's see. Okay. Create Eleventy App. Does it rotate? It rotates.

00:34:34 - Ryan Carniato

Yeah. That's...

00:34:35 - Anthony Campolo

Oh wow. That was a while ago. All right. Good. Of course Ben hit me with the "11ty did it first." I love it, I love it. Yeah.

00:34:45 - Ryan Carniato

No, it was funny though because Eleventy often isn't really thought of like, you know, React is an interactive JavaScript framework. Eleventy's example of doing that is actually more amusing, I think, than even Solid or some other libraries doing it.

00:35:00 - Anthony Campolo

Yeah, no, it is funny actually. I spent a decent amount of time working on Slinkity, which was trying to basically take Eleventy and turn it into Astro, so I've got a deeper respect for that whole kind of paradigm shift and how hard it is to do.

00:35:15 - Ryan Carniato

Yeah. I mean, the funny thing here is, if we just circumvent the app component, I think we're almost there.

00:35:22 - Anthony Campolo

The service worker part here.

00:35:23 - Ryan Carniato

No, I mean, that's just whatever. Yeah. But if you circumvent the app part, I think comment, comment, comment, we can leave the refresh reload at the top.

00:35:36 - Anthony Campolo

But yeah, the CSS in there.

00:35:40 - Ryan Carniato

Well, though the CSS might have been coming in somewhere else.

00:35:44 - Anthony Campolo

That's true. Yeah.

00:35:45 - Ryan Carniato

How was the CSS coming in is a good question.

00:35:48 - Anthony Campolo

The CSS is coming from here. And so I had that. And then this would be the new CSS. But first let's see what we're getting here. So we need solid-router. Obviously that would be the first thing. So kind of just pnpm install this.

00:36:01 - Ryan Carniato

Yeah, I suspect you want version three because version four, like I mentioned, the APIs are different. It might be a small lift though.

00:36:10 - Anthony Campolo

Oh, like that?

00:36:13 - Ryan Carniato

Yeah. I suspect this is what you want, though it might even be two. Honestly, that example is really...

00:36:20 - Anthony Campolo

Okay, let me just do... Is it just solid-router like that?

00:36:24 - Ryan Carniato

The thing is, we've actually recently moved it, but then you'd have to change all the npm imports. It's now at solid-router. But it's fine. We can probably do this one.

00:36:35 - Anthony Campolo

This is 0.4.2.

00:36:38 - Ryan Carniato

Yeah. Sorry, when I meant version three, I meant zero three. But yeah.

00:36:42 - Anthony Campolo

Yeah, I see. Okay, so...

00:36:44 - Ryan Carniato

This will be fine. My suspicion is we'll only have to rename one thing, which is it's not useData anymore. It's...

00:36:51 - Anthony Campolo

Okay. Something happened. Interesting.

00:36:57 - Ryan Carniato

My suspicion is it's not useData anymore. It's useRouteData.

00:37:02 - Anthony Campolo

Where do I go to fix that?

00:37:05 - Ryan Carniato

Into the stories. Not that one. That one. Instead of useData, it's useRouteData. Yeah, I believe. And make sure the import matches. I think that's probably the...

00:37:22 - Anthony Campolo

Oh my God. Yeah.

00:37:26 - Ryan Carniato

Yeah. So maybe I was wrong about the CSS, but yeah, I mean...

00:37:29 - Anthony Campolo

Nice.

00:37:30 - Anthony Campolo

That was the magic right there. That was tight. Yeah. Alright, I just gotta figure out the CSS.

00:37:37 - Ryan Carniato

Yeah. So maybe it's just import in the index.js. Maybe that's all it is. Yeah.

00:37:43 - Anthony Campolo

There we go.

00:37:43 - Anthony Campolo

We're up and running.

00:37:46 - Anthony Campolo

Beautiful. It's beautiful.

00:37:49 - Ryan Carniato

Yeah. Navigate around to make sure that things work. But yeah, this looks good.

00:37:54 - Anthony Campolo

Although...

00:37:56 - Ryan Carniato

Oh, you simplified it. You removed...

00:37:57 - Anthony Campolo

Something. Yeah, I pulled...

00:37:58 - Anthony Campolo

I pulled out some stuff from the top. There's just two pages, just a new route and then the home route, because I wanted to make this as easily comprehensible as possible.

00:38:07 - Ryan Carniato

That's great in that it's more of that. The thing is, if you just have that index.html and you pointed it at index, then all the other stuff falls away, right? Whereas in the Rollup build we were doing almost the same sort of thing, but there was no index.html. So I had to come up with a special plugin. And the HTML file in the Rollup build is a string that I inject everything into. This is just so much nicer.

But it's cool how this just pretty much ports across. I mean, Vite is great because it's basically just this bundler that has so much capability built in, like CSS modules and all that stuff. You just import the CSS and it works. You didn't need... there's a certain amount of plugin capability that you don't even have to worry about. In Rollup, to set that up actually took a bunch of work.

[00:39:06] Whereas Vite is just ready to go pretty much out of the box.

00:39:13 - Anthony Campolo

I'm getting this onto a git repo. This is my epic snippet that creates and pushes a whole repo all at once. Let's see.

00:39:26 - Ryan Carniato

So what's interesting about approaching learning or looking at Solid from this kind of bird's eye view. It's not like the typical... when we teach Solid, we teach reactivity and we teach JSX. We teach the fundamentals. But coming at it from this bird's eye view, let's say like I'm a developer, I've created React apps before. I'm going to just take something...

00:39:48 - Anthony Campolo

And shove it up on the internet. Yeah, I've been trained to do that, right.

00:39:53 - Ryan Carniato

And just drop some code in, some JSX, and just kind of structurally get it to work. From that perspective, this all is like, okay, there's a few different conventions here, but this all kind of makes sense, right? You're just like, okay, put the app in, drop in the JSX, and there you go. [00:40:12] - Anthony Campolo Yeah. No. It's awesome. Let's figure out the I.

00:40:19 - Ryan Carniato

I sometimes think that's the danger with us, though, because you can get pretty far. Oh, yeah. There's another use data on the other route. Yeah.

00:40:29 - Anthony Campolo

You can get pretty far without realizing you broke something stupid, like right here.

00:40:33 - Ryan Carniato

Yeah. Well, I mean, TypeScript would get after you on that one, but also. Yeah. Where it's used, are we.

00:40:42 - Anthony Campolo

It's going to be.

00:40:43 - Ryan Carniato

Yeah, but what I was getting at is you can get pretty far.

00:40:48 - Anthony Campolo

I need TypeScript for that.

00:40:49 - Ryan Carniato

So you can get pretty far treating React or treating Solid like React built. You could be building full apps and kind of doing stuff until you realize that it's actually different. And this is kind of good.

00:41:03 - Anthony Campolo

Because it makes this now not public, it looks like.

00:41:07 - Ryan Carniato

Yes. Again.

00:41:09 - Anthony Campolo

Good.

00:41:10 - Ryan Carniato

Yeah.

00:41:14 - Anthony Campolo

But pull this.

00:41:15 - Ryan Carniato

Off. It's kind of good because you were instantly productive, and you're just like, oh yeah, this is Solid. Kind of like React. It's like React. It's Solid, you know?

But I sometimes wonder, though, because at a certain point, there's an inevitability here that you will hit the difference. And if you weren't expecting it, because at this point, have you looked at Solid stocks really much at all. [00:41:38] - Anthony Campolo I mean, I've watched a lot of streams where you and Dan walk people through lots of Solid concepts. I get the signal concepts and all this kind of stuff around reactivity. We didn't hit any of that in this stream, which I think is kind of what you're getting at here.

But I find that if I have code examples that are already working, I can do almost anything I want with it when it's in this paradigm. Because the things that are working, I know not to change, and the things that I know how to move around, I know how to move around. But that's because it was already working. I didn't have to actually create this from scratch. This example already existed.

So if I had to actually do this from scratch with an API that I wasn't familiar with, and I had to do that from the beginning to the end, yes, doing that with React versus Solid, there would be differences. There would be important differences that I would not necessarily know until I hit those issues.

[00:42:32] But then when I hit those issues, I just go to the Solid Discord and I ask for help.

00:42:36 - Ryan Carniato

There you go. Yeah, for sure. That's what I was kind of talking about.

In general, it's surprising how far you can get without actually getting into it when you approach it from this side. Sometimes I have to be careful with it because it can lead to some unexpected stuff, but I think we're going to be really good here. Yeah, it is.

00:43:07 - Anthony Campolo

This is going to work. We'll see. And you now are employed by Netlify to work on Solid. Yeah.

00:43:18 - Ryan Carniato

Yeah, yeah. The mandate is a little bit open on the open source side. I've been doing a lot of Solid, a lot of stuff. We're doing Solid, and we're really trying to push stuff out with Solid Start. I've been doing all the work around Solid core to support that. So that's what I've mostly been doing.

But I've also been able to, as you mentioned earlier, I spent a lot of time covering and learning about the new frameworks and the different approaches. Netlify has been very supportive in me continuing to help both promote those frameworks and work with them on various tasks or things that will kind of help them figure out where they need to be.

I've been spending some time vetting the new Builder.io benchmarks that Steve from.

00:44:10 - Anthony Campolo

Oh, cool. Can you talk about those actually? And also hello to Trost in the chat. I would love to know. Builder is an awesome company that is building a framework with Qwik and Qwik City. I'm trying to debug my builds at the same time.

Yeah, so talk about Builder.io and what their benchmark is.

00:44:32 - Ryan Carniato

Yeah. Okay. So Builder, if you step way back out, is basically a low-code solution for building sites. It's really easy for designers to come in and use the tools and then generate the sites they need. They have a bunch of tooling around that low code. There's something called Mitosis, which converts components from a single format into any framework. The whole idea is.

00:44:59 - Anthony Campolo

Mitosis is really interesting. Yeah.

00:45:02 - Ryan Carniato

Their whole desire here was to make it really easy for people to have a single entry point and then build the best apps they could. What Steve was having some trouble with, though, was he was doing a lot of e-commerce sites, very common with these design-heavy content type sites. He was like, the performance, they weren't getting good Lighthouse scores. This is one of those competitive edges.

So he started looking more and more into how he could get better performance. That actually started with Solid. Mitosis's original syntax was based off Solid, like the idea of using JSX as a way of converting to any component was kind of based off what we'd done with Solid because Solid was very different than React but looked similar. Over time the syntax became more like React.

What ended up happening is he realized that it wasn't just the JavaScript framework thing they needed to look at, it was loading and all that stuff.

[00:46:02] And that's how Qwik was born and how Partytown was born. The interesting thing about that is Qwik is a crazy departure on architecture in terms of how we can build apps, in terms of the way JavaScript is loaded and what work happens when the browser starts up. That's a whole amount of crazy detail, though. But the problem is, we don't know.

00:46:29 - Anthony Campolo

That.

00:46:31 - Ryan Carniato

That's awesome. I was saying we don't know the details there of what those trade-offs are like. There are the costs of lazy loading, costs of data serialization, and that resumability. There's a lot of details in there.

So he started benchmarking the various kind of meta frameworks. It was a higher level benchmark just to see what their loading times were and how long they took to hydrate. Simple examples. He's using Lighthouse and a combination of a few other tools to basically get an idea of the overhead of different frameworks. The funniest thing is, I guess he found what he was looking for because we started doing the test and I was super stoked that he had a harness because I complained that we don't have good hydration tests.

The funny thing I actually realized, because I spent a lot of time on Solid optimizing the micro, so to speak, like best, fastest string renderer, fastest thing to do an update on 10,000 tables. It's all very specific in terms of a series of benchmarks. I hadn't stopped back and tried to just hit requests against an Express server, go all the way back out.

The thing was, we found what we were measuring because most of the bottleneck and most of the expense wasn't from the UI framework. It wasn't because I know that React string rendering, or server rendering, is much, much slower than other solutions. That wasn't where we hit most of the bottleneck. It was actually, as we've been working through this, we're realizing there's just different things that happen on the server in these meta frameworks that are actually performance overheads that you don't even realize.

It wasn't actually the framework, but actually the meta framework. We can see differences between, say, Next and Gatsby or Remix or whatever, just because of these other things. As I said, it's inconclusive, maybe because we're still working on them, they're new, but there's a lot of overhead that we're not even.

00:48:34 - Anthony Campolo

There's a lot of downstream effects of architectural decisions that you don't think about. You build these frameworks and you go towards what feels nice and what feels right and what makes a nice experience. Then all of a sudden, you're two or three years into it and you're like, wait a second. There's this implication of how we built this.

Plenty of frameworks have hit this. There's no use pointing fingers because it happens to a lot of us. This is Redwood. Redwood built this entire serverless model, realized serverless functions at minimum are going to take you one to two seconds to get a response. And you're like, that's the benchmark. You're never going to be faster than that. That's a huge issue. Then you have to re-architect your entire deal to make it work.

So meta frameworks need to think about this stuff. They need to think very hard about this stuff, because you can build these bottlenecks in very, very easily.

00:49:25 - Ryan Carniato

And when you take a performance approach at the beginning, it's a lot easier to get there. I think that's why they're building these right now. Qwik has just started on Qwik City and they're like, we've added the base features we want. Let's see what the performance indications are of those. It's already helped for them because their SSR was actually slow enough that it was noticeable in these benchmarks. So they moved off to DOM and moved to string rendering on the server. As I said, that wasn't the biggest overhead.

00:49:59 - Anthony Campolo

Redwood doesn't even have SSR, so we still don't even have SSR, right?

00:50:05 - Ryan Carniato

So don't get me wrong, SSG also will remove that, but even the WAV files are served compression. There's a lot of stuff in there that we haven't been measuring, so we don't even have an indicator on.

I'm super stoked that that work is being done here. That's why I'm spending time here, because I want to do some benchmarking myself, more on the hydration side. But just coming in and seeing his benchmark from playing with it, I already found several bottlenecks in Solid. Like I mentioned, it wasn't the rendering, but I was like, oh my, the way we insert assets in the head of the document was really slow. Using a benchmark actually helped me see that.

So it's kind of funny how little, almost tertiary stuff can make such an impact on these kind of things. As I said, it's hard because when you make benchmarks you end up chasing the benchmarks, and that's not the only benchmark to go by.

[00:50:57] But on the other hand, when you have no way of measuring, other than just some arbitrary Lighthouse score you do on a PageSpeed Insight, there's very little you can necessarily do with that. I'm super stoked at the potential of at least having more measurements and more places to see where we can make improvements.

00:51:19 - Anthony Campolo

Yeah, definitely. So drop us some links in the chat here for your Twitter, which is just Ryan Carniato. And then we've got solidjs.com. Any other places you want to direct our viewers here to learn more about Solid or your own work?

00:51:33 - Ryan Carniato

Yeah, those are both really good. I'm thinking here, the website has a link to the Discord, the GitHub, all the important stuff for Solid's community. Great.

00:51:42 - Anthony Campolo

Discord. Awesome Discord.

00:51:44 - Ryan Carniato

Thank you. We try our best. It's an interesting place. A lot of different people with a lot of, as I've mentioned before, framework authors and people working on other projects kind of sitting in there and debating the different elements.

It sometimes gets kind of crazy often, where somebody's like, this CSS and JS solution compared to this one, and then they'll both go off or something and they'll come back. Then two people have created two new libraries to show how they could picture doing it. I'm very proud and stoked about having that kind of open discourse where people aren't afraid to tell me that they're like, Solid is not very good here. I'm like, okay, well, let's talk about it. So that's cool.

00:52:31 - Anthony Campolo

Well, thank you so much for being here, Ryan. This was a ton of fun. And just thank you for being an open resource to people who are interested in open source or frameworks or anything like that.

There's been times where I've written articles that have referenced your work and I've sent those to you and you've given me notes on them. Stuff like that is just, I'm so thankful for that. So I really appreciate all the work you do. I think you're a really fantastic mentor just in the community.

I'm super stoked you got hired by Netlify. You get to work on more open source stuff there. So I think it's just all up and to the right for Ryan and Solid right now. I'm very, very happy to see it.

00:53:06 - Ryan Carniato

Yeah. No, thank you so much. It's been amazing. Honestly, anyone who spends the time to teach people, it's such an important part of what we do. I am more than willing to help or provide insight, because there is a certain amount of knowledge that comes within our profession.

As much as we do a lot of effort to lower the bar and all that, it's still there, and it's critical that we continue to find better ways to be able to explain these topics and concepts so that they're reachable by anyone.

00:53:40 - Anthony Campolo

Yeah, definitely. And that's the mission of this stream, so I think that's a good place to end off here. Thank you, everyone who's in the chat who is hanging out. Had a lot of great friends here watching along.

This should be a weekly thing every Monday. I may bump this back an hour because I'm beefing with Ginger Node right now in terms of we have a similar stream time, so I might do this an hour later next week. But Monday mornings is when I would like to do this, Monday morning kind of lunch time for all you out there in America and hopefully people in other parts of the world as well.

This will close out for us. This is AJC and the Web Devs episode two. Come back next week for possibly a solo stream. Then we got Travis on board for episode four, so bedrock layouts, CSS, that'll be coming at you. That'll be three weeks from now, I think. So I'm taking a week off, but that'll all be in the Twitter.

[00:54:35] So thank you so much, Ryan, for being here. And we're going to close off here.

00:54:39 - Ryan Carniato

Perfect. Thanks for having me. It was a lot of fun.

On this pageJump to section