Skip to content

Headless Shopify на Next.js: полный гайд по архитектуре (2026)

Headless Shopify - не тема Shopify с API-вызовом. Это полная реархитектура data layer, pipeline рендеринга и модели состояния корзины/аутентификации. Гайд охватывает то, что большинство туториалов опускают: внутреннее устройство API, семантику кэширования и последствия каждого архитектурного решения для клиентского бандла.

Архитектурная диаграмма headless Shopify на Next.js - Storefront API, Data Cache, Cart
Опубликовано:Обновлено:Время чтения:17 мин

Headless Shopify на Next.js - де-факто стандарт для высокопроизводительного eCommerce в 2026 году. Это не упрощение по сравнению с Liquid-темами - это переработка трёх уровней, которые большинство туториалов обходят стороной: API-поверхности Shopify - все три уровня (Storefront API, Admin API, Customer Account API) с их моделями аутентификации, rate limiting и пагинацией; data layer Next.js App Router - как RSC, Data Cache и generateStaticParams убирают клиентские waterfalls для каталога; и модели state-границ - что идёт в Server Components, что требует 'use client', и точные механизмы (cookies для cart ID, OAuth PKCE, оптимистичные обновления) интерактивного слоя. Всё основано на реальных продакшн-реализациях включая Shopify Plus с несколькими сторами.

Часть I - API-поверхность Shopify: три уровня, три разных контракта

Наиболее распространённая архитектурная ошибка - воспринимать Storefront API как 'API Shopify', игнорируя Admin API и Customer Account API.

  • Storefront API (GraphQL, публичный): Эндпоинт https://{shop}.myshopify.com/api/{version}/graphql.json. Аутентификация через X-Shopify-Storefront-Access-Token. Rate limiting cost-based: 1,000 cost units/запрос, refill 500 units/секунду. Пагинация - только cursor-based (first: N, after: $cursor), не offset-based. API версионирован (квартальные релизы: 2025-01, 2025-04). Версия должна быть явно зафиксирована - никогда не используйте unstable в продакшне.
  • Admin API (GraphQL + REST, приватный): Полное управление магазином: инвентарь, заказы, данные клиентов, метаполя, вебхуки. Аутентификация через X-Shopify-Access-Token. Никогда не открывайте Admin API credentials браузеру. Admin API принадлежит исключительно Route Handlers или серверным утилитам с import 'server-only'.
  • Customer Account API (OAuth 2.0, 2024+): Shopify отказался от legacy Storefront API мутаций для клиентов (customerCreate, customerAccessTokenCreate) в 2024. Замена - Customer Account API: отдельный OAuth 2.0 сервис на shopify.com/authentication/{shop-id}. Использует PKCE flow (RFC 7636), выдаёт короткоживущие access tokens (1 час) + refresh tokens. Любая новая headless-реализация в 2026 году обязана использовать этот API.

Часть II - Data Layer: типизированный GraphQL с кодогенерацией

  • Инструментарий: @graphql-codegen/cli + @graphql-codegen/typescript-operations + @shopify/api-codegen-preset. Пресет скачивает схему Storefront API для зафиксированной версии и генерирует TypeScript-типы для всех .graphql-операций. Запускать в CI - типы всегда синхронизированы со схемой.
  • Стратегия фрагментов: Определить переиспользуемые фрагменты для форм данных компонентов: fragment ProductCardFields on Product { id handle title featuredImage { url altText } priceRange { minVariantPrice { amount currencyCode } } }. Запросы PDP и PLP составляют фрагменты - без расхождения форм данных между страницами.
  • Серверный data layer: Все Shopify-функции в lib/shopify/ с import 'server-only' в индексном файле. TypeScript выдаст ошибку сборки при попытке импортировать серверный код в Client Component. process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN - переменная без префикса NEXT_PUBLIC_, никогда не попадает в клиентский бандл.

Часть III - Архитектура каталога: generateStaticParams и ISR

Каталог (PDP, PLP) - наиболее критичная по производительности поверхность eCommerce-стора. Правильная архитектура: пре-рендер всех страниц каталога при сборке через generateStaticParams с ISR для актуальности данных. Это устраняет серверный round-trip на каждый запрос и обеспечивает LCP < 1.2s p75 для запросов из CDN-кэша.

  • PDP generateStaticParams: export async function generateStaticParams() { const products = await getAllProductHandles(); return products.map((handle) => ({ handle })); }. getAllProductHandles() пагинирует Storefront API cursor-based: 5,000 продуктов = 20 запросов при сборке, нуль запросов при обслуживании страницы.
  • ISR конфигурация: export const revalidate = 3600; - регенерация в фоне каждый час. Для inventory-critical страниц: revalidate = 300 + on-demand через вебхук Shopify → Route Handler → revalidateTag('product-' + handle).
  • RSC-паттерн для PDP: Страница - async Server Component. const product = await getProduct(params.handle); - данные загружаются напрямую в теле компонента. Заголовок продукта, описание, изображения, характеристики = Server Components, нуль байт в клиентский бандл. <AddToCartButton> и <VariantSelector> - единственные 'use client' компоненты.
  • Пагинация коллекций: Cursor-based: products(first: 24, after: $cursor). Каждая 'страница' коллекции - отдельный статический маршрут (/collections/[handle]/page/[page]). Кэшируем на CDN. Offset-based (?page=2) не подходит, если порядок продуктов динамический.
  • Cart API vs Checkout API: Используйте Cart API (текущий стандарт). Мутации: cartCreate (создание), cartLinesAdd, cartLinesUpdate, cartLinesRemove, cartBuyerIdentityUpdate (привязка клиента после авторизации).
  • Cookie-хранилище cart ID: localStorage недоступен в Server Components. cartCreate возвращает cart.id - сохранять в cookie: httpOnly: false (клиентский JS должен его читать), sameSite: 'lax', path: '/', maxAge: 30 * 24 * 60 * 60. В Server Component читается через cookies() для рендеринга количества товаров в шапке без клиентского fetch.
  • Граница `'use client'`: <CartProvider> - Client Component с React Context. Мутации корзины проксируются через Route Handlers (/api/cart/lines/add) - токен Storefront API никогда не попадает в браузер.
  • Оптимистичные обновления (React 19): useOptimistic даёт мгновенный UI-фидбек до подтверждения от сервера. При ошибке мутации React автоматически возвращает серверное состояние. Устраняет 200–400ms spinner на кнопке 'Добавить в корзину'.

Часть V - Аутентификация: OAuth PKCE через Customer Account API

  • PKCE flow (RFC 7636): (1) Генерация code_verifier (43–128 символов). (2) Вычисление code_challenge = BASE64URL(SHA-256(code_verifier)). (3) Редирект на shopify.com/authentication/{shop-id}/oauth/authorize с параметрами PKCE. (4) Обмен code + code_verifier на access token в Route Handler. code_verifier хранится в httpOnly cookie - недоступен клиентскому JS.
  • Auth.js v5 adapter: Customer Account API конфигурируется как custom provider в Auth.js v5. Auth.js управляет обновлением токена, сериализацией сессии и жизненным циклом PKCE verifier.
  • `cartBuyerIdentityUpdate` после логина: Связывает анонимную корзину гостя с аккаунтом клиента. Открывает историю заказов, сохранённые адреса, начисление баллов лояльности за предыдущую анонимную активность.

Часть VI - SEO: product schema и каноникал вариантов

  • Product structured data: Schema Product с Offer (цена, валюта, доступность из product.variants.availableForSale), AggregateRating (если есть интеграция с отзывами), BreadcrumbList. Product.url - всегда canonical URL без параметра ?variant=.
  • Каноникал URL вариантов: Shopify добавляет ?variant={id} к URL при выборе варианта. В generateMetadata() всегда возвращать alternates: { canonical: '/products/' + handle } без параметра варианта. Консолидирует все сигналы PageRank на базовый URL продукта.
  • hreflang для мультирегиональных сторов: Shopify Markets + Next.js i18n + generateMetadata().alternates.languages. Подробный анализ реализации - в гайде по App Router миграции.

Часть VII - Производительность: бандл и image pipeline

  • `'use client'` поверхность на PDP: Только <VariantSelector> + <AddToCartButton> + опционально <ImageGallery> (~15–25 KB gzip). Заголовок, описание, характеристики, отзывы, похожие продукты - Server Components. Итоговый бандл: 80–120 KB gzip против 350–500 KB у Liquid + Alpine.js. Детальный анализ связи сокращения бандла с INP - в The Universal Web Performance Architecture.
  • Shopify CDN image трансформации: cdn.shopify.com поддерживает трансформации через URL-параметры: ?width=800&height=800&crop=center&format=avif&quality=80. Отдельный image CDN не нужен. next/image + remotePatterns для cdn.shopify.com.
  • Preconnect: <link rel='preconnect' href='https://cdn.shopify.com' /> в app/layout.tsx. Устраняет ~150–200ms задержки DNS + TLS на первый Shopify CDN-запрос.
  • Edge caching: Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400 для статических страниц. Route Handlers корзины (/api/cart/*) - Cache-Control: no-store обязательно.

Часть VIII - Продакшн-паттерны: референсы кейсов

  • Global Home & Decor eCommerce ([кейсы](/ru/projects)): Multi-storefront Shopify Plus + Magento 2 для B2B и B2C-аудиторий на 12 рынках. Единый типизированный интерфейс Product для обоих бэкендов - одни React-компоненты для Shopify и Magento. Паттерн composable headless architecture в наиболее требовательной форме.
  • High-Load Retail (Traffic Spikes): generateStaticParams пре-рендерит весь PDP/PLP при сборке - пиковый трафик поглощается CDN edge-нодами без origin-запросов к Shopify API. Во время спайков на сервер приходят только мутации корзины. Для углублённых паттернов enterprise eCommerce - сервис enterprise ecommerce.
  • Shopify Hydrogen vs. Next.js: Hydrogen подходит, когда Shopify - единственный бэкенд, команда знакома с Remix, и деплой на Oxygen. Next.js - при нескольких бэкендах, существующей React/Next.js кодовой базе или несовместимости с Oxygen. Полное сравнение - Shopify Hydrogen vs Next.js Commerce.

FAQ

  • Почему нельзя хранить ID корзины в localStorage? localStorage недоступен в Server Components и при SSR. Количество товаров в шапке должно рендериться на сервере - это часть начального HTML. Cookie с httpOnly: false и sameSite: 'lax' - единственный механизм, доступный и серверу (cookies()), и клиенту.
  • Как обработать rate limiting Storefront API при большом каталоге? Паттерн ISR означает нуль Storefront API-вызовов на закэшированные страницы. Rate limiting актуален только при сборке (generateStaticParams) и фоновой ISR-регенерации - оба случая имеют низкую частоту. При сборке каталога из 5,000+ продуктов используйте билд-время data pipeline с явным throttling.
  • Как реализовать on-demand ISR при обновлении продукта в Shopify? Вебхук Shopify products/update → Route Handler с валидацией HMAC-подписи → revalidateTag('product-' + handle). Следующий запрос к PDP триггерит регенерацию.
  • Как правильно обрабатывать `?variant=` URL для SEO? В generateMetadata() всегда возвращать alternates: { canonical: '/products/' + handle } без параметра варианта. Параметр ?variant= можно оставить в URL для shareability - Google соблюдает canonical и консолидирует сигналы на базовый URL. Никогда не включать ?variant= URL в sitemap.

Источники

Похожие статьи

Shopify Hydrogen vs Next.js Commerce: какую архитектуру выбрать для магазина в 2026

Детальное сравнение двух основных headless-архитектур для Shopify. Модель исполнения, слой данных, стратегия кэширования, размер бандла, бенчмарки производительности (LCP/INP/CLS), TCO, риск вендор-локина и практический фреймворк решений между нативной глубиной Hydrogen и компонуемой гибкостью Next.js Commerce.

eCommerceNext.jsShopify
Читать статью

Архитектура веб-производительности: системный анализ 12 инженерных принципов (издание 2026)

Глубокий технический разбор веб-производительности 2026 года: физика сетей, конвейеры изображений, модели выполнения JavaScript, Critical Rendering Path, edge-вычисления, Core Web Vitals и продакшн RUM - с реальными бенчмарками и конкретными примерами реализации.

EngineeringArchitectureCore Web Vitals
Читать статью

React 19: useOptimistic, use(), Server Actions - механизм и архитектура (2026)

Детальный разбор пяти новых примитивов React 19: useOptimistic (конкурентная composition оптимистичного состояния с автоматическим rollback), use() (условное чтение Promise и Context), Server Actions (RPC-over-HTTP контракт и Progressive Enhancement), useActionState (стейт-threading паттерн), useFormStatus. Action-based mutation архитектура, которая заменяет Redux/Zustand для серверных мутаций.

React 19ArchitectureNext.js
Читать статью