It’s a more opinionated framework to make it easier to do server rendered applications with solid, really to make it easier to make any sort of application with solid. Today isn’t gonna be an introduction to , though. But it does build on my learnings from working on it for the past six years.
If you aren’t super familiar with , that’s okay. All you need to know is that it, it introduces using reactive primitives to rethink the component model, popularized widely by react and dominates most frameworks in the ecosystem in the last decade or so. The key takeaway is that for [00:01:00] all the good component architectures abroad, and I mean they are everywhere.
In modern front-end development, we’ve conflated code organization with execution life cycles in pretty much every framework. Components have runtime considerations. They are a primary state. Our renderer really are everything. And that isn’t limited to the virtual dom. It’s true for compiled solutions as non-com compiled tag template literals to virtual doms, single file components for the hottest DSLs, everything kind of running top down.
And I get there’s a bit of who cares? , it informs every subsequent question what do I memorize? When do I memorize? What do I use for global state? How do I share reactivity between files? When to use effect? What’s the difference between reux and context? Why does this log twice?
Why does this stupid thing keep rebranding? These are topics that dominate the conversation. And really I’d rather be talking about pretty much anything else. There are a lot of things that are just unlocked when you change your perspective a little bit. [00:02:00] Now, I could wax poetic about the power of reactivity.
There’s a different recalibration going on, and that is around the role of the browsing the server and how we build applications. To appreciate this, we need to look back at our history. From my perspective, the history of web development has been a game of hot potato to see. Who’s left holding the state?
The web started on the backend. We served static HTML files from File Server on request. Soon these pages became more dynamic and generated via code on these requests. And state was owned by the server. Change of piece of ui. The whole page reloads. [00:03:00] These days. We call this approach multiage. Apps are MPA for short, but nothing’s more distinctive to me of this time than going to a travel booking.
I’m talking about things like templating, business logic in ui. , I don’t know how many of you had the pleasure of layering your front end logic on top of Ruby’s erb templates, but I have, here’s a little knockout js. On top of erb. You can see the duplication. And honestly, this approach is still around today in form of things like alpine js and petite view.
With an api. In many ways this was a drastic simplification. Client owned state communicates with a stateless backend. We could author UI in a single code base,
Let’s server render it initially. Get the fast page and the benefits of our single page app. And that basically brings us to today Next.js, Nuxt, SvelteKit, Remix. Like I’ve already mentioned, for the most part, the authoring experience stays the same as it did with client rendering, but [00:05:00] now everything is isomorphic.
It runs both in the browser and the server, and this has largely been seen as the pinnacle of WebDev for the past seven to eight years. However, during the same period, I’d be remiss not to mention a different model developed. And that was pioneered by eBay’s Marko Framework as early as 2014.
The negative is we are back to full page loads and most frameworks don’t have a means to support this.
The truth is, the numbers I’m showing on the screen are from 2017 and things have only grown since.
I am sure what you’re thinking is, aren’t there ways to address this? What about code splitting? What about streaming responses? The ladder actually probably helps MPAs more than s spas, as now they can respond immediately on navigation instead of waiting for data while still giving nice loading indicator feel.
What can be sent to the browser [00:07:00] shall be sent to the browser. That’s the adjustment we need to think about. So we have two solutions that benefits over each other, but don’t do everything we want in one package. Do we go with a better page load at the cost of future navigation, or do we go with our slower?
Loading isomorphic approaches that feel more apt, like after initial load. Can we somehow do both? Does that even make sense? What I’ve actually noticed is server and client-centric approaches almost mirror each other. In a client-centric approach, the vast majority of your app is believed to be isomorphic.
And we define patterns to denote things like that are only server only things like get server side props or loaders in a server centric approach like islands, we do the opposite and denote the code that is required to be ran on the client. To be at interactive, each starts with a different base assumptions and comes at the problem from the opposite.
Of course, we can do this in a very solid way. If you are already use solid, what you’ll find is that we aren’t introducing a new router or new libraries. It’s all the ones already in the ecosystem. We are building upon what’s already there and providing tools that can help every library in our ecosystem feel like it’s first.
As you can imagine, that means this is all about primitives.
We want things like get cide props in next or loaders like remix, but we didn’t want to compromise and we want to keep the benefits. We have come to desire from being modular and composable. The pattern solid for the past several years has been to define data functions that attach to each nested route section, and it runs in parallel to code [00:09:00] splitting while setting up our resources for data fetching.
It doesn’t care whether it is on the server or the browser. It runs the same way. If left alone, it will fetch on the server during initial s r, and then on the browser and subsequent navigation. That’s what we have here. If we’re exporting this route data function, it creates a resource, which is basically a reactive primitive that will fetch the data from that URL and put it in our story signal.
But what if I want to always fetch on the server? We had an idea what, if any function could be ran on the. , right? We immediately saw that this meant we could preserve types across the boundary. And this is really quite nice. All we’d have to do is wrap it in the server function. And this way we could tell the library that, Hey, the code inside this function always runs on the server.
And the thing is, if you still want a url, it’s [00:10:00] available. still as a property on that function. So we’ve used this, the design, interesting APIs. We’ve used this with web sockets or server scent events. But the takeaway is suddenly we had a primitive to do network communication in a type safe way.
So it turns out we can just plug this into our resource and while suddenly we have a function that always runs on the server, see server fetch story. Now that could hit the database directly. And we can write a wrapper to clean it up a bit. And we’re in business a little bulkier than maybe a simple async function.
We get to have the cool things like invalidation by key so we can granular, invalidate these things the same way we would in libraries like TanStack Query,
and. Speaking of TanStack Query, the community has already jumped into using our PIBs Solids Port of TanStack Query uses our resources under the hood, which means suspense, streaming, [00:11:00] hydration, and even server functions. All just work out of the box with zero configuration picture. Just drop into create, query, call and querying your database your component.
That’s what you can do with this approach.
This all just piles on top of each other. You can define as many of these actions as you’d want in a file as they’re just server functions and don’t feel that restriction having adhered to a file-based a p I for local mutations or worrying about over re fetching on invalid. , we took, a lot of the ideas have come up with loaders and actions and data fetching and almost, and some [00:12:00] inspiration from things like GraphQL, of separating the concept of mutations as RPCs versus loaders being like the graph or the page structure.
But let me show you an example of this in action. I’ve remade our classic todo nbc, and this is a very simple example. It, it is just all in one file. Just for our sake here, because it’s funny the simple examples are almost always the. The they’re reused over time for a reason.
They handle a lot of really basic use cases. So I’m just gonna fire this up here. So we can see this, I’m gonna be using not dev mode mostly today because I want to focus on size and performance. But let me see if I can get to do mdg. So do, excuse me if there’s sometimes longer build.
but he, here we go. This is a solid start app. We have our route where we kinda come in, of set up, with a HTML structure, suspends boundaries, [00:13:00] routes, and then there’s a file routes that indicates this is where in the route structure you want to inject the file system running. You could always just not use the file system running.
I just wanted show this and in our routes folder, our main index here is just our to-do. We are exporting a route data, and as I showed before, it’s just a server data that calls our database to-dos with an initial value here, right? So just sets an empty list while, suspense is loading.
But generally speaking, we’ve defined our data. And then when we go into our to-do app, we use route data to get those, the set of to-dos. We use the location to get the location from the router. And then what you’re gonna see here is a bunch of these server. and these are all just the typical verbs. You see when doing a create to do a to do NBC app, adding, to do, removing to do toggling to-dos.
And we’ve used those actions both to do calculations like the remaining count where we use them to looking at the pending to show optimistic [00:14:00] updates. And they also are used as forms. So here we wrap a few inputs. Maybe a hidden input to pass, some special information through. But essentially this is made off a bunch of forms that are exported from those actions.
And in fact, we even can nest actions inside each list item. We also have actions for toggling the to-dos and editing them and how the show the pending state. What do I mean by pending state? Let me show you here. Here’s our to-do NBC application. Okay. And this is pretty typical. I’m just gonna add a to-do.
Hello, and it probably happened a little bit fast. I do have a slowdown here, but before it toggles, you’ll see it flash purple for a second before it turns gray. This is showing the optimistic updates and we can run as many of these as we want in parallel, and race conditions and stuff are automatically handled for us, and this has this kind of nicety here of being able to [00:15:00] seamlessly work and handle this mutation story.
and nice interaction points. And what’s cool about this approach is so it’s taken into consider [00:16:00] things like that. Some actions are multi umit versus single submit. So you might see stuff like up here, create server multi actions. And this is really powerful cuz now we get an array and this means that while the main list is shown as a for loop, while we’re pending, we can iterate over that array.
Of pending actions and basically feed that form data back through and draw that optimistic api, and each submission has its own error. State. Has its own submission state, and this way we can granularly handle errors and submissions and race conditions all automatically with these permits. Of course, if you don’t like using forms, don’t care about progressive enhancement.
Don’t worry about it. The ad the like. This here that’s returned. The add to do or removed to do is also just a function you can call. It’s just a server function. The form is just kinda nice, add-on. So we can do progressive enhancement, but you can always just call add to do directly, not use forms and do everything the way you’d want to [00:17:00] otherwise.
All right. Sorry, it’s this way. So that’s all fine and good, but what you might be asking, what about service centric view of things? Nothing you’ve seen so far. Is that different than other frameworks? Except maybe a focus on primitives. The fact that you could literally just slide in, solid query from TanStackand it will work first class with, server functions.
I have good news on that front as well. I wanna share with something that we’ve been working on. It’s still experimental, but I think it’s something that worth getting excited about. I’m gonna use a demo app that I’m all too familiar with. Hacker News. Again, this is a classic example. There’s a reason why we keep on going to these classics.
Hacker News PWA was a site that collected hacker news implementations in every framework. It’s no longer really maintained and most links are dead. But I myself have gone and taken old View two version and remade it in every framework pretty much that I can find. And so it’s kinda like the perfect example, the demo.
What I want to show here [00:18:00] today. Okay, so I’m gonna go back to our code, sorry, not that way. And we’re going to take a look at our Hacker News example. And this one’s a little bit more complicated, but all that happens now is we have three routes. We have a route where we grab all the stories. And you can see we’ve of fetched based on the query parameter and we create a resource for that or the user and the individual stories.
I’m just going to what is it? I’m just going to build
and start this app so we can just look around and you can see what we’re dealing with. Okay. All right. So done with that refresh. Okay, so here we go. Hacker news example, listing of stories navigate based on pages. [00:19:00] Different story types. Click into story. See it, there’s some comments. These comments are collapsible.
So there’s minimal interaction with this page. There isn’t like heavy mutations like TodoMVC but you can see data fetching patterns. You can see interactivity, and that’s why people look at this example. And if you’re wondering, like this is pretty typical kind of scenario for these kind of frameworks.
You know this is perfectly fine. We made things small fast, relatively, you could be pretty happy with this. And what you’ll see is a pretty typical thing with this is in your framework is you’ll see all the like index, I think it’s called Next data. You’ll see this big blob of json, which [00:20:00] contains all the story information here for the comments and stuff so that we can hydrate it, so that we can get that interactivity so we can collapse those comment.
This is pretty, pretty typical stuff. I’m just refresh on this page to make sure I’ve got everything. Yeah, perfect. But what can we do with a server centric view? How does this change? Something that we’ve been playing with was we, I worked on Marko at eBay, which I mentioned had these islands and things like Astro and Fresh have been popularizing them.
So what we can do is we can break our toggle out from our comment component. So if you, just to kinda get the flow for this so you understand when you load a story, it shows the information about the story. And then he goes through each [00:21:00] story and shows all the comments, but each comment recursively can have its own comments in four loops and, but they’re toggle bulls.
So what we did was we wrapped each branch of comment components, it’s recursive comment and comment with a toggle component to extract out the state here. So what’s a toggle component? It just has a signal, which is re solids reactivity to open and close it. And then all we do is update some classes based on the, that signal state.
Pretty simple. And then we insert the props children, which is a child list of. Comments, but now we want this component to be an island. So what we ended up doing, and this API will change, this is experimental right now, is we’re like, okay, let’s just do this. Cons. Toggle equals unstable island.
Import, let’s import from toggle. So this is. Let’s just do this. As I said, this is not gonna be the final api, but I just wanna show [00:22:00] now our toggle is imported as an island, and with that and setting it to islands true, we should be able to just build our example again and start, and we’re gonna see a little bit of a different story happen when we refreshed the.
So service-centric here showed you the client-centric approach. You can kinda see the world’s kind of combining, all right, sorry, this way. But as cool as that is, they have the ability of MPAs or S spas that we each bring fully optimized for the use case. About a year ago, I realized we could do.
What if we didn’t need to choose? I realized that combining three existing technologies, we could get it all. And those technologies are nested routing, which as I said, we’ve been using for years now. Pretty much since Solid was first created Islands, which I just showed you, and [00:24:00] HTML over api, something popularized by turbo.
But also thanks to our good friends over at Astro have been playing with their HMR solution. See, the realization struck that I noticed what happens when we combine these technologies and change the size of our islands. . The trick to island’s savings is that you only need to serialize the data that’s passed down as props, which is why we didn’t need to serialize all that comments data, because technically speaking, the only data we needed to we didn’t need to pass that in as props.
The toggle component had no props. So typically with this architecture, as you navigate, you’d be just sending, HTML over the wire for the page and the json for the props. So picture something li like what I just showed you, but it s renders each page. But what if the whole nested section, like what if the island actually took up the whole page?
There’s a small router that you need on the MPA side, but on the single page app side, if you actually treat it like a single page app, Your server rendering basically just turns into JSON APIs like you do today. You don’t need two modes or switch, it’s a continuous range. You just use what makes sense for the application.
And for me, this is a game changer. So we built it, we were like, okay, let’s add a nested router that does server rendering as well. And the cool thing is you just go islands, right? Or true. Our current. Islands are already have everything you need, right? You have to attack this from a server centric view if you want to get the full benefits.
But what’s cool [00:26:00] about this is, look, I’m gonna refresh and yeah, clearly this still works and clearly we don’t need that script tag anymore and serialization. But the difference now is watch, this is not spinning up. This is full client side navigation here, right? as we move around, go through these stories, do this stuff.
but I think this is actually best exemplified in another app. And I want, if you all check it out sometime solid dash movies. Dot app. We remade the TA taste movies demo, which is really cool. They have demos in every framework. Next Angular Nuxt Astro [00:27:00] Solid, which is this one SvelteKit Lit quick. And what’s really cool about this demo, We built this on the same technology.
You can see all the interaction. You can see this. This feels like a single page app. In fact, you’d be pretty hard to tell the difference between this version. Oh, this one seems to be down, my bad. And I was gonna say in the next version. Okay. But es essentially you, you can navigate, you can search, you can, what was it?
and I think that’s really cool.[00:28:00]
And just to emphasize how big of a of a thing this is, I read those demos I showed you at Taste Movie app, navigating you around a few pages. This is the kind of size 190 kilobytes, 90 kilobytes from next 121. Even spell kit is about 34 kilobytes and that’s probably where SA start would be.
Normally this approach is. Whole different dimension on reducing size well without losing those benefits that we’ve come to love from single page apps. Anyway, I think that’s pretty cool. If you wanna get started with solid start yourself. You can just run m p m and Knit solid at latest and you’re ready to go and you’ll be o on your way to creating the next generation of solid websites and applic.
Brian Rinaldi: [00:29:00] Ryan. Oh my gosh that was, that. You got my mind spinning. I’m like, I’m not sure. I a hundred percent got everything, but I like, I, I. I’m impressed by what I saw. So I got some questions, but I think Pete some folks in the audience I’m sure must have questions. So one, one question from the audience was sell the start V1 and stable items.
When are these, when do you expect these to be fully released?
Ryan Carniato: Yeah. And those are two different initiatives. I’m gonna be clear v. In my scope of things, at least today, I don’t wanna pull the island stuff in because I don’t want to delay it further needs to right now the state of V1 is, we have mostly API APIs and the beta launch.
Right now we’re just, we’re working on stabilization. This is just the part where we are working with all the adapters. That’s where we’re having the pain. This doesn’t work on herself, this doesn’t work on netlify, and we’re just, going through like, how do you do this in CloudFlare? I’m not gonna make any promises here.
If you’ve seen any of the other meta frameworks, this stuff takes a long time and every time someone tries to make a promise here, they’re usually months [00:30:00] off. So I’m not gonna give that to you. Unfortunately, right now we are just going through a stabilization period and I’m hoping that it will not take too long, but it really comes down to How much feedback and how much, we can work through stuff with the community.
Brian Rinaldi: Sure. Makes sense. And so just to clarify for, cause I haven’t tried solid yet, or I obviously solid starts new So is solid start does, is it fully s sr like a remix model or is it like some combo like Astros, like especially now with Astro two can mix static and ssr? Are we So you’re fully sr, right?
Ryan Carniato: Yeah, I, there’s a static adapter. The funny thing about these libraries that they can, a lot of them can do a lot of the same things, but they’re preconfigured to work a certain way, right? Like the Astro is an MPA framework and it does, it’s really good set up for STA static, but you could always like stick a full single page app on an astro page if you want to.
Solid [00:31:00] is much more on the spell kit remix side of things where it’s configured to set up to build applications. And in our case, like fki, we have the option to say, Hey, let’s do a static page or whatnot. But Yeah, I’d say we’re more on the felt kit remix side of the things. Okay.
Brian Rinaldi: That makes sense.
So can do static, but it would, it’s probably like a all or nothing I’m assuming, or,
Ryan Carniato: yeah, that’s generally the approach we’ve taken to date. I, we have talked about doing it on a page level, but as you can see, I’m very interested on. How things can scale without having modes or switches, like just simply on what you write.
So w I will say for V1 it will be just per page level. Similar to S kit. . Okay,
Brian Rinaldi: that makes sense. So let me ask you like this approach you talked about at the end and where it’s like the feel of an S p a, but the benefit of an MPA M p A in terms of like how it’s rendered and stuff is this an approach you think is, it’s like can be universally applied or is this, are there specific scenarios where this works [00:32:00] or it doesn’t work? Or is that something you still
Ryan Carniato: experiment? My hope, yeah. My hope is that this can be universally applied. And obviously even working beyond frameworks like solid. It’s a tr tricky thing. My biggest concern right now is actually developer experience concerns.
I think that it’s hard to know the boundaries between server and client if it’s not handled right and when you’re dis, I showed in this example, like I literally switched the modes by just like toggling a switch or like changing something and all the existing code works. That seems really good in theory, but it gets confusing as you scale things.
So that’s the largest reason why I’ve kept that in experimental because. I think the place we need to figure out next for this is how to make that experience really feel natural and not confusing. And, but yeah, so I, that’s why it’s where it is, if that makes any sense. But in general I’m very hopeful as I was pointing out that this actually.
Scales across the whole spectrum. There’s a little bit of overhead that comes with doing it over a [00:33:00] pure MPA islands approach, but it’s like fractions of kilobytes, so to speak. Like it’s not a huge thing on size. There is some consideration that certain types of components now become islands that went before, things like anchors, cuz you need to, update the style of an anchor selected where an M P A.
It, you wouldn’t need that. So there are considerations, but I think that like it covers the 90% range so well that this could be the future. Yeah.
Brian Rinaldi: Okay. That makes sense. And, but and you’re getting a lot of yeah, people understand the DX concerns. I know for myself, like even from a simplistic standpoint I’m often like, sometimes this isn’t working and I’m looking for the error in the wrong place.
And it’s because, oh, that’s right. That one’s on the server, not on the client. And it’s not always like that obvious where that’s where that script is running. Yeah. So I totally get.
Ryan Carniato: Yeah, and this is gonna be something that we have to consider across the whole ecosystem for the next couple years.
The, you’re, this is the challenge on the DX side for everything [00:34:00] honestly, the, you’re suddenly like aware of certain, it’s not just the boundaries of where the code runs, but boundaries on data serialization. Like what needs to be serializable over the wire and what doesn’t. You could try and hide that, but then you’re gonna get hit some point.
You and I think that’s, That has now entered our mindset and we need to figure out a way to com combat this complexity or otherwise. Developers are not gonna adopt this.
Brian Rinaldi: Makes sense. And do you, are you all exploring cause I know one of the things remix pushes is okay we do a lot of this rendering at the edge kind of thing.
Is that, I’m assuming this would be entirely possible with this.
Ryan Carniato: Yeah. I didn’t even talk about this. Solid has been on the solid start, started on the edge. We made our first demo on CloudFlare Workers March, 2021 with streaming from the. If you’ve recently seen that defer feature that remix has that’s something that we’ve had from Sol with solid start, right from the creation that was like offset it was it, this is how one of the things that Marko introduced back in 2014 and we I immediately was like, yes, we need [00:35:00] out of order streaming.
We need to be able to deploy to the edge. So yeah. As of today, solids supports Edge on CloudFlare, on Netlify, on Versace. Y Yeah, yeah, I, if people follow me, you though, I’ve been jumping in on that one for sale released next 12 a year ago, within 24 hours we had streaming solid to start on the edge.
That’s what it, that’s what I’m all about here. Yeah. And
Brian Rinaldi: it’s really interesting cuz here we are there at a, what’s basically a JAMstack conference, right? And I was thinking back it wasn’t too long ago, we were really. Almost entirely in static with some client side, interactivity and maybe some hydration, but seems like now we’re moving, A lot of frameworks are moving to where it’s only an s r solution.
I, I know Enhance, which will be talked about later today. That’s their approach as well, and something they’ve pushed as, Do you think is that, do you think this is headed in general? We’re gonna be, we’re we’ve now dropped, Okay. There’s not a lot of benefit to pushing stuff, to pre rendering stuff.
We’re just gonna go with server
Ryan Carniato: ending. [00:36:00] It’s a challenge because here, there’s two things going on. We obviously, the interactivity and the expectations of interactivity in our applications have gone up over time. And as a result, single page apps have gone bigger and more bloated, and that’s been the whole problem.
And no one wants to sacrifice that. At the same time, we all recognize, as I was mentioning, like if you build with that mentality, you’re just gonna have the whole, you’re gonna pull the whole in, internet onto your webpage and. We know that we have to delegate more to the server and we have to change that balance.
That’s what we’ve been doing. But now you’ve got this push happening on both sides, right? Because the, those complicated front ends are like, no server do more stuff. Like something has to give. And the timing with edge functions is just great because now we’re bringing that processing, closer to the end user.
And I think that this is why you’re seeing it. It’s just. Some of that demand and expectation that we were like it’s okay. We can do that in the browser. We’re like saying, no, it’s not okay. Don’t do that in the browser. So it’s just natural that you are gonna have more stuff running [00:37:00] on these server list environments compared to, maybe a couple years ago.
That being said this is why. The net Laies and Versace and everyone in the world are so focused on cashing solutions and stuff at the edge, cuz there’s still a cost going back to your data centers. This whole world is now, instead of looking at a CDN as a single, like here’s your static files.
It’s looking at even parts of individual pages as like static chunks that can be stitched together. That’s the world we’re heading into.
Brian Rinaldi: Yeah, I think that makes sense. And I think, it’s good. It’s, it becomes really difficult to even think about this mentally when you’re like, some things are rendering, where is, are, is my rendering happening?
Where is my data coming from? Where is and how much. This is where I get into the edges. I’m a firm believer in the edge, but it’s adds a whole layer of complexity to your application development when you’re thinking about, like, when you’re trying to think about, okay, it doesn’t immediately solve latency.
If I’m trying, if I’m then going, having to go back three [00:38:00] times. To, to my, server to get data kinda thing, yeah.
Ryan Carniato: It’s amusing to me, and I’ll ex I’ll explain why if I got a second. It’s that. Yeah. The rise of single page apps came up around the same times and the rise of microservices and, wanted to give like stateless, and these things aligned and that kind of like really went hand in hand and.
Now we’re seeing a return. People are like, oh, that’s too complicated. I need monoliths. But we know that we still need to solve the distribution problem, so to speak. So my, my expectation here is you’re gonna see more and more tooling that lets people author as monoliths, but then handles the distribution details in the background for them.
Semi-automated or half manual or whatever. But that’s where the, you’re gonna see the development in this space because as I said, the pressure’s kind of pushing from all sides. And it’s getting compressed right around these serverless and edge technologies.
Brian Rinaldi: Yeah. And I’d say like my, the last thing I mentioned, not really a question, but it’s just I think it’s funny because I’ve been doing this super.
Long time of 20 something years and it’s[00:39:00] I’ve gone from okay, we’re doing everything on the server to none. Let’s push everything to the client. And it’s no, this is not working. Let’s push it back to the server. Back to the client. It’s just like a continuous continuum, as a back and forth as technologies.
Change and we can we adjust our expectations. But anyway it’s fun. It’s fun
Ryan Carniato: to watch. Yeah. Hot potato. Who’s left holding the bag? I don’t know. It’s some of it, some we take it on by choice because new opportunities always emerge every time we move the, move this around. So yeah, I think it’s exciting cuz each iteration gets a little bit better, gets a little bit more, Nuanced gets a little bit more powerful, and of course that opens up new possibilities, which send us back to the drawing board a few years later.
So yeah it’s really exciting to see this evolve over time as myself, also a very long time person in web dev.