Yuki's Tech Blog

仕事で得た知見や勉強した技術を書きます。

Hydrogenにざっくり入門してカスタムストアフロントを構築してみる

目次

Hydrogenに入門する理由

新しく入社する会社で触る技術なので、あらかじめマスターしておきたいと思い、入門しました。

Hydrogenとは

Hydrogenとは、Shopify公式のReactベースのフレームワークです。カスタムストアフロントを開発するのに使用します。独自でNext.js + Storefront APIなどでカスタムストアフロントを開発するよりも、APIコールやレンダリング処理など多くの面で最適化されるそうです。

(※)Hydrogenを使わなくても、カスタムストアフロントは作成できます。フロントエンド側の実装にはStorefront APIを用いること以外の技術的制約はありません。

Hydrogenの3つの特徴

実際にHydrogenを触って感じた3つの特徴を、以下に記載します。

  1. ECサイトを構築するのに便利なコンポーネントやhooksが提供されている
    ECサイトを構築するために便利なコンポーネントやhooksが提供されています。自分はまだuseShopくらいしか使ったことありませんが、ざっと見て便利なものが提供されているなという印象です。

  2. React Server Componentsを用いたSSRをサポートしている
    React Server Componentsとは、一部のReactコンポーネントをサーバーサイドでレンダリングするReactの新しい技術です。一部のコンポーネント(Server Components)をサーバーサイドでレンダリングすることで、アプリケーションのパフォーマンスを向上させることができます。React Server Componentsでは、特別に理由がなければサーバー側でコンテンツを描画させた方が良いです。

  3. ファイルを用いたルーティングを採用している(Next.jsに似てる)
    ある法則に沿って配置したファイルが、そのままサイトのルーティングになります。例えば、http://localhost:3000/hogeへの訪問は、src/routes/foo.tsxというファイルで処理されます。また、[]で囲まれた文字はパスパラメータとして処理されます。例えば、src/routes/[hoge].tsxというファイルなら、次のようなPropsとして、このページを実装するReact Componentに渡ります。
  type Props = {
    params: {
      hoge: string;
    };
  };

(※)ちなみに以下のサイトが特徴1の公式ドキュメントです。
Hydrogen components, hooks, and utilities overview

React Server Componentsの使い方

React Server Componentsは、コンポーネントを三種類(Server/Client/Shared Components)に分類します。Server Components(サーバーでのみレンダリングされるコンポーネント)を作成したい場合、拡張子を .server.tsx にします。また、Client Componentsを作成したい場合、拡張子を .client.tsx にします。 各コンポーネントの特徴を以下にまとめます。

種類 使い方 特徴 いつ使うか
Server Components 拡張子を .server.tsx にする Server Componentsは、サーバーでのみレンダリングされるコンポーネント。ステートを持てないので、useStateやuseReducerが使えない。再レンダリングができないので、ライフサイクルフックであるuseEffectやuseLayoutEffectが使えない。サーバーでレンダリングされるため、ブラウザでのみ利用可能なAPI(DOMやWeb API)が利用できない。関数はシリアライズできないため、Client ComponentsのPropsに関数を渡すことができない。Server Componentは、Client Componentを子コンポーネントに持つことができる。 レンダリングが起こらないであろう部分のコンポーネントを、Server Componentsにする。パフォーマンス向上のため、基本的にはServer Componentsを使う。
Client Components 拡張子を .client.tsx にする Client Componentsは、従来のクライアントでのみレンダリングされるコンポーネント。ステートを持ったり、イベントをハンドルしたり、Web APIを利用したりする必要がある場合は、Client Componentにする。Clinet ComponentではServer Componentsをimportできないが、Server ComponentがClient Componentに対して、childrenなどのpropを通してServer Componentsを渡すことはできる。 ステートが必要だったり、イベントをハンドルしたい場合、Client Componentにする。
Shared Components 拡張子を.tsxにする Shared Componentsは、サーバーとクライアントのどちらでもレンダリング可能なコンポーネント。Server Componentから呼ばれた場合はServer Componentとして、Client Componentから呼ばれた場合はClient Componentとして振る舞う。両方の制約を持つため、ステートは持てず、Server Componentsをimportできない。 Client Components内でも使いたいServer Componentは、Shared Componentにする(Client Componentから呼ばれた場合はClient Componentとして振る舞う)。

↓ 画像引用(How React server components work: an in-depth guide)

そもそもShopifyとは

Shopifyとは、簡単にECサイトを構築・運用するためのプラットフォームです。Shopifyを使うことで、全くコードを書かなくてもECサイトを構築することができます。

また、ShopifyはWeb APIを提供している為、フロントエンドを独自に構築して、連携させることもできます。APIを利用することで、商品、注文、顧客管理、配送、決済など多くのECに必要な仕組みを利用することができ、顧客体験のカスタマイズに集中できます。

Eコマース(EC)とは

Eコマース(EC)とは、電子商取引のことです。一般的には、インターネットを通じた取引を表します。

(※)ちなみにeコマースとは、電子を表す「エレクトロニック(Electronic)」と、商売を表す「コマース(Commerce)」を組み合わせた造語です。

マーチャントとは

マーチャントとは、販売者のことです。

Shopifyの5つの特徴

  1. クラウド型のサービス(SaaS)
    クラウド型のサービス(SaaS)なので、別途サーバーの設置や環境構築が必要ではありません。

  2. 拡張性の高さ
    テーマ、アプリ(拡張機能)、API、カスタムストアフロント等、拡張性が高いです。

  3. 各種売り場の連携
    売り場ごとの在庫や売り上げをShopifyで一元管理できます。

  4. 決済機能を簡単に作成できる
    「Shopify Payments」というShopify独自の決済プラットフォームを用いることで、クレジットカードやコンビニ決済などを簡単に対応させることができます。管理画面から利用を申請すれば、すぐに利用可能です。

  5. 越境ECに対応
    言語、通貨の切り替えや税金(関税など)、配送地域の設定など細かな対応が可能です。

開発ストアとは

開発ストアとは、 開発用のShopifyストア です。構築したテーマやアプリのテスト、クライアント用のShopifyストアを構築するために使用できます。

(※)Shopifyパートナーであれば、無料で無制限に開発ストアを作成できます。

(※)Shopify Partner(パートナー)とは、会社または個人が、Shopifyと結ぶパートナーシップのことです。登録費は無料です。

Shopify Partner(パートナー)とは?世界で注目されているエコシステム – コマースメディア株式会社

Shopify CLIとは

Shopify CLIとは、Shopifyアプリの構築に役立つCLIツールです。Node.js, Ruby on Rails, PHPアプリのプロジェクトやShopifyテーマの雛形を作成できます。

Shopifyで扱える主なWeb API

Shopifyでは、以下のWeb APIが提供されています。

名称 用途 API仕様
AdminAPI ECサイト運営の主要なデータ(カスタマー情報、商品情報)を取得・操作できます GraphQL、REST API
StorefrontAPI 独自のWebサイトやモバイルアプリといったクライアントアプリから商品情報、顧客の注文を操作することができます GraphQL
PartnerAPI パートナーダッシュボードにあるデータへプログラムでアクセスするために使用します GraphQL
PaymentsAppsAPI ストアでのカスタマーの決済方法をカスタマイズできます GraphQL
MessagingAPI (Beta) ShopifyInboxを通じてメッセージを送受信できます REST API
Multipass 別のWebサイトでカスタマーがアカウントを持っている場合、そのカスタマーをShopifyストアにリダイレクトさせてログインさせます 調査中

(※)Admin APIには2種類のAPI仕様がありますが、REST APIよりもGraphQLの使用が推奨されています。

ECサイトで頻繁に扱うオブジェクト

Shopifyのデータは概念をイメージしやすく扱いやすくするために、抽象化されたオブジェクト群で構成されています。以下のオブジェクトがECサイトで頻繁に扱われます。

カテゴリ 名前 説明
顧客 Customer ストアで商品を購入するエンドユーザー
注文 Order 注文
注文 LineItem 注文商品
商品 Product 商品
商品 ProductVariant 商品のバリエーション
出荷 Fulfillment 出荷
在庫 InventoryItem 在庫 

テーマについて

テーマとは、デザインテンプレートのことです。テーマを使うことで、HTMLやCSSなどの技術的コストをかけずに高品質なShopifyに連動したストアを立ち上げることができます

(注) テーマはオンラインストア(Liquid)にしか適用できません。

テーマを編集する2つの方法

テーマの編集するには、2つの方法があります。

  1. テーマエディタ(GUI)
    ノーコードでカスタマイズします。日々の運用などでコンテンツが変動する場合に使います。

  2. コード
    細かなデザインなど自由な編集が可能です。テーマに存在しない機能を開発するときに使います。

テーマの構造について

Shopifyのテーマは、カスタマイズしていくことを前提に以下のような構成になっています。

構成要素 意味
layouts 表示するテンプレートの土台になるもの。headタグなどを含む
templates ページ単位で実装されるファイル
sections ページ内に実装されるコンポーネント
snippets section内で利用できる再利用可能なコンポーネント
locales 言語別ファイル
assets 画像、アイコン、JS、CSSファイルなど
config テーマ全体の設定情報などの保存

(※) 2021年6月末に発表されたバージョンでは、各ページの内容やデザインを「セクション」という単位で自由に変更できる仕組みが実装され、ノーコードでサイトの編集が可能になりました。また、セクションには子要素があり、「ブロック」と呼ばれます。

テーマ自体をカスタマイズする方法

テーマをカスタマイズするためには、HTMLやCSS、Shopifyが提供するLiquid言語を使います。

ヘッドレスコマースとは

ヘッドレスコマースとは、ECサイトの「フロントエンド」と「バックエンド」を分離したアーキテクチャのことです。Shopifyの場合、Storefront APIを境界にしてECサイトの「フロントエンド」と「バックエンド」が分離されています。「バックエンド」=管理画面と「フロントエンド」=オンラインストアが分離してサービスを提供しています。つまり、ヘッドコマースを採用しているECサイトは、管理画面とオンラインストアが別のサーバーで動作していることが分かります。 

カスタムストアフロントとは

カスタムストアフロントとは、ヘッドレスコマースによって分離されたバックエンドと連携してオンラインストア(Liquid)とは違う「カスタム」されたフロントエンドを提供するための機能です。

ざっくり言うと、カスタムストアフロントとは、オンラインストア(Liquid)とは別に提供される、独自の「ECサイトのフロントエンド」です。

カスタムストアフロントとオンラインストアの違い

カスタムストアフロントとオンラインストアには以下のような違いがあります。

オンラインストア カスタムストアフロント
見た目の構築 Liquid 制限なし
バックエンドデータの取得 オンラインストアのLiquidで取得できる独自変数 StorefrontAPI
カスタマイズ性 高くも低くもない。サイト構成はShopfyのルールに準ずる 高い
サービス提供までのコスト 低い。既存のテーマを流用でき、簡単なカスタマイズは容易 非常に高い。原則としてマーチャントが一からUIを構築する必要がある
サービス運用のコスト 低い。ShopifyのBasic Plan以上の基本機能に含まれる。運用コストを意識する場面は少ない 非常に高い。原則としてマーチャントが運用環境を設計・運用する必要がある

比較してみると、カスタムストアフロントはカスタマイズ性において優れているものの、開発や運用のコストが高いことが分かります。

Storefront API

カスタムストアフロントからバックエンド(Shopify)と通信するためには、Storefront APIを使用します。

Admin APIとStorefront APIの違い

Admin APIが管理者向けのAPIであるのに対して、Storefront APIはストア利用者向けのAPIです。つまり、Admin APIが全ての顧客の情報を操作できるのに対して、StorefrontAPIはストア利用者自身の情報のみ操作できます(他人の情報は操作できない)。

Hydrogenを使ってカスタムストアフロントを構築してみる

以下の手順でカスタムストアフロントを構築します。

(注) 事前にStorefront APIを使用できるようにしておきます。また、ストアを構築して商品を事前に登録しておきます。

1: Node.jsをインストールします。

2: StorefrontAPIにリクエストするために、Storefront APIのアクセストークンを取得します。

3: 以下のコマンドを実行して、Hydrogenを用いたカスタムストアフロントの雛形を作成します。

npm init hydrogen-app@0.12.0

4: shopify.config.jsにアクセストークンとストアドメインを書きます。

↓ shopify.config.js

export default {
  storeDomain: 'ストアのドメインをここに書く',
  storefrontToken: 'アクセストークンをここに書く',
  storefrontApiVersion: '2022-04',
};

5: 依存しているライブラリをインストールします

npm i --legacy-peer-deps

6: 以下のコマンドを実行して、開発サーバーを起動します。

npm run dev

以下の画面が出れば成功です。もし出ない場合、Storefront APIのアクセススコープの権限がうまく設定されていない可能性があります。

Image from Gyazo

6: 終わり

TypeScript化する

Hydrogenを用いて作成したカスタムストアフロントの雛形は、JavaScriptで書かれています。以下のコードを実行してTypeScript化しましょう。

  npm i -D -E typescript @types/react @types/react-dom
  npx tsc --init

カスタマーアクセストーク

Storefront APIではunauthenticated scopeなリソースは、ユーザー名とパスワードを必要とせずにアクセス可能なデータです。 顧客自身のプライベートなデータの閲覧や操作には、事前にカスタマーアクセストークンを作成する必要があります。このトークンを用いてリクエストを出すことで、顧客が認証されます。カスタマーアクセストークンを作成するためには、顧客のメールアドレスとパスワードを指定したmutationでStorefront APIにリクエストを出します。リクエストが成功すると、カスタマーアクセストークンを返します。

↓ リクエス

mutation {
    customerAccessTokenCreate(input: {email: "顧客のemail", password: "顧客のパスワード"}) {
    customerUserErrors {
      code
      field
      message
    }
    customerAccessToken {
      accessToken
    }
  }
}

↓ レスポンス

{
  "data": {
    "customerAccessTokenCreate": {
      "customerUserErrors": [],
      "customerAccessToken": {
        "accessToken": "ここにカスタマーアクセストークンが書かれている"
      }
    }
  }
}

カスタマーアクセストークンが取得できた場合、以下のようなクエリにカスタマーアクセストークンを渡すことで、顧客の情報を取得できます。

↓ リクエス

query {
  customer(customerAccessToken: "ここにカスタマーアクセストークンを書く") {
    id
    email
    firstName
    lastName
  }
}

↓ レスポンス

{
  "data": {
    "customer": {
      "id": "gid://shopify/Customer/6524302262581",
      "email": "test@example.com",
      "firstName": "カリフォルニア",
      "lastName": "アメリカ"
    }
  }
}

顧客情報を取得する

実際にカスタムストアフロント上で顧客情報を取得してみます。
カスタマーアクセストークンを取得した後、そのトークンをcustomerAccessTokenという名のステートに保存します。その後、customerAccessTokenを依存配列の要素に持つuseEffect内で、そのトークンを用いてリクエストを出します。そうすることで、アクセストークンを取得すると同時に顧客情報を取得できます。

以下の例ではGraphQLのクエリを文字列で書いて、axios.postでリクエストしています。しかし、本来ならApollo Clientなどのライブラリを使ってリクエストを出した方が良いです。

↓ src/queries/queries.ts

// GraphQLのクエリは文字列としてファイル内で直接定義することができる。
// しかし、これはベストプラクティスではない。
// コードハイライトが効かない、型検査ができない、入力補完がされない、リクエストパラメータやレスポンスの型を手で定義しなくてはならないといった問題があるからである。
// 実際の開発では*.gqlファイルにクエリを定義して、graphql-codegenを使ってAPIクライアントとリクエストパラメータ、レスポンスの方を自動生成します。
export const CREATE_CUSTOMER_ACCESS_TOKEN_MUTATION = `
  mutation customerAccessTokenCreate($email: String!, $password: String!) {
    customerAccessTokenCreate(input: {email: $email, password: $password}) {
      customerUserErrors {
        code
        field
        message
      }
      customerAccessToken {
        accessToken
      }
    }
  }
`;

↓ src/apis/createCustomerAccessToken.ts

import axios from 'axios';
import {SHOPIFY_GRAPHQL_ENDPOINT} from '../constants/url';
import {CREATE_CUSTOMER_ACCESS_TOKEN_MUTATION} from '../queries/queries';

type Args = {
  email: string;
  password: string;
  storeDomain: string;
  storefrontApiVersion: string;
  storefrontToken: string;
  onSuccess: any;
  onError: any;
};

export default async function createCustomerAccessToken({
  email,
  password,
  storeDomain,
  storefrontApiVersion,
  storefrontToken,
  onSuccess,
  onError,
}: Args) {
  const url = SHOPIFY_GRAPHQL_ENDPOINT(storeDomain, storefrontApiVersion);
  const graphqlQuery = {
    query: CREATE_CUSTOMER_ACCESS_TOKEN_MUTATION,
    variables: {
      email,
      password,
    },
  };
  const headers = {
    'Content-Type': 'application/json',
    'X-Shopify-Storefront-Access-Token': storefrontToken,
  };

  axios.post(url, graphqlQuery, {headers}).then(onSuccess).catch(onError);
}

コードの詳細は以下のリポジトリをご参照していただければ幸いです。
GitHub - yukiHaga/hydrogen-practice

商品の購入

Shopifyにはゲスト購入機能が存在するため、顧客のログインは必須ではありません。

CartとCheckout

Shopifyには、購入に関係するリソースとしてCartとCheckoutが存在します。Cartは「これから買おうとしているものたち」を表すリソース、Checkoutは「購入行為そのもの」を表すリソースです。

終わり

Hydrogenを使ったECサイト構築のコストは高いですが、オリジナルのECサイトを構築するのに良いのかなと感じました。個人的にはLiquidよりReact × TypeScriptの方が描きやすいなと感じるので、後者の方がカスタマイズ性のあるサイトを作れる気がします。 あと、Tailwind CSSとGraphQLも感覚で書いているので、もっと理解する必要があるなと感じました。

参考記事

「eコマース」とはどういうもの?企業でECサイトを作るメリットとは? - システム開発のプロが発注成功を手助けする【発注ラウンジ】

Shopify(ショッピファイ)とは何か?なぜアマゾン・楽天キラーと呼ばれるのか |ビジネス+IT

ShopifyのフロントエンドフレームワークHydrogenをローカルで動かしてみた - necco note|necco inc.

Shopify Developers Platform—Build. Innovate. Get paid.

Shopify Community

Storefront API reference

Shopifyテーマのカスタマイズ①コード編集【7つのフォルダ構成とLiquid3種類の構文】|ショプクリ

エンジニアのためのShopify開発バイブル | フィードフォースグループ, 加藤 英也, 小飼 慎一, 佐藤 亮介, 大道 翔太, 長岡 正樹 |本 | 通販 | Amazon

ヘッドレスコマースとは?仕組みやメリット・デメリットを解説|クレジットカード決済代行の株式会社DGフィナンシャルテクノロジー(DGFT,旧:ベリトランス株式会社)

Backends For Frontends(BFF)はじめました - ZOZO TECH BLOG

BFFとはなんなのか? - Qiita

Shopify Hydrogen でストア構築を試してみる(Developer Preview 段階)

React Server Components 総まとめ

TSでReactの環境構築中に出た "error Cannot use JSX unless the '--jsx' flag is provided." を解消する - Qiita

リダイレクト

reactjs - GraphQL post request in axios - Stack Overflow

Hydrogen components, hooks, and utilities overview