Hidrogen: Cadrul de comerț Shopify

Shopify Hydrogen este cadrul oficial React pentru construirea de vitrine Shopify fără cap. În versiunea actuală (Hydrogen 2.x) este construit pe acesta Remixuri, meta-cadru React care folosește API-urile web native și acțiunile serverului pentru o arhitectură imbunatatit progresiv.

Oxigen este timpul de găzduire global al Shopify pentru proiectele Hydrogen: bazat pe Lucrătorii Cloudflare (V8 izolate), rulează cod pe server la margine — în centrele de date cele mai apropiate de utilizatorul final. Rezultatul este unul TTFB (Time to First Byte) de 30-80ms la nivel global, imposibil de realizat cu un server tradițional centralizat.

Crearea unui proiect de hidrogen

# Crea un nuovo progetto Hydrogen
npm create @shopify/hydrogen@latest my-store

# Rispondi alle domande:
# - Store domain: mystore.myshopify.com
# - Storefront API token: [da Shopify Admin > Apps > Develop apps]
# - Language: TypeScript
# - CSS: Tailwind CSS

cd my-store
npm run dev
# Apre su http://localhost:3000

Structura unui proiect Hydrogen se bazează pe Remix și foarte asemănătoare cu cea clasică rutare bazată pe fișiere:

app/
├── components/           # Componenti UI riutilizzabili
│   ├── Cart.tsx          # Componente carrello
│   ├── ProductCard.tsx   # Card prodotto
│   └── Header.tsx        # Header con mini-cart
├── routes/              # File-based routing Remix
│   ├── _index.tsx        # Homepage (/)
│   ├── products.$handle.tsx  # Pagina prodotto (/products/[handle])
│   ├── collections.$handle.tsx  # Collection (/collections/[handle])
│   └── cart.tsx          # Pagina carrello (/cart)
├── lib/
│   ├── fragments.ts     # GraphQL fragments riutilizzabili
│   └── utils.ts         # Utility functions
├── root.tsx             # Root layout
└── entry.server.tsx     # Server-side entry point

Storefront API: Miezul de hidrogen

Hydrogen se conectează la Shopify prin intermediul Storefront API GraphQL. Fiecare operație comerțul este o interogare sau o mutație GraphQL. Hydrogen oferă clientului preconfigurat:

// app/routes/products.$handle.tsx
// Pagina dettaglio prodotto

import {json} from '@shopify/remix-oxygen';
import {useLoaderData} from '@remix-run/react';
import {Image, Money} from '@shopify/hydrogen';
import type {LoaderFunctionArgs} from '@shopify/remix-oxygen';

const PRODUCT_QUERY = `#graphql
  query Product($handle: String!, $selectedOptions: [SelectedOptionInput!]!) {
    product(handle: $handle) {
      id
      title
      descriptionHtml
      vendor
      selectedVariant: variantBySelectedOptions(selectedOptions: $selectedOptions) {
        id
        availableForSale
        selectedOptions { name value }
        price { amount currencyCode }
        compareAtPrice { amount currencyCode }
        image { url altText width height }
      }
      options {
        name
        values
      }
      variants(first: 100) {
        nodes {
          id
          availableForSale
          selectedOptions { name value }
          price { amount currencyCode }
        }
      }
    }
  }
`;

export async function loader({ params, context, request }: LoaderFunctionArgs) {
  const { handle } = params;
  const { storefront } = context;

  // Leggi le opzioni selezionate dalla URL (?color=red&size=M)
  const searchParams = new URL(request.url).searchParams;
  const selectedOptions = [];
  for (const [name, value] of searchParams) {
    selectedOptions.push({ name, value });
  }

  const { product } = await storefront.query(PRODUCT_QUERY, {
    variables: { handle, selectedOptions },
    cache: storefront.CacheShort(),    // cache di 1 minuto su Oxygen
  });

  if (!product) throw new Response('Not Found', { status: 404 });

  return json({ product });
}

export default function Product() {
  const { product } = useLoaderData<typeof loader>();
  const { selectedVariant } = product;

  return (
    <div className="product">
      {selectedVariant?.image && (
        <Image
          data={selectedVariant.image}
          className="product-image"
          sizes="(min-width: 768px) 50vw, 100vw"
        />
      )}
      <h1>{product.title}</h1>
      {selectedVariant && (
        <Money data={selectedVariant.price} />
      )}
      <AddToCartButton variant={selectedVariant} />
    </div>
  );
}

Cart API: gestionați-vă coșul cu hidrogen

Hidrogenul gestionează căruciorul prin intermediul API-ul Coș de la Shopify (bazat pe Mutații GraphQL). Cadrul include un sistem UI optimist pentru actualizări imediate:

// Aggiungere un prodotto al carrello
const ADD_TO_CART_MUTATION = `#graphql
  mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
    cartLinesAdd(cartId: $cartId, lines: $lines) {
      cart {
        id
        totalQuantity
        cost {
          totalAmount { amount currencyCode }
        }
        lines(first: 100) {
          nodes {
            id
            quantity
            merchandise {
              ... on ProductVariant {
                id
                title
                product { title }
                price { amount currencyCode }
                image { url altText }
              }
            }
          }
        }
      }
    }
  }
`;

// Componente AddToCartButton con Fetcher di Remix
import { useFetcher } from '@remix-run/react';

function AddToCartButton({ variant }: { variant: ProductVariant }) {
  const fetcher = useFetcher();
  const isAdding = fetcher.state !== 'idle';

  return (
    <fetcher.Form method="POST" action="/cart">
      <input type="hidden" name="intent" value="add" />
      <input type="hidden" name="variantId" value={variant.id} />
      <button
        type="submit"
        disabled={!variant.availableForSale || isAdding}
        className="add-to-cart-btn"
      >
        {isAdding ? 'Aggiunta...' : 'Aggiungi al Carrello'}
      </button>
    </fetcher.Form>
  );
}

Memorarea în cache pe oxigen: cheia performanței

Oxygen rulează codul Hydrogen pe marginea Cloudflare Workers. Cache-ul este gestionat prin API-uri native Cloudflare și ajutoare Hydrogen:

// Strategie di cache disponibili in Hydrogen
// Definiamo cache personalizzate per tipo di contenuto

// Cache lunga per pagine prodotto (aggiornamento raro)
export async function loader({ context }: LoaderFunctionArgs) {
  const { storefront } = context;

  const data = await storefront.query(PRODUCTS_QUERY, {
    cache: storefront.CacheLong(),        // cache di 1 ora
  });

  return json(data, {
    headers: {
      'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400',
    },
  });
}

// Cache breve per dati variabili (inventory, prezzi)
const inventoryData = await storefront.query(INVENTORY_QUERY, {
  cache: storefront.CacheShort(),         // cache di 60 secondi
});

// Nessuna cache per dati personalizzati (cart, customer)
const customerData = await storefront.query(CUSTOMER_QUERY, {
  cache: storefront.NoStore(),            // no-cache
});

Migrarea de la tema Lichid la Hidrogen

Dacă aveți o temă Shopify existentă, migrarea la Hydrogen este un proiect semnificativ. Abordarea recomandată este progresivă:

  1. Identificați paginile prioritare: pagini de produse și pagini de colecție primesc mai mult trafic. Începeți de acolo.
  2. Utilizați hidrogen ca subdomeniu: shop.tuodominio.com pe hidrogen, tuodominio.com pe tema Lichid. Testați și măsurați performanța.
  3. Migrați plata separat: Shopify se ocupă de plată cu propriile sale sistem nativ (Extensibilitate de checkout) — nu trebuie să-l rescrieți de la zero.
  4. Transferați treptat: pagină cu pagină, traseu după traseu.

Limitările hidrogenului de cunoscut

  • Checkout gestionat de Shopify: checkout este întotdeauna pe domeniu Shopify (checkout.shopify.com). Puteți personaliza aspectul cu Checkout Extensibilitate, dar nu puteți înlocui plata cu propria dvs.
  • Blocare parțială a furnizorului: Hydrogen/Oxygen funcționează numai cu Shopify ca backend. Dacă doriți să schimbați platforma de comerț, trebuie să rescrieți interfața.
  • Limitele ratei API: API-ul Storefront are limitare de rată. Pentru trafic intens mare luați în considerare cache agresivă sau un model BFF cu cache pe server.

Concluzii și pașii următori

Hidrogen + Oxigen este cea mai pragmatică alegere pentru cei care lucrează deja în ecosistem Shopify și vrea să rămână fără cap. Combinația de Remix, GraphQL, edge computing și Managementul nativ al caselor oferă o bază excelentă pentru vitrinele de înaltă performanță.

În următorul articol vom explora Medusa.js, cea mai bună alternativă open-source fără cap: arhitectură modulară complet auto-găzduită și fără blocare a furnizorului.