mcpField
S
shopify-hydrogen

shopify-hydrogen

github.com/finsilabs開発6083 回インストール1 週間前に更新
リポジトリ

shopify-hydrogen について

HydrogenでShopifyのカスタムストアフロントを構築する開発者向けのスキルです。Reactベースのヘッドレスフレームワークを使い、Storefront APIのクエリ、カート機能、キャッシュ設定、Oxygenへのデプロイを扱います。

主な機能

  1. 01ReactとRemixによるストア構築
  2. 02Shopify Storefront APIのクエリ
  3. 03Hydrogenユーティリティによるカート管理
  4. 04キャッシュ戦略の設定
  5. 05Oxygenへのデプロイ

活用シーン

  1. 01Shopifyストアのデザインと体験のカスタマイズ
  2. 02商品・コレクションページのデータ取得
  3. 03サーバー側カート操作の実装
  4. 04HydrogenストアのOxygenへのデプロイ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill shopify-hydrogen

インストール後、Claude Code で/shopify-hydrogenを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

tile.json
evals/cart-implementation-with-server-side-sta/
criteria.json
task.md
evals/project-configuration-and-deployment/
criteria.json
task.md
evals/storefront-api-querying-and-caching/
criteria.json
task.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)

主な手順

  1. 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
    
  2. 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]),
    });
    
  3. 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;
    
  4. 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>
      );
    }
    
  5. 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,
      }),
    });
    
  6. Oxygen にデプロイする

    npm install -g @shopify/cli
    shopify hydrogen deploy
    # Creates a deployment in your Shopify admin under Online Store → Themes → Headless
    

    CI/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

コメント