Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
@qwikdev/astro
Advanced tools
Leverage the power of Resumability inside of Astro, using Qwik components.
There are two methods to add the integration. Let's begin with the easiest one!
Astro comes with a command-line tool for incorporating built-in integrations: astro add
. This command will:
astro.config.*
file to apply the integrationTo install @qwikdev/astro
, run the following from your project directory and follow the prompts:
# Using NPM
npx astro add @qwikdev/astro
# Using Yarn
yarn astro add @qwikdev/astro
# Using PNPM
pnpm astro add @qwikdev/astro
The integration needs the following in tsconfig.json
for typescript to recognize Qwik's JSX types.
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@builder.io/qwik"
}
If you don't intend to use Qwik as your primary jsxImportSource
, add:
/** @jsxImportSource @builder.io/qwik */
at the top of each Qwik component file.
This is when you may not have that many Qwik components compared to other JSX frameworks on the page.
If you face any issues, please post them on Github and attempt the manual installation below.
First, install the @qwikdev/astro
integration like so:
npm install @qwikdev/astro
Typically, package managers install peer dependencies. However, if you get a Cannot find package '@builder.io/qwik'
warning when starting Astro, install Qwik.
npm install @builder.io/qwik
Now, add the integration to your astro.config.*
file using the integrations
property:
// astro.config.mjs
import { defineConfig } from 'astro/config';
+ import qwikdev from '@qwikdev/astro';
export default defineConfig({
// ...
integrations: [qwikdev()],
// ^^^^^
});
Hooray! We now have our integration installed. Before deep diving in, there are quite a few differences than other UI frameworks.
Astro is popular for its partial hydration approach, whereas Qwik does not require hydration.
What does this mean?
In other UI frameworks, a hydration directive would be needed for interactivity, such as client:only
or client:load
. 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 create a counter component in Qwik (e.g. at src/components/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>;
});
It can be consumed in our index.astro
page like so:
---
import { Counter } from "../components/counter";
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Astro</title>
</head>
<body>
<h1>Astro.js - Qwik</h1>
/* no hydration directive! */
<Counter />
</body>
</html>
Let's take a look at this in the wild.
Here we are refreshing the page, and you'll notice nothing was executed until the button was clicked. Without resumability, our <Counter />
would have been executed on page load.
The 402 byte q-chunk is our Counter's onClick$
handler.
The framework! We do not execute it until it is needed. In this case it is gzipped using SSG.
One of Astro's key features is Zero JS, by default. Unfortunately, after adding a JavaScript framework, and any subsequent components this is usually not the case.
If we want to introduce interactivity with a framework such as React, Vue, Svelte, etc., the framework runtime is then introduced. The number of components added to the page also increases linearly O(n) with the amount of JavaScript.
Qwik builds on top of Astro's Zero JS, by defaut 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, and zero effort on the developer.
Instead, upon page load, a tiny 1kb minified piece of JavaScript, known as the Qwikloader, downloads the rest of the application as needed.
Hydration forces your hand to eagerly execute code. It's not a problem with components that are outside of the tree, such as modals, but it must exhaustively check each component in the render tree just in case.
Qwik works exceptionally well in Astro due to Resumability and its ability to lazy load code in a fine-grained manner. Especially for marketing sites, blogs, and content oriented sites with many components.
As of @qwikdev/astro
v0.4, we have added support for Speculative Module Fetching in Astro.
This enables instant interactivity for your Qwik components. Speculative module fetching will prefetch the application bundles in the background of a service worker, so that when needed, the code is already present in the browser cache.
You should be able to use Qwik insights out of the box!
While Astro generally adopts an islands architecture with other frameworks, Qwik uses a different strategy known as Qwik containers. Despite the differences in approach, both share similar limitations.
In the DOM, you'll notice there aren't any <astro-island>
custom elements, this is because to Astro, Qwik looks like static data.
This is because in Qwik, the handlers themselves are the roots / entrypoints of the application.
One common limitation is trying to pass state into another island or container.
Sharing state is crucial in modern web development. The question is, how can we achieve this when state needs to be shared across different containers or islands?
Other frameworks with Astro address this by using nano stores, or global signals.
While you may see all of your tests passing, and the application working as expected, we do not recommend using nanostores or global signals. They can lead to some unexpected behavior in an SSR context.
For example, in Solid's tutorial the following is mentioned:
While it is possible to use global state and computations, Context is sometimes a better solution. Additionally, it is important to note that global state should not be used in SSR (server side rendering) solutions, such as Solid Start. On the server, global state is shared across requests, and the lack of data isolation can (and will) lead to bugs, memory leaks and has security implications. It is recommended that application state should always be provided via context instead of relying on global.
In Qwik, it was a design decision to not include global signal state.
Instead, we recommend the use of custom events, which offer several advantages:
This example shows how custom events can be used throughout your application. Pay attention to counter.tsx
, random-island.tsx
, and our index.astro
page.
To use multiple JSX frameworks like Qwik, React, Preact, or Solid in Astro, you need to set up rules for which files each framework should handle.
For example, you can place all Qwik components in a folder named qwik
. Then, configure Astro to process any file within this folder using the Qwik integration.
import { defineConfig } from "astro/config";
import qwik from "@qwikdev/astro";
import react from "@astrojs/react";
export default defineConfig({
integrations: [
qwik({ include: "**/qwik/*" }),
react({ include: "**/react/*" }),
solid({ include: "**/solid/*" }),
],
});
Above we're using the Qwik, React, and Solid integrations in the same Astro project.
If we look at the first integration, it's going to look for any file in the qwik
folder and use Qwik for any file in this folder.
For simplicity, consider grouping common framework components in the same folder (like /components/react/
and /components/qwik/
). However, this is optional.
If you're using React, we suggest using the @builder.io/qwik-react
integration. It's a drop-in replacement for @astrojs/react
, and allows a seamless transition to Qwik.
import { defineConfig } from "astro/config";
import qwikdev from "@qwikdev/astro";
import { qwikReact } from "@builder.io/qwik-react/vite";
// https://astro.build/config
export default defineConfig({
integrations: [qwikdev()],
vite: {
plugins: [qwikReact()],
},
});
With Qwik-React, we can "qwikify" our React components, and use them in our Qwik application, even nesting Qwik and React components outside of an Astro file!
You do not need to specify an include property with qwikReact.
Here's an example of a React component with the qwik-react
integration.
/** @jsxImportSource react */
import { qwikify$ } from "@builder.io/qwik-react";
import { useState } from "react";
const ReactCounter = () => {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>React {count}</button>;
};
// "Qwikified" React component
export const QReactCounter = qwikify$(ReactCounter);
After creating our counter, it can be consumed in our index.astro file.
<QReactCounter qwik:visible />
Notice that in .astro
files we use a qwik:
hydration directive prefix, this is to prevent a conflict with Astro's hydration directives that are provided out of the box.
You can also use the client:*
prefix, but only in tsx files. You can find a list of directives in Adding Interactivity section of the Qwik docs.
Qwik React components still have hydration, thus it is recommended to use Qwik-React as a migration strategy to resumable components.
Unfortunately, TypeScript can only have one jsxImportSource
default. If you're using React, Solid, or Preact's Astro integration in your Astro app alongside, please override each component's import source.
If you're using @astrojs/react, you can use qwik-react instead. The proper configuration will be supported out of the box.
/** @jsxImportSource react */
import { useState } from "react";
export const ReactCounter = () => {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
};
Solid JS for example, is:
/** @jsxImportSource solid-js */
Preact for example, is:
/** @jsxImportSource preact */
For named slots within Astro, instead of adding q:slot
on the markup, add slot
instead.
my-slot-comp.tsx
import { Slot, component$, useSignal } from "@builder.io/qwik";
export const MySlotComp = component$<{ initial: number }>((props) => {
return (
<>
<Slot name="test" />
</>
);
});
index.astro
<MySlotComp>
<div slot="test">Content inside the slot named test!</div>
</MySlotComp>
Default slots work as expected in their Qwik City counterpart.
Paul Scanlon shows a hands-on look at using Qwik in Astro over React and Vanilla JS.
Rishi Raj Jain has written an awesome guide on setting up Qwik with Astro's Vercel SSR Adapter.
Paul Scanlon explores using Qwik as a React alternative in Astro.
Watch Jason & Steve discuss the Qwik Astro integration on the LWJ show.
Awesome's Qwik + Astro video goes into how Astro just got even faster.
We'd love for you to contribute! Start by reading our Contributing Guide. It's got all the info you need to get involved, including an in-depth section on how the integration works under the hood.
There's also a qwik-astro
channel in the builder.io discord to discuss API changes, possible ideas to the integration, and other cool stuff. 😊
Special thanks to Matthew and Nate from the Astro core team! This integration would not be possible without their help.
Nate's handles:
FAQs
Use Qwik components and Resumability within Astro
We found that @qwikdev/astro demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.