Hydrogen 與無頭式商務
並非所有店面都適合 Liquid 佈景主題模式。當品牌需要像素級精確的自訂設計、類似應用程式的互動性,或與非 Shopify 資料來源整合時,他們會選擇無頭式架構。Hydrogen 是 Shopify 的解決方案——一個建構於 Remix 之上的 React 框架,專為無頭式 Shopify 商務而設計。本課程涵蓋何時以及如何使用 Hydrogen、其架構,以及如何建構您的第一個無頭式店面。
什麼是無頭式商務?
在傳統的 Shopify 設定中,店面(顧客看到的部分)和後端(資料存放的位置)是緊密耦合的。Shopify 在伺服器端渲染 Liquid 模板並傳送完整的 HTML 頁面。
在無頭式商務中,店面與後端是解耦的。您的自訂前端透過 Storefront API 從 Shopify 擷取資料,並以任何您想要的方式渲染使用者介面。Shopify 仍然處理產品、訂單、結帳和付款——您只需控制展示層。
何時使用 Hydrogen vs Liquid 佈景主題
| 情境 | 建議 |
|---|---|
| 標準電子商務商店 | Liquid 佈景主題 |
| 商家透過佈景主題編輯器管理內容 | Liquid 佈景主題 |
| 預算有限的專案 | Liquid 佈景主題 |
| 完全自訂的設計系統 | Hydrogen |
| 類似應用程式的互動(動畫、轉場) | Hydrogen |
| 多來源內容(CMS + Shopify + 自訂 API) | Hydrogen |
| 擁有 React 專業知識的開發團隊 | Hydrogen |
| 從單一 Shopify 後端運行多個店面 | Hydrogen |
| 高效能需求(串流式 SSR) | Hydrogen |
Hydrogen 功能強大,但並非總是最佳選擇。Liquid 佈景主題建構更快、商家更容易維護,且涵蓋 90% 的使用場景。只有當您有 Liquid 無法滿足的特定需求,且團隊能夠長期支援 React 應用程式時,才選擇 Hydrogen。
Hydrogen 架構
Hydrogen 建構於 Remix 之上,這是一個全端 React 框架。如果您了解 Remix,您已經知道 Hydrogen 的大部分內容。Shopify 在其上增加了一層商務特定的工具。
關鍵 Hydrogen 套件
@shopify/hydrogen:核心商務元件和工具(購物車、分析、SEO、貨幣、圖片)@shopify/hydrogen-react:與框架無關的 React hooks(可在 Hydrogen 之外使用)@shopify/remix-oxygen:Oxygen 主機託管的 Remix 介面卡@shopify/cli-hydrogen:用於建立和管理 Hydrogen 專案的 CLI 命令
建立 Hydrogen 專案
# 建立新的 Hydrogen 店面
npm create @shopify/hydrogen@latest -- --template demo-store
# CLI 會提示:
# ? Where would you like to create your app? hydrogen-store
# ? Choose a language: TypeScript
# ? Connect to Shopify: Use mock.shop (or connect your store)
專案結構
hydrogen-store/
├── app/
│ ├── components/ # 可重複使用的 UI 元件
│ │ ├── Header.tsx
│ │ ├── Footer.tsx
│ │ ├── ProductCard.tsx
│ │ └── CartDrawer.tsx
│ ├── routes/ # 基於檔案的路由(Remix)
│ │ ├── ($locale)._index.tsx # 首頁
│ │ ├── ($locale).products.$handle.tsx # 產品頁面
│ │ ├── ($locale).collections.$handle.tsx
│ │ ├── ($locale).cart.tsx
│ │ ├── ($locale).account.tsx
│ │ └── [sitemap.xml].tsx
│ ├── lib/
│ │ └── fragments.ts # 可重複使用的 GraphQL 片段
│ ├── styles/
│ │ └── app.css
│ ├── entry.server.tsx # 伺服器進入點
│ └── root.tsx # 根佈局
├── public/
│ └── favicon.svg
├── server.ts # Oxygen/Node 伺服器
├── storefrontapi.generated.d.ts # 自動產生的類型
├── .env # 環境變數
└── hydrogen.config.ts # Hydrogen 設定
Storefront API 整合
Hydrogen 使用 Storefront API 進行所有資料擷取。API 客戶端在伺服器進入點中設定,並透過 Remix context 傳遞給路由載入器。
設定客戶端
// server.ts
import {createStorefrontClient} from '@shopify/hydrogen';
const {storefront} = createStorefrontClient({
storeDomain: env.PUBLIC_STORE_DOMAIN,
publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN,
privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN,
storefrontApiVersion: '2026-04',
});
在路由載入器中擷取資料
Hydrogen 遵循 Remix 的模式,在伺服器端執行的 loader 函式 中載入資料:
// app/routes/($locale).products.$handle.tsx
import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {useLoaderData} from '@remix-run/react';
import {Image, Money, ShopPayButton} from '@shopify/hydrogen';
const PRODUCT_QUERY = `#graphql
query Product($handle: String!) {
product(handle: $handle) {
id
title
description
descriptionHtml
vendor
tags
featuredImage {
url
altText
width
height
}
priceRange {
minVariantPrice {
amount
currencyCode
}
}
variants(first: 100) {
nodes {
id
title
availableForSale
price {
amount
currencyCode
}
selectedOptions {
name
value
}
image {
url
altText
width
height
}
}
}
seo {
title
description
}
}
}
`;
export async function loader({params, context}: LoaderFunctionArgs) {
const {handle} = params;
const {storefront} = context;
const {product} = await storefront.query(PRODUCT_QUERY, {
variables: {handle},
cache: storefront.CacheLong(),
});
if (!product) {
throw new Response('Product not found', {status: 404});
}
return json({product});
}
export default function ProductPage() {
const {product} = useLoaderData<typeof loader>();
const firstVariant = product.variants.nodes[0];
return (
<div className="product-page">
<div className="product-grid">
<div className="product-image">
{product.featuredImage && (
<Image
data={product.featuredImage}
sizes="(min-width: 768px) 50vw, 100vw"
/>
)}
</div>
<div className="product-info">
<h1>{product.title}</h1>
<p className="vendor">{product.vendor}</p>
<Money
data={firstVariant.price}
className="product-price"
/>
<div
className="product-description"
dangerouslySetInnerHTML={{
__html: product.descriptionHtml,
}}
/>
<ShopPayButton
variantIds={[firstVariant.id]}
storeDomain={context.env.PUBLIC_STORE_DOMAIN}
/>
</div>
</div>
</div>
);
}
快取策略
Hydrogen 提供內建的快取工具,對效能至關重要:
// 在 storefront 客戶端上可用的快取策略
storefront.query(query, {
cache: storefront.CacheNone(), // 不快取(即時資料)
cache: storefront.CacheShort(), // 1 秒過期,60 秒最大值
cache: storefront.CacheLong(), // 1 小時過期,1 天最大值
cache: storefront.CacheCustom({
mode: 'public',
maxAge: 60, // 秒
staleWhileRevalidate: 300,
}),
});
- 產品頁面:
CacheLong()—— 產品資料變更不頻繁 - 商品系列頁面:
CacheLong()—— 與產品類似 - 購物車:
CacheNone()—— 必須始終為即時資料 - 搜尋結果:
CacheShort()—— 保持新鮮但可容忍短暫的過期 - 首頁:
CacheLong()配合內容變更時的手動失效
伺服器端渲染與串流
Hydrogen 利用 Remix 的串流式 SSR 來實現快速的初始頁面載入。伺服器不會等待所有資料解析完畢才傳送 HTML,而是立即串流 HTML 外殼,並在資料到達時填入動態內容。
// app/routes/($locale).collections.$handle.tsx
import {defer, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {Await, useLoaderData} from '@remix-run/react';
import {Suspense} from 'react';
export async function loader({params, context}: LoaderFunctionArgs) {
const {handle} = params;
const {storefront} = context;
// 關鍵資料:立即等待
const collection = await storefront.query(COLLECTION_QUERY, {
variables: {handle, first: 12},
});
// 非關鍵資料:延遲以進行串流
const recommendations = storefront.query(RECOMMENDATIONS_QUERY, {
variables: {handle},
});
return defer({
collection: collection.collection,
recommendations, // 這是一個 Promise,未被 await
});
}
export default function CollectionPage() {
const {collection, recommendations} = useLoaderData<typeof loader>();
return (
<div>
<h1>{collection.title}</h1>
{/* 關鍵內容立即渲染 */}
<ProductGrid products={collection.products.nodes} />
{/* 延遲內容在準備好時串流傳入 */}
<Suspense fallback={<RecommendationsSkeleton />}>
<Await resolve={recommendations}>
{(data) => (
<RecommendedProducts products={data.products.nodes} />
)}
</Await>
</Suspense>
</div>
);
}
這種模式確保顧客在幾毫秒內就能看到有意義的內容,即使某些資料需要更長時間載入。
Oxygen 主機託管
Oxygen 是 Shopify 的邊緣託管平台,專為 Hydrogen 店面而建。
部署
Oxygen 與 GitHub 整合以實現自動部署:
- 在 Shopify 管理後台的 銷售通路 > Hydrogen 下連接您的 GitHub 儲存庫
- 推送到您的主分支——Oxygen 自動部署
- 推送到任何其他分支——Oxygen 建立預覽部署
# 透過 Shopify CLI 手動部署
shopify hydrogen deploy
環境變數
透過 Shopify 管理後台或 CLI 管理環境變數:
# 為生產環境設定環境變數
shopify hydrogen env push
# 將環境變數拉到本地 .env
shopify hydrogen env pull
為何選擇 Oxygen
- 零設定:無需伺服器設定、CDN 設定或擴展決策
- 全球邊緣網路:Worker 在全球範圍內靠近顧客運行
- Shopify 最佳化:到 Shopify Storefront API 的最低延遲路徑
- 預覽部署:每個分支都有唯一的 URL 供審查
- 內建分析:在 Shopify 管理後台中進行效能監控
您可以將 Hydrogen 部署到任何 Node.js 主機託管供應商——Vercel、Netlify、Cloudflare Workers、Fly.io 或您自己的伺服器。Oxygen 方便且針對 Shopify 最佳化,但不會造成鎖定。
入門模板
Shopify 提供多個 Hydrogen 入門模板:
| 模板 | 描述 |
|---|---|
demo-store | 包含所有頁面的完整店面 |
hello-world | 最小起始點 |
skeleton | 包含路由的基本結構,無樣式 |
# 從特定模板建立
npm create @shopify/hydrogen@latest -- --template demo-store
# 或克隆並自訂
npm create @shopify/hydrogen@latest -- --template skeleton
demo-store 模板包含產品頁面、商品系列頁面、購物車功能、顧客帳戶、搜尋、部落格和 SEO——一個可以自訂的完整店面。
重點整理
- Hydrogen 是一個用於建構無頭式 Shopify 店面的 React + Remix 框架
- 當您需要完全的設計控制、React 專業知識或多來源資料整合時使用它
- Storefront API 是資料層——透過路由載入器中的型別化 GraphQL 查詢存取
- 使用
defer和Await的串流式 SSR 實現快速的初始頁面載入 - Oxygen 提供零設定的邊緣託管,支援 GitHub 整合和預覽部署
- 大多數商店應使用 Liquid 佈景主題——Hydrogen 適用於特定的高端使用場景
接下來,我們將探索 Shopify Functions——讓您直接在 Shopify 基礎設施內自訂商務邏輯的 WebAssembly 執行時。