Qwik + Astro perf on perf on perf
Links & Resources
Click to toggle the visibility of the transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, friends. Welcome back to another episode of Learn with Jason. And today on the show, we're bringing back Steve. How are you doing?
STEVE: I'm doing great. How are you, Jason?
JASON: I'm doing so good. I'm so happy you're here. I'm excited for a lot of reasons. I've loved watching your content, you have good short format comment on getting better at code. You're building cool stuff over at Builder and doing interesting stuff with Qwik. And before I get this all wrong, why don't you give us some details on what you are, what you do?
STEVE: Yeah, co-founder of a company, Builder.io, and we do Figma and with the code and pump out the APIs to your website. Take it to the home page, publish, boom, and get off the backlogs. Marketing wants a change, marketing can do the change. That's the idea. We make cool open source projects. Obsessed with how to build and deliver amazing web experiences, easy to build, et cetera. And it can be integrations like Figma, building with Qwik, building with Astro, party town, mitosis. It's hard as a startup to do all the things, but we do our best.
JASON: Yes, absolutely. And it seems like you're doing a pretty good job. Everything that comes out feels quality. Especially there's been a lot of hype around the Qwik stuff. And I think for good reason. Like the Qwik stuff introduced something that I have never seen before, the concept of resumability. So, if other folks are like me and this was a brand new term, do you want to give us a quick overview what have resumability is?
STEVE: Yes, totally. For really brief background, the way that I came about to pairing with Misko and saying, oh my goodness, Qwik is incredible and we're investing significantly in. We made this builder platform, this way to make a visual editor, pump it out to code, whatever framework you have. Whatever we see is people see a drag and drop GUI editor, people compare it to legacy things like Microsoft Front Page, modern things, web server or Wix, but that's going generate poor-performed code. Buggy or ugly, it's gonna hurt my site performance. I'm a developer, I need to manage that by hand. We are proud, drag and drop, make something. But then crunch it down to be highly-optimal code. But what people were doing, going to our website, content generated from the platform and, oh, you know, this is a 40 in Google PageSpeed Insights. And why is your site not faster? Why is our site not faster? Why is nobody fast? It's a decent scale, not your personal blog or something. This is silly. It was a React site, using Next.js or similar, well, we could ask for any plugin. We plugged Vue, we plugged in SolidJS, Angular, Svelte, all the things, and the same content written to the Canonical code of the frameworks. The best was with SolidJS. It was 45. It was still not that much higher. Where is the hundred or 90?
JASON: Right. And to put a very fine point on this, one of the big challenges with hydration, you are putting all of the data, every word in the site comes in the pre-rendered HTML that is static. And also if you look down at the bottom of the rendered markup, there's a script tag that has got this giant JSON object that duplicates all that have data. You're doubling the size of all of the content on your page just by virtue of doing this hydration. Which seems trivial until it's not. Then it's really not trivial. This was the thing -- there was that big thing about a government site where they leaked everybody's Social Security numbers because they didn't understand how hydration worked. And in their static builder, they had loaded everybody's data. And then they only rendered the data they needed on the page, but all of the data went in that JSON blob. Somebody viewed source and started copy-pasting out people's identities. It's one of those things that it's sneaky. But man does it add a ton of weight to a page that has to then be parsed and rehydrated and all of those things. So, anyways, I interrupted you. But I feel like that's an easy one to forget if you have never actually viewed the source of one of these hydrated pages.
STEVE: Yes. 100%.
JASON: Amazing. So, this is very, very exciting. So, I have questions about this. And I think I'm gonna try to stick to just a couple questions because I want to spend a lot of time building. But I am very curious like was this hard? Like did this require -- because it bends my brain trying to think about how you would do there. How did you implement this in practice?
STEVE: Don't get me started on that, we thought we needed an acronym for the Qwik something, something. Just don't. Don't make an acronym. Invent a word if you have to, "resumable," but don't make an acronym.
STEVE: Yes, one more.
JASON: Let's do it.
STEVE: One more metaphor to share how this works. I didn't go into the details of where the concept of resumability comes from.
JASON: Have you seen the movie memento? He has to look at the notes and has important facts tattooed on his body so he can figure out what he's supposed to be doing.
JASON: That. If you have seen memento, that's replayability.
STEVE: It looks at Google Analytics for your site and looks at what the user paths are. And based on that, it will do start prefetching. Most people go from your home page to your product page, prefetch that immediately, it's ready, lightning fast. Much smarter than what we do today. If this link is visible on the page, the menu has a hundred links. What do people click on? With Qwik, you can plug in a similar mechanism and on a granular basis, and most people hit this page, it's pre-streamed. I'll stop rambling about cool stuff and we can dive in and learn together.
JASON: I saw a question that I think is good. Astro does page transitions and things. Does Qwik work with view transitions and things like that? It seems like the answer is yes.
JASON: For anybody who wants a one on one how Qwik works, we have had Misko on several times. Actually, why don't I take us over into this view here. And I will actually just pull up a couple links here. So, let's look at the site. It you go to Learn with Jason, hit command K and search for Qwik, you are gonna find concern here is something on Qwik City, the framework for building with Qwik. Intro to Qwik here, update on Qwik 1.0. And after -- as soon as Steve and I go offline, this one will be available to watch on demand. Lots of Qwik content here on the Learn with Jason site. You can make sure that you go and check that out. And then we are talking to Steve. So, this is Steve's Twitter profile. You can go and do a follow there. We've got the Qwik home page. If you want to go and get those details. Here is Astro. Which we're gonna be doing the combination. And then over here, I've got this page on how to integrate Astro and Qwik on the Qwik docs. What else? What am I -- all right. At this point, I have -- I think links to things. But I'm not sure how to get started outside of just saying, Steve, what do I do next?
STEVE: Yes. Yeah. Let's find the right doc for you. So, in this case, I think this is the right one. So, scroll down on this page a little bit. We will need an Astro project and then, yeah, we'll follow the installation which is really just two steps.
JASON: Got it.
STEVE: First is create from the Astro docs.
JASON: And npm Astro, latest, if I can get my keyboard to push the right keys.
STEVE: I love Houston.
JASON: Houston is such a good idea. All right. And so, we are going to call this one... Qwik-Astro-perf. And should I -- do you want me to keep any files or go empty?
STEVE: It's up to you, either works.
JASON: Let's go empty, keep it simple. Write TypeScript, new, newer repository, yeah.
STEVE: I love that you use Twitter instead of X. I have been hard core using Twitter instead of X. Everybody gave grief -- I went back, not saying X. I appreciate that.
JASON: I will call it X when they make it good again.
STEVE: When it's good again. I will join that pact. 100%.
JASON: Like, I know I'm being grumpy about this. But also like, that was -- it was my favorite place and now it's sad.
JASON: Okay. So, here we go. We're in this -- I'm not gonna do that right now. Let's close that up. And all right, I've got my site. So, this is a bog standard Astro site. All we have in here, let me make this a little bit bigger so we can see what's going on. I'm gonna close this down. This is basically all we've got. We've got our Astro config, empty, package JSON, the bare basics to make Astro work. And we have this one Astro file which has no Astro features in it outside of sharing what version of Astro you're using where you publish the site. From here, I want to add Qwik.
JASON: Keep this open. And looks like we got some deals here. I saw Elian from the Astro team was saying that there's even an Astro command for this.
STEVE: Oh, is there?
JASON: This is it right here. Npm Astro.
JASON: Here we go. I'm gonna grab it. And this is my -- this is my favorite thing about Astro. I think this is so clever. So, I've gone to add this. And it says: Do you want to install all the dependencies? So, not just the Qwik Dev thing, but like, hey, we need builder Qwik, we need the right version of TypeScript. Okay. Great. Yeah, let me install. Do you want to update your config? Here is the code we're gonna add. God, this is just a good experience. Now if we go out and look here and open up my config. We're done. It's in there.
JASON: I love you, Astro.
STEVE: There is one last step, and I actually wonder, we should ask Jack this. I wonder why we don't do it automatically. I have a guess why we don't do it automatically. Scroll down, update the TypeScript config. If you're using TypeScript, I think most people do and should, it matches the JSX import source of quick needs.
JASON: Where is my -- here it is. It was there. I was trying to type TypeScript. All right. Let's add the compiler options. And gonna stick that right there. Good, good.
STEVE: That should be it. Now when you scroll further down on the doc, it will give us a component we can copy and paste in. There we go. Adding the component further down, sorry. Ignore that.
JASON: Oh, here we go.
STEVE: Now, we can grab that code. It's not pretty. Just a button with text inside.
STEVE: And then we can create a new file. You can add a file, source components, count it, CSX, whatever. And then paste it in, we can import it.
JASON: Okay. counter.CSX and copy this component here.
JASON: Let's take a quick second. Make this bigger, hide this, close this down. And let's just look what a basic Qwik component looks like. So, things that are really familiar to me. It's the capital C counter. so, it looks like a component the way we're used to. We're returning JSX, return the markup that I want to use. A lot of the rest of this looks fairly familiar. But a little bit different from what I've seen. If I want to put a value in, put it in curlies just like in React. I've got some functions here. This use signal has got like a hook vibe. But it also has the solid signal vibe. I can see the dot value is very signally. Any specific notes here? Like there's a couple things I've never seen before, like the dollar sign attached to a couple things. Is that to make it very clear that you're using a Qwik feature? Or is there another reason?
STEVE: Great question. Yeah, so, the dollar is really, really critical here. You're right. The hooks and signals works most similar to Preact.
STEVE: Solid is really unique, you don't ever rerun component functions ever as you're probably familiar. You don't use things, you create things. Pushing the point, it's done, it's there. Which is a really cool feature of it. In our case, we actually found Preact's approach to be the most elegant for Qwik in that you have maybe a closer balance to what you expect from React with the benefits of Signals. That was one of the closest inspirations here. And you have stores which are like recursive. If you have a products list and the whole thing needs to be observed. If it updates, anybody who renders from needs to get a re-render or granular patch, that happens automatically. Vue is a close comparison. Taking the best of what we've seen and the fitting for the framework. But the dollar sign, that's the most important thing here. We talked about, we can serialize all these crazy things, serialize a closure, a signal, a promise, a function, whatever. So, the dollar sign is something you'll see throughout Qwik. You will see it, wrap components in a component dollar. And also for the event handler or onClick, that ends with a dollar as well what that does is it signals to our compiler. So, it's a special sort of token, anything that ends with a dollar sign is something that our compiler and other tools are aware of as a serialization boundary. What that means, anything that crosses a dollar sign, a good example would be a counter variable. Is outside the dollar sign when defined. And inside the dollar of the dollar sign whether referenced. That is a serialization boundary. Something you cannot do here -- I'm trying to think of a weird example. We can serialize so many things, it's actually hard to come up with an example. I don't know if I can off the top of my head. At least something that makes sense. What's a Node.js-specific API? Actually, that's a good example. Here's an example. Let's say at the top of the file, you did import FS and FS. Importing JS specific functions. And during the on click, and the status analysis and ESLint phase, you can't do that. Oh, my goodness -- you know what is crazy? This map thing, balloons up here, you have to disable it per application. I haven't disabled it for Chrome yet.
JASON: It is atrocious. It's funny because once you find it. Hold on, let me go back. You can start turning them on just by like, hey -- let's do a...
STEVE: How do I do this?
JASON: It's up in the little green camera thing. And then you can drop down the cameras and just start doing effects. And it's --
STEVE: Oh, I see. There it is. Oh my goodness.
JASON: Absolutely ridiculous, but hey, why not?
STEVE: Was in a board meeting on Zoom -- one of the best benefits post-pandemic is I can join board meetings wearing sweat pants. Nobody knows. It's remote, it's amazing. But I was in a board meeting one time. Had a very serious discussion, very difficult. And out of nowhere, balloons came up on a camera. Everybody was trying not to laugh. It was the worst possible timing. I don't know what they did. But anyway, so the -- we will statically analyze -- this is important for many things, performance and security safety, all the stuff. You can't take, for example, Node.js APIs and shoot them out to the clients. We will not allow that. That would be absurd. Don't do that. Even if it could be done, don't do it. The dollar sign makes it clear. Anything that crosses a dollar sign could go from server to client. And guarantees, we have the server dollar function and stuff like that. But in this case, that tells you, the human, the compiler at sort of parse and check time, lint time, as well as the compiler at distribution time, if there's a dollar, things have to serialize to get over it. As soon as won't work, we will tell you. And in the majority of cases you don't think about it.
JASON: Yeah. Got it. Okay. So, we've got a basic counter. I have -- let me see. Let's look over here.
STEVE: Yeah, use it. Yeah.
JASON: I've got my index here. And then I believe I can do the thing that I always do.
JASON: Which is import this right from my components counter. And it should just autocomplete for me. It does. There we go. And then down here... I'm gonna put in my counter. And I'm gonna intentionally do it wrong to start. So, here's my counter. I've put it in.
STEVE: Yes, jesuit.
JASON: Then I'm gonna run the site, npm run Dev. And that starts me up on four, three, two, one. Let's go over here and open up 4321. Here is our Astro site. This is the Astro part. And here is our Qwik component. And what the hell?
STEVE: I was wonder for you were gonna catch that.
JASON: Whoa, hold up. Hold up. Okay. This is magic. Check out what just happened. In Astro, to make something dynamic, you are supposed to have to include a client directive. Because otherwise you're doing a bunch of unnecessary hydration. But we're using resumability, folks. Apparently it doesn't matter and it just works. That is freakin' dope. Talk to me about this. Does this --
JASON: That is extremely cool. I'm looking down here to see -- here's a little more happening. But look at what's actually happening here. It's not very much.
STEVE: Yeah, I think some of these might be -- only as well --
JASON: Is this also what happened when I clicked? Let me reload. And I want to look to see what's happening here. Okay. So, we've got this, we've got our quick loader. It is pretty impressive that you can fit your entire framework, including Dev mode, on to one screen.
JASON: So, then we've got some refs here. And then when I go to click one of these, we'll see...
STEVE: It won't update. We won't synchronize the update back. That's just for the sort of like hand-off so to speak.
JASON: I gotcha.
STEVE: There is a utility to write it back. That is useful in the cases where -- let's say you're doing something where the server generated HTML and the edge picked it up and modified and continued. The edge writes it back, that makes it distributable over a wire. How we used to do it, inline attributes everywhere. In the old way, the button its held on toes it own state. But the tiny JSON turned out to be more optimal for that.
JASON: Gotcha. Gotcha, gotcha. I think by comparison, like if we look at -- what's a -- what's an easy example for like a -- I'm trying to think of a next site that's not me just picking on the team directly. Let's just pick on the Vercel team directly. If you're looking at the bottom, you're gonna find the next data -- which will be... where is it? Boy, there's a lot in here. Am I going to be able to find this if I -- like next data.
STEVE: Where the app router, they may not use next data anymore. Lots of -- I think that's streaming, chunk-by-chunk.
JASON: I got it. That's not a good example. Whatever. It doesn't matter. So, the general idea is that you get -- you get a lot of extra stuff down in the bottom and that JSON object is big. It's a hefty -- a chonky boy.
JASON: It's nice to know that I don't have to worry about that.
JASON: Right. It's a good point. And I don't know. I like the sort of pragmatism there of just recognizing that like, sure, if we had infinite time and no outside directives, we would all write clean code all the time. But that's just not -- the reality is most become append only. How do you get an append-only to not become unmanageable. Or if it's unmanageable, only for the Devs and not for the users. That is a form of thinking that I think we fall into a trap as Devs, well, I'll have time, I'll make time. This one is going to be different. Make sure I carve out the maintenance hours with leadership. Like you can do it for a while. But it's not a -- it's not a sustainable battle. Like it's -- you got to be thinking about, all right, what happens when everybody gets lazy because they have other things to worry about. And how can we make sure that still gets results?
STEVE: Totally. And I can say, I remember I was working on my last job and I feel like everybody has at least a moment of thinking this way. I have moments, if I ran this company, we would have the cleanest code base, so maintainable, so fast because the bar was so high. Then you start your own startup and realize customers need stuff. They don't need it in a month, they literally need it right now. And like your opinion starts to change. And you realize, okay, there's a balance here. I think we're right.
JASON: One of my favorite things is when like you see somebody who is early in their clear and they go, you know, like, ah, you know, if I could just get rid of these idiots in charge and then five years down the road, I'm the idiot in charge and I realize...
STEVE: Exactly. 100%. There's a good -- oh, my god, there's this guy on TikTok. I don't know his name. One of the few tech TikTok creators I don't know. I should probably reach out to. He also does improv and has this character he does where he's like Jerry the intern. Jerry gets in the code base, I don't know what this garbage is, delete, delete, delete, push to prod. junk code, refactor. That is the codebase until the crushing reality of the world destroys you. And the people, the leadership, might not be entirely the bad guy. The bad guy is the world. Customers need things, business has to make revenue. It's just a thing. That's how the world is. And no business has the salt. In the builder journey, we worked with company, and a lot of logos think highly of. All of them think all their software is garbage, how do they do it? They're good. They're not good. Nobody is doing it right, everybody sucks and that's life in a nutshell.
JASON: So true. Okay. So, I want to make sure that we -- that we take advantage of the fact that I've got you here and I want to try a couple things that sound hard. And see how hard they actually are.
JASON: So, here's my thoughts. One of the big things that Astro promises is islands architecture. Take multiple components, spread them around my site and only the pieces rehydrate. Something interesting already happened here where when I embedded a counter component from Qwik, I didn't have to add one of these client directives to get it to be interactive. So, it is already we're using resumability, not hydration. So, we're not paying that hydration toll. So, step two, then, something that's hard in Astro is what if I want my islands to talk to each other? So, what is the process if I want to my counter button also inform something over here. So, let me -- let me maybe just try out my Qwik -- my Qwik skills here. And I'm gonna say we're just gonna have like info.tsx. And what I want here is I'm gonna export const info. And that's gonna be a component.
JASON: And that component has a render function that's going to return for now. We'll say info goes here. And let's see if I think that might be enough to get me on the page. I'm going to come down here and say info. And then we will import info. From our -- oops. I swear I know how to type. Info. I think I -- did I screw something up? Here's our info. Goes here. So, what I -- what I want to happen is I want -- when I click this button -- maybe this just says, the button has been clicked. Whatever the count is, times.
JASON: Can I do that? How would I do that?
STEVE: Yeah, let me explain how you do it today. And there could be even more kind of deeper integration with Astro to add more forms in the future. Today, as long as you're okay with a parent component in Qwik, it's easy to share it across and communicate across. That's the important thing. That's why Qwik takes the approach of being a, I guess you would call it full-featured framework. Not purely meta or feature, but signals, hooks, all of that good stuff. For now, we can make a compare of components.
STEVE: We can structure in a couple ways, but make a parent component. Trying to think. There's so many ways to do this, create a store that gets passed down, a context that gets referenced. Context could be a nice way to do it. Or actually the store as well. Start with the store. We'll take the concepts kind of one at a time. We'll define a store and do something fun with it.
JASON: We'll go with the old classic wrapper.
STEVE: Yeah, I think this will actually be a good example.
JASON: Okay. So, then do I need to do a fragment to do --
STEVE: Yeah, plain old JS.
JASON: So, put a counter. And we're gonna put in our info component. Okay. And then I'm gonna back out to my page, I guess it's index. And I'm gonna swap these out for we'll call it wrapper. And we're gonna put our wrapper here. Oh, I screwed it up. Components wrapper.
STEVE: Named differently?
JASON: Oh, that's right. Ah. So, now everything is kind of back to normal. But we've got our wrapper. And if I go back into my parent.TSX, I'm ready. What happens next?
STEVE: Yes. Why don't we do this? Why don't we do something fun, a cool property of Signals? And why don't we lift the count tracking of the counter up to the parent. Copy const counter, yeah. And go back and paste it. We'll deal with how we pass it down in a moment. Beautiful.
JASON: Okay. Then I need my use Signal... okay.
STEVE: Beautiful. And now yeah why don't we just pass count signal equals counter -- whatever you like.
JASON: Yeah. Let's do count equals counter.
STEVE: Cool. And let's go to counter. And let's -- in fact, yeah. Why don't we -- we could do something fun, actually. We could make the count button just say click me or something. And make the other component display the count. So, in this one, first thing we want to do is -- yeah. Exactly. So, why don't we define -- so we want to have a prop. Say, you can say like props, colon, and provide the types. Provide the types other way, yeah, counter, good. Or count. And then there's a signal type, exactly. In the what do you call it? The alligator brackets, number. Prop scatter, perfect. Count.
JASON: Does that just work?
STEVE: It does. Though Signal right now will assume an any time. If you just signal and pass the type argument of number, it will be number. But yeah, it should just work.
STEVE: Yeah. And then we could go back to your other component.
JASON: Okay. It's not -- no errors at least. Like we took out the part where we're showing -- let's see... here's -- oh, wait, did I? I do have an error. Hold on. Let me reload. And maybe it was just because I -- oh, no. It doesn't like this. What does it not like?
STEVE: Count of value -- oh, I know what it is. Go back out other components. The parent we are passing this -- count, counter, hop back one more time. We could try logging props.count. Why is count not being passed through? plus... yeah, props.count. This might come on the server. If you clip click me, it should log. Or maybe not, actually. Yeah, this is actually a funny case. Let me explain one brief thing. This is an important thing to know. Just adding a console log there, because Qwik is resumable, that function body doesn't run on the client ever. So, that props will only ever run on server. This is the compiler magic that's running. So, what we should actually probably do is put the log inside of the onClick. The onClick dollar says we're only going to capture what's inside the click handler and only send that, exactly.
JASON: Okay. We got our proxy.
STEVE: Try doings props.count just in case it's a props --
STEVE: Props.count is undefined. And our parent, maybe log something in the parent. What did we do here? I'm sure it's the most simple thing in the whole entire world that's just escaping us. What we can do is we can add the finishing code to pass in into info as well. We could also switch to a context, whatever tiny typo we're hitting wouldn't affect us for context. But also try to flesh out this code further. Maybe learn something by hooking into info, uh-oh, we did one silly thing wrong. But going into info, follow the same pattern and log out the counts.
JASON: Okay. So, we want props. And that is going to have we'll call it the count. And that is a signal number.
JASON: Okay. And on this one, we want count.value -- oops. Stop that. We want props.count.value.
STEVE: Okay. Cool. See if any magic happens.
JASON: See? It immediately fails. So, something is going wrong here.
STEVE: Yeah. What's showing up or I know server. This is what I hope for, a new error. Okay, okay.
JASON: Unhandled rejection, converting circular structure to JSON. We're trying to serialize something that's not serializable, it looks like.
JASON: Render to static markup, cannot read property of undefined. That's interesting.
STEVE: That's similar. It's running into this at this point as well. Jump back to your wrapper quickly maybe. See if there's a typo on how we're defining signal. Let's do this, switch over to context. This will explain it.
JASON: That makes sense.
STEVE: A new error here.
STEVE: Okay. Same error.
JASON: Did we get any error?
STEVE: I don't know.
JASON: Let me just start this one more time. Make sure we're getting...
STEVE: Yeah, good call.
JASON: Are you doing anything? Are you frozen?
JASON: Not doing anything.
STEVE: Oh, we don't know why.
JASON: Now it's trying something. Did my stuff freeze?
STEVE: I don't know. Okay. It's a new tab.
JASON: But now it's just working. I think I locked it up somehow. Because that looks like it wasn't reloading.
STEVE: Oh, yeah. It's logging the -- oh. Oh. Oh, my goodness, yes. So, that's definitely what happened. For some reason, something got frozen here. And so, it was just never passing the props.count through. It wasn't getting this update. So, good news is --
JASON: So, I locked something up.
STEVE: Not crazy.
JASON: Everything is fine. We have working components.
JASON: And whatever we did had nothing to do with the software. We just -- probably logged something wrong. I think I might have gotten the console caught in a loop. This is full frozen. I can't even close this tab.
STEVE: Yeah. Something. Heisenbug. When you're livestreaming, it will guarantee to fail in a way that you can never reproduce in your entire life.
JASON: Okay. Here's the other thing I was interested in.
JASON: I'm gonna add just some extra crap in here that is not interactive because I want to look at what happens. Do we have a lorem? Can I just do like a lorem?
STEVE: What? Do you have an extension for that?
JASON: I think that's cool. Yeah, the extra. Yeah, okay.
STEVE: That might have been -- do you have Copilot on?
JASON: No, no, no. This is -- it's Emmett.
STEVE: That's awesome. It just comes with VSCode, I think?
JASON: I think it's on by default. I might have installed it early on. There's a few that I add every time.
JASON: Let's build, let's see.
JASON: So, npm run build. No errors, everything is fine. Then I'm gonna npm run serve. Wait. Is that -- that's not a thing, is it? So, it's NPX serve, and then is it dist? Yeah. Okay. So, I have localhost 3000 now. If I open this up, all right. So, this is our production site.
STEVE: Yep. Do we have quick loader? Now quick loader -- that ticket is not solved yet. It's either done or coming soon. That's the expectation the customer should have. I would say it is still in beta. By v1, it would be there. That's with Qwik City and everything too.
JASON: Got it. We don't see much of anything here. It's all good. And if we look at the network size, let me turn off the cache. Let me -- let's -- you know what? Let's play even more. Let's go slow 3G.
STEVE: Oh, yeah.
JASON: And... nine and a half kilobytes of resources.
JASON: Npm run preview? I don't know what --
STEVE: I forget the difference. This is a Vite thing, pretty sure. I've run into this with multiple Vite projects. I've never known the difference. I just know in the case of like Astro or Qwik City, I just use deployment adapters. So, if I deploy to Netlify or whatever, it just works. It just does the right things.
JASON: Cool, okay. I don't know what preview is. Turning it off and turning it back on would solve problems. Yeah. The preview is the build, I mostly understand what that means. So, we've got --
STEVE: The build command, I think in Vite projects in general, it's a common thing. Build, okay.
JASON: This is good. We're good, I'm happy. I'm in. Okay, yeah. Paulie is saying there's -- it's in the package JSON. Which obviously it just worked when I ran it.
JASON: Do these deployment adapters work going directly to AWS? I believe there should be Astro adapters for just about everything that you would want. If we look at the deployment... where is it?
STEVE: Yeah. And that's actually a really nice thing. One of the really nice things about the combination of Qwik and Astro. If we adapt Qwik and Astro, every feature of Astro, every feature works. Every deployment adapter, probably doesn't have as much as Astro. Whatever feature you have on here, you basically give -- if you want all the things, all the perf and all the features, this is a pretty awesome combo.
JASON: Where is the actual deployment thing? SSR adapters, maybe? Official adapters. Community maintained-adapters. All right. Here's the thing I was looking for.
JASON: Node, Vercel, cloud, SST, AWS --
STEVE: SST is AWS too, or SST supports AWS.
JASON: Yes, deploy your site to AWS. There's another AWS, more AWS. So, it looks like there are lots of options out here for what you can do. Astro WordPress, that's fascinating.
STEVE: Oh! What the heck?
JASON: Lots and lots of options. Let me drop the link here for anybody who wants it. Lots of good stuff there. So, all right let's dig back into -- is this my frozen one? No, this one is fine. So, let's take this, make this a little bit bigger so I can get to it. All right. We're in the preview still?
STEVE: Yes, maybe.
JASON: Okay. Let me get back into Dev mode. All right. And then I can uncomment, uncomment --
JASON: We're gonna turn off the log, disable the cache, and then run this. So, these, I think, are the Astro bits. So --
STEVE: For that preview widget, yes.
JASON: Yeah. Let me just filter out for like Astro.
STEVE: Whoa, you can type dash and a negative filter? What?
JASON: I think I learned this one from like Tim -- why am I blanking on his name? Perf Lord Tim.
STEVE: Yes, I know who you're talking about. I forgot his last name too. But yes.
JASON: Hold on, we can find this fast. Tim! Kadlec.
JASON: That's a Tim special. Also, this episode is dope if you're into performance, get in there.
JASON: Here's a question, what's the difference between Qwik City and Astro?
JASON: All right. I figured out what was going on.
JASON: And it's the best possible use case. I hope that jackhammer next door is not coming through my mic. Sorry, everybody.
STEVE: It's not. At least for me, it's not.
JASON: Check this out. Here, right? Watch the network tab when I click. Did you see that? That's cool
STEVE: Oh, yeah. And this is the file I wanted to show. So, go cool thing here is. I'm glad you pointed occupy. One is that in development mode, we will only fetch in interaction, and in prefetch, this is the thing on the show, you know what I was talking about. Go to the counter component we can look at these two things side by side. In counter.tsx. There we go. You know how I said the onClick handler, only sends the click handle, this is what we're seeing here. This is actually -- this is kind of a big secret, by the way. We talked about how we can serialize -- we were the first to serialize functions, serialize promises, serialize stuff across web worker and server client boundaries. It was new in Qwik land. And to be honest in the beginning, we didn't know if this stuff would be possible. And Manu on the team would go away for a week and come back and be like, you can! Here's how! And then you see this stuff propagate. Prove the idea and then it shows up in other frameworks, Remix, Solid. Ryan is a great engineer and reverse engineer. It can be done in Solid, and it will, if it's possible. He will make it happen. Quite an amazing cadence. But one thing that's completely unique to us, many of them are, serializing signals. But what this is, this is what serializing function closures look like. In this case, we have a function that covers certain lexical scope. The props object. What we're doing is actually generate this function at compile time that can pull out what whole use lexical scope was one of the biggest sort of unlocks to create a lot of the serialization power. The ability to pass at runtime as needed and compile all the other stuff away. So, we're still just distributing this little tiny couple lines to still execute with still all the thing use expect from a basic closure, a basic reference function, how it manipulates stuff outside. I don't know if that was so abstract it didn't even make sense. But that's the idea.
STEVE: Yeah, what the heck is that?
STEVE: Yeah, no. Yeah.
JASON: But if you send a promise across the server client boundary in most frameworks you would get nothing. And because of the work of -- it sounds like Manu -- you can just do it now in Qwik. And subsequently in Remix and in Solid and so on and so forth. Pretty dang cool.
STEVE: And if it's not obvious, we should take it back, what's the benefit? Why does this cool stuff matter? It's simple. Imagine this component, I'll tell you, hold on. Let me find a stat for you that most people never want to share. I will do it because I enjoy pain. Let me tell you something. We have a React component in our codebase, in the builder codebase, that will -- that loads a lot. It's very commonly used. If you use our platform, you will be using this component a lot. Jason, could you guess how many lines of code our largest React component is?
JASON: 75 line -- no, 750 lines. No, two lines.
STEVE: No, much, much larger. Definitely larger than two. I'll give you the number -- it's 13,449 lines of code. One React component. This stuff happens sometimes. It is -- I'm sorry -- it is being broken apart bit-by-bit. Every time we work on this component, we break thing office. But stuff happens in real world application developments. And so, in this case, let's imagine for a moment -- and like honestly, I -- one thing I hate -- I hate, hate, hate -- is when the authors of frameworks tell you, oh, well, you're doing it wrong. You need to make smaller components. That's great. All your doc examples are beautiful. And my code is not. That's just how it's going to be. Because we don't have time to restructure the code every time we have to append something to it. And so, the reality is, if the guidance is right, you code differently. In many cases, it's not going to happen. At least in these ways.
JASON: I do think -- yeah, I also think that something that always kind of drives me up a wall is the general approach that when somebody writes something that thing is very technically impressive and then somebody brings them a very practical reason why they had to do something different or why the thing they're doing, they're like, this isn't gonna work in my use case or whatever. And the response tends to be like you're not understanding this correctly. You need to refactor, you need to rewrite. Like this implicit expectation that like the world should shape around the brilliant idea.
STEVE: Yeah, exactly, yes.
JASON: This is why so many good ideas die in open source is because people think that the good idea will just cause everybody to drop everything and rebuild everything. And like, it's not -- we still got codebases. Our entire banking system runs on what? Cobalt?
STEVE: Cobalt! Yeah!
JASON: Because there's zero chance that anybody is gonna rewrite the 50 million lines of banking code. Because React server components have a technically superior idea. There's a much bigger reason that causes those times of codebases to get rewritten. It's not like, it is more pleasant to work with.
STEVE: Totally. And if you have ever been in involved with one of those projects, this is unmaintainable garbage, rewrite it. Over never experienced so much pain as a developer. Because those projects start great. You make 80% of the progress in a few months. And then you spend four years doing the last 20% and it never gets off the ground and it's horrible. It's horrible for everybody. It starts great and it goes downhill and you live in the pit of despair for years.
JASON: I feel like this is a -- it's a -- like another way of experience that, like, well, if we could just get rid of those idiots in charge. Well, if we could just get rid of the legacy code and get the green field, and it looks just like the old codebase. Turns out people write code for a reason.
STEVE: Exactly. The end result.
JASON: Us not wanting to deal with them doesn't mean it doesn't exist. You have to handle them, oh, I see why they did that thing the way they did it.
JASON: Expecting everybody did it wrong because they don't have your brain is a sure fire ticket to pain and to realizing you're not as smart as you thought you were.
STEVE: 100%. You have this mentality of well the prior code was written without respect to the codebase, and should have factored that in when delivering the feature. We actually do this in our company. A lot of our engineers talk to the customers directly and figure out the solutions. When you're face to face with a customer, if you try this, you'll probably try it once ever. If you are not gonna do that, that won't look nice in the codebase, they have no -- that does not resonate whatsoever with them. What they care about is what they're trying to use your product for. And you realize through this experience repeatedly that they are correct. Your codebase is not correct. And, you know, we try to find a balance. And in this case, like this example, this 13,000 line of code React component, if that was here in Qwik, that massive component and all we did was click on that one button, that tiny code that's there is still what executes on the client. I don't care if you wrote 13,000, that's what you see and what's downloaded. That's the beauty. In Elm, large files are a virtue. I'll be honest, there are many cases whether you ignore the performance drawbacks that most frameworks have with large files and accept -- take one extreme, SolidJS. SolidJS I've never thought about it this way, but if I think deeply, besides rehydration, there's no runtime penalty to a massive component. Everything is granular signal. You're never rerunning and re-hy-diffing. In React, at 13 ,000 license, the team would say, don't do that. It's nice when your framework says that's fine. Refactor when you need to, not when you have to.
JASON: And really anything we're doing is just us like -- we're writing abstractions over the fact that this is all gonna get unrolled into one giant file anyways when it's executed on the browser.
JASON: At a certain point, we're just making our lives harder, taking a little thing and moves it out. It doesn't look right. It's okay to put a function inside a function if that's the only place it gets used. It's okay. The aesthetics are not the point. Because we always said, well, code is the course of truth. Sure, code is the source of truth, but the truth is whether or not people who use the software find if valuable.
STEVE: exactly, yes.
JASON: That's it. You can write the most beautiful code in the world. If the source of truth is everybody hates your app, you're out of a job, I'm sorry. Gorgeous code doesn't pay the bills. A what pays the bill is writing code that people are using. As I'm off on a rant, we're coming close to time. Anything you want to cover on should we look at next steps for people who want to go further on their own?
STEVE: Good question. I think we covered the basics. Let's talk next steps. Even for those what found these initial steps, there's a lot more to the framework. Stores, context stores are freaking awesome. So many other things. The route loaders and the server and worker dollar. Needs its own episode, the ability to send things to the server. Do one last quick thing.
JASON: Yeah, let's do it.
STEVE: Let's go to your counter component. I'm trying to think of where we want to do this. What I would love to do is call a function on the server, or server code, from the client and show how stupidly easy this is. Maybe we could just add another but then and just do an alert of like the current date or something. And the date will actually come from the server. So, if you want to put wherever you want, if you want to add a fragment, add another button, or something else add in the wrapper. Whatever you think is easiest.
JASON: Yeah, this is easier. We'll go for time.
JASON: We have got this one here. And then we're gonna have another button. Have an onClick.
JASON: Actually not do that yet. Just go here. Get the server date.
JASON: Okay. Now we've got a button to click to do it.
JASON: I assume I want to be in here for this.
STEVE: And now -- yes. Login would be a good idea. Good. Add onClick and remember onClick ends with a dollar in Qwik land. TypeScript is your friend. There you go. Let's say const time equals await server dollar.
STEVE: There we go.
JASON: Let me make this async.
STEVE: Yes. And server dollar, you can import -- yeah, do you have an autoimporter doodad?
JASON: That's not what we wanted at all.
STEVE: Do we need to import from Qwik City? I don't know if it works --
JASON: It's not part of it, doesn't look like.
STEVE: Try npm installing Qwik City and importing server dollar. Yes.
JASON: Is it builder --
STEVE: Yes, add server.-- Jack can you say in the comments? Will it work in the Astro integration? If not, we can add that. If he knows it doesn't work, we don't have to take the time.
JASON: Saying use task.
STEVE: He is right, but server dollar is way cooler. Let's show what server dollar looks like. If it's not in Astro, we can be optimistic it will come in 1.0 or soon. Add a callback function to server dollar. Okay. There we go. And if it surprise works, that's super-awesome. But we'll see. Cool. We can return like date.now or something, you know? It would be really cool to return a server-specific API. Use a Node.js import or something.
JASON: What if we use -- yeah. This is fine. Let's start here. And then we're gonna return... time.
STEVE: Yeah, do that. Console log it, alert it, whatever.
JASON: Console log... okay. Saving.
STEVE: Okay. Jack is saying it won't work. There's still a chance that it does. Yes, I'm happy. Let's look at the code. Ignore the fact that this doesn't work in the Astro integration. It works in Qwik City. Jack is saying let's bring it over to the Astro integration. But what this is, if you're familiar with React server components or how any framework handles this boundary. Server land is over here in this file, client land in this file, and Qwik is about granularity. If you write something and you want -- if you have seen -- this is taking this concept of trying to make it one more step generic and work with others. If you want to call code on the server, do it anywhere, and this serialization technology identifies the dollar and every dollar can transfer over the wire, it can work forwards and backwards. Client back server. In this case, if you looked at the code that the compilation gave you it's not easy to do here, what you would see, whether you run that server dollar, it's making an HTTP call to the server. The code is only running on the server, ripped out by the compiler, executes server side only. And any time, this relates to the point we were talking about, this idea that you need to re-architect the code, you need a server side or client something, React server components, need a client, refactoring components. We know that's something people don't have time to do. And back and forth, that's the dream. Building out server first, but have client handlers, and I want to call my client again, I don't need to make this HTTP. Others do it at the module level, instead of the closure levels.
STEVE: This is unique to Qwik. I'll pause there. But yeah, that's an exciting thing. And also works with dollars. Worker dollar execute on a dollar, if this imported JS, it would only be in the server or the worker.
JASON: That's a thing to consider. Something like moment is huge. Not having to download that on the client side, that's a big win. It just lets you make more informed choices about what your code is doing. And the way the tradeoffs of like do I want to do this work on the server? Do I want to do this work on the client? And not think is this a use server or client file? Do I have to write an API endpoint and so on and so forth? I know we're almost out of time. Where else should people go if they want to learn more?
STEVE: Yeah, I would say check out -- go to Qwik.dev and search for the Astro integration. It's on our docs. I think because it's not maintained bit Astro team, it won't show up in the docs. You can go in here, search the docs for Astro. Google Qwik Astro. There you go. That's the getting started. It will walk you through, install the package, add TS config and just writing quick inside of Astro. Add magic HTML too your HTML-first framework. It's cool. I would love to see what people build. I think what we'll see off of this and I'm excited about is more I would call like rich Astro sites that fully maintain that performance. There's Qwik sites out there -- we didn't talk about visible tasks, making animations crazy fast. All things to learn separately. And bring all that to Astro, really cool stuff.
JASON: Yeah, I'm going to drop a link to the Qwik docs if you want to dig in. And take advantage of the community. A lot of people building cool stuff. I know your team is hanging out on Discord, right?
STEVE: That's correct. And a whole bunch of community members. Some our Qwik heroes, community members who are awesome, killer, contribute, answer questions. It's an amazing ecosystem.
JASON: Excellent. Yeah I know we're basically out of time here. I'm going to take this opportunity to just do another quick thank you to our sponsors, Netlify, Vets Who Code, make this episode possible. Look like I've got a bug. It's been live captioned, Amanda here from White Coat Captioning all day. And Steve, thank you for being here. One more link to your Twitter profile. And then I think I'm gonna call this one a -- I had a blast, did you have fun?
STEVE: Super fun. Appreciate it. This was awesome.
JASON: Chat, I hope you had fun. And look at the schedule, we have a lot of fun, including a special episode next week, live in studio. make sure your mark your calendars and show up for that one. I think that's. Thank you so much for hanging out.
STEVE: Love it, thanks, everybody!
Closed captioning and more are made possible by our sponsors: