Skip to main content

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
大多数商店应该使用 Liquid

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 集成,实现自动部署:

  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 查询访问
  • 流式 SSRdeferAwait 配合使用,实现快速初始页面加载
  • Oxygen 提供零配置的边缘托管,支持 GitHub 集成和预览部署
  • 大多数商店应该使用 Liquid 主题 —— Hydrogen 适用于特定的高端用例

接下来,我们将探索 Shopify Functions —— 让你直接在 Shopify 基础设施内自定义商务逻辑的 WebAssembly 运行时。