Hydrogen 与无头商务
并非每个店面都适合 Liquid 主题模型。当品牌需要像素级精准的自定义设计、类应用的交互体验,或与非 Shopify 数据源集成时,就需要无头架构。Hydrogen 是 Shopify 的解决方案——一个基于 Remix 构建的 React 框架,专为无头 Shopify 商务打造。本课程涵盖何时以及如何使用 Hydrogen、它的架构,以及如何构建你的第一个无头店面。
什么是无头商务?
在传统的 Shopify 设置中,店面(客户看到的内容)和后端(数据所在位置)是紧密耦合的。Shopify 在服务器端渲染 Liquid 模板,并交付完整的 HTML 页面。
在无头商务中,店面与后端是解耦的。你的自定义前端通过 Storefront API 从 Shopify 获取数据,并按照你想要的方式渲染 UI。Shopify 仍然处理产品、订单、结账和支付——你只需控制展示层。
何时使用 Hydrogen 与 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,用于 Shopify(可在 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 上下文传递给路由加载器。
配置客户端
// 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 模式,在服务器端运行的加载器函数中加载数据:
// 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,未被等待
});
}
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 查询访问
- 流式 SSR 与
defer和Await配合使用,实现快速初始页面加载 - Oxygen 提供零配置的边缘托管,支持 GitHub 集成和预览部署
- 大多数商店应该使用 Liquid 主题 —— Hydrogen 适用于特定的高端用例
接下来,我们将探索 Shopify Functions —— 让你直接在 Shopify 基础设施内自定义商务逻辑的 WebAssembly 运行时。