Skip to main content

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
大多數商店應使用 Liquid

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 整合以實現自動部署:

  1. 在 Shopify 管理後台的 銷售通路 > Hydrogen 下連接您的 GitHub 儲存庫
  2. 推送到您的主分支——Oxygen 自動部署
  3. 推送到任何其他分支——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 管理後台中進行效能監控
Oxygen 並非必需

您可以將 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 查詢存取
  • 使用 deferAwait串流式 SSR 實現快速的初始頁面載入
  • Oxygen 提供零設定的邊緣託管,支援 GitHub 整合和預覽部署
  • 大多數商店應使用 Liquid 佈景主題——Hydrogen 適用於特定的高端使用場景

接下來,我們將探索 Shopify Functions——讓您直接在 Shopify 基礎設施內自訂商務邏輯的 WebAssembly 執行時。