Originally written by Jack Shelton
Hey Devs! My name is Jack, and I am a freelance fullstack developer based in Texas. I also work on this thing called Qwik UI in my free time. 🙂
The problem
In mid-late 2022, I had the opportunity to try Astro, a server-first, content-focused, and extremely flexible meta-framework on my day job.
It quickly became my go-to for creating landing pages, marketing websites, and even small web apps. If my clients needed something, it was almost always a click and integration guide away.
Astro sites significantly outperformed the previous static site generators I had used. I appreciated the speed and found it intuitive to work with.
Unfortunately, as I added more interactivity, my Astro sites began to slow down, despite Astro being the fastest meta-framework I had used up to that point!
My clients and I took notice of this. I spent a lot of time researching how to improve site speed, but in the end it always felt like an uphill battle of optimizing versus adding the stuff my clients needed.
The journey
In an ideal world, you could build your application, and it would be extremely fast, regardless of the level of interactivity or the size of your page. This appears to be an unsolvable problem. The more components we add, the slower it gets.
I wondered, did it have to be this way? Is it even possible to have a fast and easy development process? Is it the developer’s fault when our apps are slow?
Looking back, I’d say no! Developers should focus on what matters most: building the product! So, how do we solve this issue? For a while, it was a big what if. 😅
That what if quickly became a reality when I discovered Qwik’s resumability. I was 100% certain it was exactly what I was looking for.
So I did some research. I saw a lot of comparisons between the two in terms of performance. April this year I thought “why don’t we use them together?” One is a meta-framework, and the other a UI framework.
Would it still be resumable?
Is Astro’s partial hydration approach going to be a problem with a framework that doesn’t have hydration?
How would it work with islands?
Well, turns out I wasn’t the only one!
After some awesome help from Misko, creator of Angular and Qwik, as well as the Astro core team, I can finally answer that question I had back in April.
Introducing @qwikdev/astro:
Astro’s first resumable UI framework.
Starts fast, stays fast
One of Astro's key features is Zero JS, by default.
Unfortunately, this is usually not the case after adding a JavaScript framework and any subsequent components.
If we want to introduce interactivity with a framework, such as React, Vue, Svelte, and so on, the framework runtime is then introduced. The number of components added to the page also increases linearly O(n) with the amount of JavaScript.
Adding Qwik
Qwik builds on top of Astro's Zero JS, by default principle and then some. Thanks to resumability, the components are not executed unless resumed. Even with interactivity, the framework is also not executed until it needs to be. It is O(1) constant, … with zero effort on the developer.
This integration for Astro enables resumability, fine-grained lazy loading, and many of the Qwik core stuff we know and love.
This includes all of the Astro goodies, like view transitions, MDX collections, and the hundreds of integrations that Astro provides.
So where would @qwikdev/astro make sense?
You can use it anywhere you’re currently using a framework component in Astro! Using Qwik and resumability should significantly speed up your site.
Do Qwik components need hydration directives?
Short answer, no!
In other UI frameworks, a hydration directive, such as client:only
or client:load
, would be needed for interactivity. However, these are not needed with Qwik because there is no hydration!
When using Qwik inside a meta-framework like Astro or Qwik City, components are loaded on the server, prefetched in a separate thread, and "resumed" on the client.
For example, here's how we use a Qwik counter component in Astro.
counter.tsx
import { component$, useSignal } from "@builder.io/qwik";
export const Counter = component$(() => {
const counter = useSignal(0);
return <button onClick$={() => counter.value++}>{counter.value}</button>;
});
index.astro
---
import { Counter } from "../components/counter";
---
<html lang="en">
<body>
<h1>Astro.js - Qwik</h1>
/* no hydration directive! */
<Counter />
</body>
</html>
Does resumability work?
Yes! We can lazily execute code on interaction, just like using Qwik with Qwik City.
Here, we are refreshing the page, and you'll notice that nothing was executed until the button was clicked. Without resumability, our `` component would have been executed on page load.
The 402 byte q-chunk is our Counter's onClick$
handler.
What's in that 17.61kb chunk?
That's the framework! We do not execute it until it is needed. In this case, it is gzipped using SSG.
How about islands?
Instead of islands, we have Qwik containers! These fit quite well into Astro’s island model, having similar limitations.
Below is an example of a Qwik container in Astro. In the DOM, you'll notice there aren't any `` custom elements. This is because, to Astro, Qwik appears as static data.
This is just the beginning! You can try out the integration in Alpha today, by running:
npx astro add @qwikdev/astro
💡 This integration is currently in Alpha release. We encourage you to try it and share your feedback. If you run into any problems, open up an issue in our GitHub Repository.
You can also view the package on NPM, Github, Qwik integration page, and the Astro integration page.
Join the fun and contribute!
Stay awesome devs,
-Jack
💡 Tip: Visit our Qwik hub to learn more.
Introducing Visual Copilot: a new AI model to convert Figma designs to high quality code in a click.
No setup needed. 100% free. Supports all popular frameworks.