靜態網站生成 (SSG) 概覽
靜態網站生成,通常簡稱為「SSG」,是將網站網頁預先渲染成靜態 HTML 檔案的過程。其優點是,當訪客請求網頁時,回應是一個預先生成的 HTML 檔案(靜態檔案),不需要在訪客的瀏覽器上「重建」網頁的 HTML,也不需要由您的伺服器動態建立(稍後將詳細介紹)。
此外,由於 Qwik 的底層架構,頁面效能也受益於不需要 JavaScript「水合」步驟,這可以顯著降低效能並減慢使用者互動。透過使用 SSG 預先渲染靜態 index.html
檔案,並結合 Qwik 的可恢復性,靜態網站生成提供了許多優於傳統解決方案的效能優勢。
SSG 與伺服器端渲染 (SSR) 的比較
Qwik City 可以將 Qwik 應用程式(無論是「網路應用程式」還是「網站」)生成靜態 HTML。一旦生成為 HTML,Qwik 基本上就可以透過使用可恢復性來跳過重建應用程式的步驟,因為應用程式已經生成為 HTML。靜態網站生成 (SSG) 和伺服器端渲染 (SSR) 都使用相同的過程來生成 HTML。然而,SSG 和 SSR 之間的主要區別在於 HTML「何時」生成。
在傳統設定中,SSG 會在建置時預先渲染每個網頁,而 SSR 會針對每個 HTTP 請求按需渲染每個網頁。SSG 只需要在每次建置時生成一次 HTML,這對於多個訪客應該看到相同內容的網頁來說非常有用。相反,當每個訪客的網頁可能不同,並且需要為每個 HTTP 請求渲染自訂 HTML 時,SSR 就非常有用。
例如,SSG 非常適合部落格或文件網站,因為所有內容對於多個訪客來說都應該相同。雖然 SSR 可能適用於部落格,但對於您的 HTTP 伺服器來說,為每個訪客渲染部落格內容可能會造成不必要的負擔,即使他們最終都會看到相同的 HTML。
但是,帳戶儀表板通常會為每個登入使用者顯示不同的內容。在此設定中,每個使用者都應該獲得自己的渲染 HTML,其中包含其帳戶資訊,而不是每個人都看到完全相同的內容。這就是 SSR 的優勢所在。
理想情況下,使用靜態網站生成的功能越多越好,因為這會降低您的伺服器成本並加快回應時間。
然而,使用 Qwik City 時,使用 SSG 還是 SSR 並不一定是二選一的決定。相反,您自己的實作可以選擇讓某些路由路徑使用 SSG,而其他頁面使用 SSR。這完全取決於您和您的需求。
靜態網站生成設定
靜態網站生成是從內建的轉接器建立的,若要建立轉接器,請執行
npm run qwik add static
選擇 轉接器:靜態網站 (.html 檔案)
。完成!
變更
執行上述命令將會對您的專案進行以下變更
build.server
腳本將會自動新增到您的package.json
檔案中。- 將會建立
adapters/static/vite.config.ts
檔案。
您的建置檔案將會生成到 dist
資料夾中。
您可以使用以下命令建置您的靜態網站
npm run build.server
SSG 設定
adapters/static/vite.config.ts
檔案也包含 SSG 設定,每個實作的設定都不同。
origin
URL origin
是由協定 (protocol) 和主機名稱 (domain) 組合而成。例如,https://qwik.dev.org.tw
的協定為 https://
,網域為 qwik.dev
。但請注意,origin
並 *不* 包含 pathname
。
origin
用於在靜態網站生成 (SSG) 期間提供完整的 URL,並模擬完整的 URL,而不僅僅是 pathname
。例如,為了要呈現正確的規範標籤 URL 或 sitemap.xml
中的 URL,必須一併提供 origin
。
如果網站也是以 /
以外的路徑名稱開頭,請使用 Vite 設定選項中的 base
選項(Qwik City 設定選項中的 basePathname
選項已棄用)。
outDir
outDir
是一個檔案系統輸出目錄,用於寫入靜態檔案。在上面的範例中,它使用 Node 的 fileURLToPath 建立一個絕對的檔案系統路徑,用於寫入靜態 HTML 檔案。
JavaScript 執行環境
對於 JavaScript 專案來說,建置的執行環境通常是建立在 Node.js 之上。然而,Qwik City 靜態網站生成的核心並不侷限於僅使用 Node.js,這就是為什麼 qwikCityGenerate()
函式是從 @builder.io/qwik-city/static/node
匯入的原因。藉由將產生函式限定在特定的執行環境(例如 Node.js),Qwik City 就能夠在未來也能夠從其他執行環境(例如 Deno 或 Bun)產生 SSG。
動態 SSG 路由
到目前為止,我們只討論了如何為單一路由路徑產生靜態 HTML 檔案。然而,在大多數情況下,您會希望為具有動態參數的多個路由路徑產生 HTML 檔案。例如,產品網站可能會為每個產品提供一個路由路徑,例如 /product/:id
。在這種情況下,您會希望為每個產品頁面產生 HTML 檔案,這就需要為每個產品 ID 產生 HTML 檔案。
import { component$ } from '@builder.io/qwik';
import { useLocation, type StaticGenerateHandler } from '@builder.io/qwik-city';
import { loadProductIds } from './load-product-ids';
export default component$(() => {
const { params } = useLocation();
return <p>Example: {params.id}</p>;
});
export const onStaticGenerate: StaticGenerateHandler = async ({ env }) => {
// example of loading params for this use case
// every implementation will be different
const ids = await loadProductIds({
apiKey: env.get('API_KEY'),
});
return {
params: ids.map((id) => {
return { id };
}),
};
};
在上面的範例中,onStaticGenerate()
函式藉由請求從環境變數中擷取的 API 金鑰後面的 API,從 loadProductIds()
函式中載入產品 ID。這個函式會針對每個實作進行客製化,但一般的概念是,您需要載入每個產品 ID 的資料,然後為每個產品 ID 產生 HTML 檔案。
onStaticGenerate
函式應該從模組的最上層匯出,並且應該回傳一個具有 params
屬性的物件。params
屬性應該是一個物件陣列,其中每個物件都是路由路徑的一組參數。例如,如果路由路徑是 /product/:id
,則 params
陣列應該是一個具有 id
屬性的物件陣列。
這個範例的目錄結構如下
src/
└── routes/
└── product/
└── [id]/
└── index.tsx
請注意,index.tsx
檔案位於名為 [id]
的目錄中。這是一個特殊的目錄名稱,它會告訴 Qwik City 為每個 id
參數產生 HTML 檔案。index.tsx
檔案是 Qwik City 在為路由路徑產生 HTML 檔案時將使用的預設檔案。