shopify-hydrogen について
HydrogenでShopifyのカスタムストアフロントを構築する開発者向けのスキルです。Reactベースのヘッドレスフレームワークを使い、Storefront APIのクエリ、カート機能、キャッシュ設定、Oxygenへのデプロイを扱います。
主な機能
- 01ReactとRemixによるストア構築
- 02Shopify Storefront APIのクエリ
- 03Hydrogenユーティリティによるカート管理
- 04キャッシュ戦略の設定
- 05Oxygenへのデプロイ
活用シーン
- 01Shopifyストアのデザインと体験のカスタマイズ
- 02商品・コレクションページのデータ取得
- 03サーバー側カート操作の実装
- 04HydrogenストアのOxygenへのデプロイ
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ finsilabs/ awesome-ecommerce-skills --skill shopify-hydrogenインストール後、Claude Code で/shopify-hydrogenを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
tile.jsonevals/cart-implementation-with-server-side-sta/criteria.jsontask.mdevals/project-configuration-and-deployment/criteria.jsontask.mdevals/storefront-api-querying-and-caching/criteria.jsontask.md詳細
Shopify Hydrogen
概要
Hydrogen は、ヘッドレスストアフロントを構築するための Shopify 公式の React ベースフレームワークです。Remix を基盤とし、Oxygen(Shopify のエッジホスティング)にデプロイされます。Storefront API 向けの第一級プリミティブ(商品クエリ、カート管理、顧客アカウント)に加え、キャッシュ、ストリーミング、SEO を自動的に処理する Shopify 固有のコンポーネントとフックを提供します。このスキルでは、Hydrogen プロジェクトの作成、Storefront API のクエリ、カート機能の実装、Oxygen へのデプロイについて説明します。
このスキルを使用する場面
- デザインと UX を完全に制御できるカスタム Shopify ストアフロントを構築するとき
- デフォルトの Shopify オンラインストアテーマでは、デザイン要件を満たせないとき
- サーバーサイドレンダリング、ストリーミング、エッジデプロイによるパフォーマンスが必要なとき
- サードパーティサービス(ロイヤルティ、CMS、パーソナライゼーション)をストアフロントに直接統合するとき
- Shopify 管理のバックエンドを使いながら、完全にカスタムのフロントエンドスタックを使いたいとき
前提条件とプラットフォームに関する注意事項
このスキルはカスタム/ヘッドレスストアフロント向け(Node.js、Python、または類似のバックエンド)に書かれています。コード例では TypeScript/Node.js を使用していますが、任意のスタックに適応できます。
Shopify:Shopify Hydrogen は Shopify のヘッドレスフレームワークです。Shopify をコマースバックエンドとしてカスタムフロントエンドと組み合わせる場合や、Shopify を他の最適なサービスと組み合わせる場合に、MACH/コンポーザブルのパターンを適用できます。 WooCommerce:WooCommerce は、REST API と WPGraphQL を通じてヘッドレスバックエンドとして機能します。フロントエンドを WordPress から切り離す場合に、これらのパターンを適用できます。 Magento:Magento の GraphQL API と PWA Studio は、ヘッドレスアーキテクチャをサポートしています。MACH スタックで Magento をバックエンドサービスとして使用する場合に、これらのコンポーザブルパターンを適用できます。
必要なもの:
- Node.js 18+(またはバックエンドの言語に合わせて調整してください)
- キャッシュ/キュー用の Redis
- メール送信サービス(SendGrid、AWS SES、または Postmark)
- CDN(Cloudflare、CloudFront、または Fastly)
主な手順
-
Hydrogen プロジェクトを作成する
npm create @shopify/hydrogen@latest -- --quickstart # or with options: npm create @shopify/hydrogen@latest # Follow prompts: project name, language (TypeScript), mock shop or real credentials cd my-hydrogen-store npm run dev # http://localhost:3000プロジェクト構造は Remix のファイルベースルーティングに従います。
app/ routes/ _index.tsx # Homepage products.$handle.tsx # Product detail page collections.$handle.tsx cart.tsx components/ lib/ fragments.ts # Reusable GraphQL fragments server.ts # Hydrogen + Remix entry point -
Storefront API の認証情報を設定する
Shopify 管理画面で Apps → Develop apps → Create an app → Storefront API を開き、Storefront API トークンを作成します。
# .env SESSION_SECRET="your-session-secret" PUBLIC_STOREFRONT_API_TOKEN="your-public-token" PUBLIC_STORE_DOMAIN="your-store.myshopify.com" PUBLIC_STOREFRONT_API_VERSION="2025-01"server.tsは Hydrogen を Remix に接続します。import {createHydrogenContext} from '@shopify/hydrogen'; const hydrogenContext = createHydrogenContext({ storefront: { apiVersion: env.PUBLIC_STOREFRONT_API_VERSION, privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN, publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN, storeDomain: env.PUBLIC_STORE_DOMAIN, }, session: HydrogenSession.init(request, [env.SESSION_SECRET]), }); -
Storefront API にクエリを送信する
Hydrogen は、キャッシュポリシーが組み込まれた
storefront.queryメソッドを提供します。// app/routes/products.$handle.tsx import {useLoaderData} from '@remix-run/react'; import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen'; export async function loader({params, context}: LoaderFunctionArgs) { const {storefront} = context; const {product} = await storefront.query(PRODUCT_QUERY, { variables: {handle: params.handle}, cache: storefront.CacheLong(), // Cache at CDN for 24h }); if (!product) throw new Response('Not Found', {status: 404}); return json({product}); } const PRODUCT_QUERY = `#graphql query Product($handle: String!) { product(handle: $handle) { id title descriptionHtml featuredImage { url altText width height } variants(first: 20) { nodes { id title price { amount currencyCode } availableForSale selectedOptions { name value } } } } } ` as const; -
Hydrogen のカートユーティリティでカートを実装する
Hydrogen は Remix のアクション関数を介して、サーバーサイドのカートアクションを提供します。
// app/routes/cart.tsx import {CartForm} from '@shopify/hydrogen'; import type {ActionFunctionArgs} from '@shopify/remix-oxygen'; export async function action({request, context}: ActionFunctionArgs) { const {cart} = context; const formData = await request.formData(); const {action, inputs} = CartForm.getFormInput(formData); let result; switch (action) { case CartForm.ACTIONS.LinesAdd: result = await cart.addLines(inputs.lines); break; case CartForm.ACTIONS.LinesUpdate: result = await cart.updateLines(inputs.lines); break; case CartForm.ACTIONS.LinesRemove: result = await cart.removeLines(inputs.lineIds); break; default: throw new Error(`Unhandled cart action: ${action}`); } const headers = cart.setCartId(result.cart.id); return json(result, {headers}); } // Add to cart form component export function AddToCartButton({variantId}: {variantId: string}) { return ( <CartForm route="/cart" action={CartForm.ACTIONS.LinesAdd} inputs={{lines: [{merchandiseId: variantId, quantity: 1}]}} > <button type="submit">Add to Cart</button> </CartForm> ); } -
Hydrogen のキャッシュ戦略を使用する
Hydrogen は、CDN の Cache-Control ヘッダーに対応する名前付きキャッシュ戦略を公開しています。
// Long cache for static catalog data const {collections} = await storefront.query(COLLECTIONS_QUERY, { cache: storefront.CacheLong(), // s-maxage=3600, stale-while-revalidate=82800 }); // Short cache for inventory-sensitive data const {product} = await storefront.query(PRODUCT_WITH_INVENTORY, { cache: storefront.CacheShort(), // s-maxage=1, stale-while-revalidate=9 }); // No cache for personalized/cart data const {customer} = await storefront.query(CUSTOMER_QUERY, { cache: storefront.CacheNone(), }); // Custom strategy const {data} = await storefront.query(QUERY, { cache: storefront.CacheCustom({ mode: 'public', maxAge: 600, staleWhileRevalidate: 3000, }), }); -
Oxygen にデプロイする
npm install -g @shopify/cli shopify hydrogen deploy # Creates a deployment in your Shopify admin under Online Store → Themes → HeadlessCI/CD では、GitHub Action を使用します。
# .github/workflows/oxygen.yml - uses: Shopify/hydrogen-action@v1 with: shop: ${{ secrets.SHOPIFY_SHOP_DOMAIN }} token: ${{ secrets.SHOPIFY_CLI_TOKEN }}
例
フィルタリングと並べ替えを備えたコレクションページ
// app/routes/collections.$handle.tsx
export async function loader({params, request, context}: LoaderFunctionArgs) {
const {storefront} = context;
const url = new URL(request.url);
const sortKey = url.searchParams.get('sort') as ProductCollectionSortKeys | null;
const {collection} = await storefront.query(COLLECTION_QUERY, {
variables: {
handle: params.handle,
first: 24,
sortKey: sortKey ?? 'BEST_SELLING',
reverse: sortKey === 'PRICE' ? false : true,
},
cache: storefront.CacheShort(),
});
return json({collection});
}
const COLLECTION_QUERY = `#graphql
query Collection(
$handle: String!
$first: Int
$sortKey: ProductCollectionSortKeys
$reverse: Boolean
) {
collection(handle: $handle) {
id
title
description
image { url altText }
products(first: $first, sortKey: $sortKey, reverse: $reverse) {
nodes {
id
title
handle
priceRange { minVariantPrice { amount currencyCode } }
featuredImage { url altText }
}
pageInfo { hasNextPage endCursor }
}
}
}
` as const;
新しい Customer Account API による顧客認証
// Hydrogen supports the new Customer Account API (OAuth-based)
// app/lib/customer-account.server.ts
export async function loader({context}: LoaderFunctionArgs) {
const {customerAccount} = context;
const isLoggedIn = await customerAccount.isLoggedIn();
if (!isLoggedIn) {
return redirect('/account/login');
}
const {data} = await customerAccount.query(`#graphql
query Customer {
customer {
id
firstName
lastName
emailAddress { emailAddress }
orders(first: 10) {
nodes {
id
number
processedAt
financialStatus
totalPrice { amount currencyCode }
}
}
}
}
`);
return json({customer: data.customer});
}
ベストプラクティス
- カタログデータには
storefront.CacheLong()を使用します — 商品データとコレクションデータはほとんど変更されないため、キャッシュTTLを長くすると、OxygenのエッジネットワークでTTFBが大幅に改善します。 - GraphQLクエリをルートと同じ場所に配置します —
as constフラグメント文字列をローダーと同じファイルに定義すると、データ要件が把握しやすくなり、TypeScriptの型推論も有効になります。 - Hydrogenの
<Image>と<Money>コンポーネントを使用します — Shopify CDNの画像最適化URLと通貨の書式設定を自動で処理します。 - 重要度の低いデータにはRemixのdeferとSuspenseを活用します — 商品をすぐに表示し、
defer()でおすすめ商品やレビューをストリーミング配信します。 - カートの状態はCookieを使ってサーバー側で管理します — Hydrogenのカートユーティリティは署名付きCookieにカートIDを保存します。SSRが正しく動作しなくなる、クライアント側だけでのカート状態管理は避けてください。
- Storefront APIの
@inContextディレクティブを使用します — リクエストごとにローカライズされた価格と翻訳済みコンテンツを取得するため、languageとcountryのコンテキストを渡します。 .envでStorefront APIのバージョンを固定します — Shopifyは古いAPIバージョンを廃止するため、明示的に固定すると、API更新時の予期しない不具合を防げます。
よくある落とし穴
| 問題 | 解決策 |
|---|---|
| 「Storefront APIトークンが認可されていません」 | トークンにunauthenticated_read_*スコープがあることを確認します。プライベートトークンはサーバー側のリクエスト専用です。 |
| ページ遷移の間にカートの状態が失われる | cart.setCartId()を使ってセッションCookieにカートIDを保存します。カートIDをコンポーネントの状態に保存しないでください。 |
| Oxygenで画像が最適化されない | Hydrogenの<Image>コンポーネント、またはgetImageData()ヘルパーを使用して、Shopify CDNの変換パラメーターを追加します。 |
| GraphQLクエリでTypeScriptエラーが発生する | クエリを変更した後にnpm run codegenを実行して型を再生成します。クエリにはas constのタグ付けが必要です。 |
| 「環境変数が不足しています」というエラーでデプロイに失敗する | Oxygenの環境変数は、.envだけでなく、Shopify管理画面のHydrogenデプロイ設定で追加する必要があります。 |
関連スキル
- @saleor-development
- @jamstack-storefront
- @composable-commerce
- @pwa-storefront
- @commerce-api-gateway