Astro

Astro 是一個靈活的元框架,可以容納各種工具和整合,讓您能夠利用眾多生態系統。

它也允許您使用您喜歡的 UI 框架(或完全不使用框架)來編寫元件,並在建構時將您的頁面渲染為靜態 HTML,或使用伺服器端渲染(SSR)在伺服器上動態渲染。

這會產生快速、對 SEO 友好的輸出,可以部署到任何靜態託管環境或伺服器。

如需有關整合的詳細資訊以及檢視原始碼,請前往 GitHub 上的 QwikDev Astro 整合

使用 Astro 取代 Qwik City

在將 Astro 與 Qwik 整合時,請注意 Qwik City API 與 Astro 不相容。

Astro 是一個元框架,它提供了自己的一組 API 和功能來處理這些問題。 這些包括

  • 路由
  • 頁面
  • 佈局
  • 資料提取
  • 伺服器端渲染 (SSR)

因此,在將 Qwik 與 Astro 整合時,您應該使用 Astro 的 API 和功能,而不是 Qwik City 的 API。 這將確保您的 Qwik 元件在 Astro 環境中正常運作。 如需更多資訊,請參閱 Astro 文件

@qwikdev/astro 💜

此整合利用了 Astro 內部 可恢復性 的強大功能,並使用 Qwik 元件。

安裝

新增整合的方法有兩種。讓我們從最簡單的一個開始!

Astro CLI

Astro 附帶了一個用於整合內建整合的命令列工具:astro add。 此命令將

  1. 選擇性地安裝所有必要的相依性和對等相依性
  2. 選擇性地修改您的 astro.config.* 檔案以應用整合

要安裝 @qwikdev/astro,請從您的專案目錄執行以下命令並按照提示操作

# Using NPM
npx astro add @qwikdev/astro
 
# Using Yarn
yarn astro add @qwikdev/astro
 
# Using PNPM
pnpm astro add @qwikdev/astro

設定 TypeScript 配置

整合需要在 tsconfig.json 中加入以下內容,以便 TypeScript 能夠辨識 Qwik 的 JSX 類型。

"compilerOptions": {
  "jsx": "react-jsx",
  "jsxImportSource": "@builder.io/qwik"
}

如果您遇到任何問題,請 在 Github 上發布 並嘗試以下手動安裝。

手動安裝

首先,像這樣安裝 @qwikdev/astro 整合

npm install @qwikdev/astro

通常,套件管理器會安裝對等相依性。但是,如果您在啟動 Astro 時收到 找不到套件 '@builder.io/qwik' 警告,請安裝 Qwik。

npm install @builder.io/qwik

現在,使用 integrations 屬性將整合新增到您的 astro.config.* 檔案中

  // astro.config.mjs
  import { defineConfig } from 'astro/config';
+ import qwikdev from '@qwikdev/astro';
 
  export default defineConfig({
    // ...
    integrations: [qwikdev()],
    //             ^^^^^
  });

如果您也在使用其他整合,例如 react()preact(),您需要將 qwikdev() 放在清單中的它們前面。 否則您將會遇到 Not a QRL 錯誤。 就像這樣:integrations: [qwikdev(), react(), preact()]

Qwik 不會進行水合,它在根本上有所不同

Astro 以其部分水合方法而聞名,而 Qwik 不需要水合

新增 Qwik 元件

在其他 UI 框架中,互動性需要水合指令,例如 client:onlyclient:load。 Qwik 不需要這些,因為它沒有水合!

在像 Astro 或 Qwik City 這樣的元框架中使用 Qwik 時,元件會載入到伺服器上,在單獨的執行緒中進行預取,並在客戶端上「恢復」。

例如,以下是如何在 Qwik 中建立計數器元件(例如,在 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>;
});

它可以在我們的 index.astro 頁面中使用,如下所示

    ---
    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>

啟動快速,保持快速

Astro 的主要功能之一是預設為零 JavaScript。遺憾的是,在添加 JavaScript 框架和任何後續組件後,通常情況並非如此。

如果我們想使用 React、Vue、Svelte 等框架引入互動性,則會引入框架運行時。添加到頁面的組件數量也會隨著 JavaScript 的數量線性增加 O(n)。

Astro + Qwik

Qwik 建立在 Astro 的預設為零 JavaScript原則之上,甚至更上一層樓。由於可恢復性,除非恢復,否則不會執行組件。即使具有互動性,框架也不會執行,直到需要執行為止。它是 O(1) 常數,並且開發人員無需付出任何努力。

相反,在頁面加載時,一個稱為 Qwikloader 的小型 1kb 壓縮 JavaScript 會根據需要下載應用程序的其餘部分。

細粒度的延遲加載

激活迫使您 急切地執行程式碼。對於樹外部的組件(例如模態)來說,這不是問題,但它必須窮舉地檢查渲染樹中的每個組件,以防萬一。

由於可恢復性及其以細粒度方式延遲加載程式碼的能力,Qwik 在 Astro 中表現出色。特別適用於營銷網站、部落格和具有許多組件的內容導向網站。

即時互動性

@qwikdev/astro v0.4 開始,我們在 Astro 中添加了對 預測性模組提取 的支持。

這為您的 Qwik 組件啟用了即時互動性。預測性模組提取將在服務工作程序的後台預取應用程序捆綁包,以便在需要時,程式碼已經存在於瀏覽器緩存中。

您應該能夠立即使用 Qwik Insights

容器與孤島

雖然 Astro 通常採用帶有其他框架的孤島架構,但 Qwik 使用一種稱為 Qwik 容器 的不同策略。儘管方法不同,但兩者都有類似的局限性。

在 DOM 中,您可能會注意到沒有任何 <astro-island> 自定義元素,這是因為對於 Astro 來說,Qwik 看起來像是靜態數據。

這是因為在 Qwik 中,處理程序本身就是應用程序的根目錄/入口點。

跨容器通信

一個常見的限制是嘗試將狀態傳遞到另一個孤島或容器。

在現代 Web 開發中,共享狀態至關重要。問題是,當狀態需要在不同的容器或孤島之間共享時,我們如何實現這一點?

為什麼不使用全局信號或納米存儲?

Astro 的其他框架通過使用 納米存儲全局信號 來解決此問題。

雖然您可能會看到所有測試都通過了,並且應用程序按預期工作,但我們不建議使用納米存儲或全局信號。它們可能會在 SSR 上下文中導致一些意外行為。

例如,在 Solid 的教程中提到了以下內容

雖然可以使用全局狀態和計算,但上下文有時是更好的解決方案。此外,請務必注意,不應在 SSR(服務器端渲染)解決方案(例如 Solid Start)中使用全局狀態。在服務器上,全局狀態在請求之間共享,並且缺乏數據隔離會(並且將)導致錯誤、內存洩漏並具有安全隱患。建議應用程序狀態應始終通過上下文提供,而不是依賴全局。

自訂事件

在 Qwik 中,不包含全域信號狀態是一個設計決策。

我們建議使用自訂事件,它具有以下幾項優點:

  • 效能(避免不必要的狀態同步)
  • 在頁面載入時不會喚醒框架
  • 微前端 (MFE) 支援
  • 頁面上可以存在不同的版本
  • 事件驅動
  • 解耦

此範例 顯示如何在整個應用程式中使用自訂事件。請注意 counter.tsxrandom-island.tsx 和我們的 index.astro 頁面。

使用多個 JSX 框架

若要在 Astro 中使用多個 JSX 框架(如 Qwik、React、Preact 或 Solid),您需要設定規則,以決定每個框架應該處理哪些檔案。

例如,您可以將所有 Qwik 元件放在名為 qwik 的資料夾中。然後,將 Astro 設定為使用 Qwik 整合來處理此資料夾中的任何檔案。

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/*" }),
  ],
});

以上我們在同一個 Astro 專案中使用了 Qwik、React 和 Solid 整合。

如果我們查看第一個整合,它會在 qwik 資料夾中尋找任何檔案,並對此資料夾中的任何檔案使用 Qwik。

為了簡單起見,請考慮將常見的框架元件分組在同一個資料夾中(例如 /components/react//components/qwik/)。不過,這只是選用的。

Qwik React

如果您使用的是 React,我們建議您使用 @builder.io/qwik-react 整合。它是 @astrojs/react 的替代方案,並且可以讓您無縫地轉換到 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()],
  },
});

使用 Qwik-React,我們可以將 React 元件「Qwik 化」,並在我們的 Qwik 應用程式中使用它們,甚至可以在 Astro 檔案之外巢狀 Qwik 和 React 元件!

您不需要使用 qwikReact 指定 include 屬性。

這裡有一個範例,說明如何使用 qwik-react 整合來建立 React 元件。

/** @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);

建立計數器後,可以在我們的 index.astro 檔案中使用它。

<QReactCounter qwik:visible />

請注意,在 .astro 檔案中,我們使用 qwik: hydration 指令前置字元,這是為了防止與 Astro 預設提供的 hydration 指令衝突。

您也可以使用 client:* 前置字元,但只能在 tsx 檔案中使用。您可以在 Qwik 文件的 新增互動性 章節中找到指令清單。

Qwik React 元件仍然具有 hydration 功能,因此建議將 Qwik-React 作為轉移到可恢復元件的策略。

jsxImportSource

遺憾的是,TypeScript 只能有一個 jsxImportSource 預設值。如果您在 Astro 應用程式中同時使用 React、Solid 或 Preact 的 Astro 整合,請覆寫每個元件的匯入來源。

如果您使用的是 @astrojs/react,則可以使用 qwik-react 來代替。系統將會預設支援正確的設定。

/** @jsxImportSource react */
import { useState } from "react";
 
export const ReactCounter = () => {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
};

例如,Solid JS 是

/** @jsxImportSource solid-js */

例如,Preact 是

/** @jsxImportSource preact */

具名插槽

對於 Astro 中的具名插槽,請在標記中新增 slot,而不是新增 q:slot

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>

預設插槽在其 Qwik City 對應項目中按預期運作。

社群指南

影片

貢獻

我們非常歡迎您的貢獻!首先請閱讀我們的 貢獻指南。它包含您參與所需的所有資訊,包括關於整合如何在幕後運作的深入說明。

在 builder.io discord 中還有一個 qwik-astro 頻道,用於討論 API 變更、整合的可能想法,以及其他很酷的東西。😊

致謝

特別感謝 Astro 核心團隊的 Matthew 和 Nate!沒有他們的幫助,這個整合將無法實現。

Nate 的聯絡方式

貢獻者

感謝所有幫助改進此文件的貢獻者!

  • thejackshelton
  • hamatoyogi