Налаштування Shopify Hydrogen (React Storefront)
Hydrogen — офіційний React-фреймворк від Shopify для headless commerce. Побудований на Remix, оптимізований для роботи зі Storefront API, розгортається на Oxygen (CDN-хостинг Shopify) або будь-якому сумісному з Node.js хостингу.
Чому Hydrogen, а не просто Next.js
Next.js + Storefront API — робочий варіант. Hydrogen додає:
- Oxygen-розгортання — безплатний глобальний edge-хостинг, вбудований в Shopify (від плану Basic). Немає окремої інфраструктури для розгортання.
-
Remix routing — вкладені маршрути, server-side завантаження даних через
loader, оптимістичний UI черезaction -
Shopify-специфічні примітиви —
ShopifyProvider, хуки для корзини, аналітики, стратегії кешування - Cache API — управління кешуванням на рівні Cloudflare Workers
- Streaming SSR — Progressive HTML rendering з коробки
Ініціалізація проекту
npm create @shopify/hydrogen@latest
# Вибір: Demo Store / Hello World
# Розгортання: Oxygen / Self-hosted
cd my-hydrogen-app
npm install
npm run dev
Змінні середовища (.env):
SHOPIFY_STORE_DOMAIN=my-store.myshopify.com
SHOPIFY_STOREFRONT_ACCESS_TOKEN=abc123...
SHOPIFY_PUBLIC_STORE_DOMAIN=my-store.myshopify.com
SESSION_SECRET=random-secret-string
Структура проекту
hydrogen-app/
├── app/
│ ├── components/ # UI компоненти
│ ├── lib/ # утиліти, Shopify-клієнт
│ ├── routes/ # файловий роутинг Remix
│ │ ├── _index.tsx # головна сторінка
│ │ ├── products.$handle.tsx # сторінка продукту
│ │ ├── collections.$handle.tsx
│ │ └── cart.tsx
│ ├── styles/ # глобальні CSS
│ └── root.tsx # кореневий layout
├── public/
├── server.ts # Oxygen/Node entry point
└── vite.config.ts
Маршрут продукту з loader
// app/routes/products.$handle.tsx
import { json, type LoaderFunctionArgs } from '@shopify/remix-oxygen';
import { useLoaderData, type MetaFunction } from '@remix-run/react';
import { getSelectedProductOptions, Analytics } from '@shopify/hydrogen';
import { AddToCartButton } from '~/components/AddToCartButton';
const PRODUCT_QUERY = `#graphql
query Product($handle: String!, $country: CountryCode, $language: LanguageCode)
@inContext(country: $country, language: $language) {
product(handle: $handle) {
id
title
handle
descriptionHtml
options {
name
values
}
selectedVariant: variantBySelectedOptions(
selectedOptions: $selectedOptions
ignoreUnknownOptions: true
caseInsensitiveMatch: true
) {
id
availableForSale
image {
url
altText
width
height
}
price {
amount
currencyCode
}
compareAtPrice {
amount
currencyCode
}
sku
title
unitPrice {
amount
currencyCode
}
}
media(first: 7) {
nodes {
... on MediaImage {
mediaContentType
image {
id
url
altText
width
height
}
}
}
}
}
}
`;
export async function loader({ params, context }: LoaderFunctionArgs) {
const { handle } = params;
const { storefront } = context;
const { product } = await storefront.query(PRODUCT_QUERY, {
variables: {
handle,
selectedOptions: getSelectedProductOptions(request),
},
});
if (!product?.id) {
throw new Response(null, { status: 404 });
}
return json({
product,
url: request.url,
});
}
export const meta: MetaFunction<typeof loader> = ({ data }) => {
return [
{ title: `${data?.product?.title ?? 'Product'}` },
{ description: data?.product?.descriptionHtml ?? '' },
];
};
export default function Product() {
const { product } = useLoaderData<typeof loader>();
return (
<div className="product">
<h1>{product.title}</h1>
<img
src={product.selectedVariant?.image?.url}
alt={product.selectedVariant?.image?.altText}
/>
<p>{product.descriptionHtml}</p>
<AddToCartButton variant={product.selectedVariant} />
</div>
);
}
Інтеграція з Oxygen
Розгортання на Oxygen (безплатний CDN):
npm run build
npm run deploy # через Oxygen CLI
Oxygen автоматично обробляє кешування, edge rendering та глобальне розподілення.







