vom Schema bis zur fertigen Produktseite
Ein React Storefront auf Basis von Magentos GraphQL API entkoppelt Frontend und Backend vollständig und macht den Shop schneller, flexibler und leichter wartbar. Wer das Schema versteht, den richtigen Client wählt und Caching sowie Fehlerbehandlung von Anfang an mitdenkt, spart sich Monate an nachträglichem Refactoring.
Inhaltsverzeichnis
- 1. Warum ein React Storefront auf Magento GraphQL
- 2. Das Magento GraphQL Schema verstehen
- 3. Apollo Client konfigurieren und einrichten
- 4. Produktlisten, Facetten und Pagination laden
- 5. Produktdetailseite mit konfigurierbaren Produkten
- 6. Customer Token und Session-Handling
- 7. Caching-Strategie für den React Storefront
- 8. Fehlerbehandlung bei Magento GraphQL Antworten
- 9. React Storefront Ansätze im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum ein React Storefront auf Magento GraphQL
Ein React Storefront auf Basis von Magentos GraphQL API ist die konsequente Weiterentwicklung des klassischen Luma Frontends. Statt server-gerenderter phtml-Templates liefert Magento nur noch Daten aus, und React übernimmt vollständig die Darstellung, das Routing und die Interaktivität im Browser. Dieser Ansatz entkoppelt die Release-Zyklen von Frontend und Backend, erlaubt eigene Deployment-Pipelines für den Storefront und öffnet die Tür für moderne Tools wie Vite, TanStack Query und Tailwind, die im Luma-Kontext nie sauber integrierbar waren.
Der zentrale Unterschied zu PWA Studio oder einem generischen Headless-Setup liegt darin, dass ein selbst gebauter React Storefront genau auf die Anforderungen eines konkreten Shops zugeschnitten wird. Kein ungenutzter Code, keine fremden Abhängigkeiten, keine Kompromisse bei der Bundle-Größe. Wer schon einmal versucht hat, ein PWA Studio Theme an ein individuelles Design-System anzupassen, kennt den Aufwand, unerwünschte Komponenten zu entfernen. Ein eigener React Storefront beginnt bei null und wächst nur um das, was tatsächlich gebraucht wird.
Technisch basiert jeder React Storefront auf Magento GraphQL auf drei Säulen: dem GraphQL Schema als Vertrag zwischen Backend und Frontend, einem Client wie Apollo oder urql für Caching und Request-Management, und einer sauberen Trennung zwischen Server- und Client-State. Die folgenden Abschnitte gehen jede dieser Säulen im Detail durch, mit lauffähigen Beispielen für Produktlisten, Produktdetailseiten und Authentifizierung.
2. Das Magento GraphQL Schema verstehen
Bevor die erste Zeile React-Code entsteht, lohnt sich ein gründlicher Blick in das Magento GraphQL Schema über die integrierte GraphiQL-Oberfläche unter /graphql. Das Schema folgt der Relay-Connection-Spezifikation für paginierte Listen: Felder wie products liefern nicht direkt ein Array, sondern eine Struktur mit items, page_info und total_count. Wer diese Konvention beim Aufbau des React Storefronts ignoriert, baut Pagination-Logik, die bei größeren Kategorien mit tausenden Produkten bricht.
Ein zweiter wichtiger Baustein ist die Unterscheidung zwischen ProductInterface und den konkreten Typen SimpleProduct, ConfigurableProduct und BundleProduct. GraphQL-Queries müssen mit Inline-Fragmenten (... on ConfigurableProduct) arbeiten, um typ-spezifische Felder wie configurable_options abzufragen. Für einen React Storefront, der mehrere Produkttypen im selben Katalog darstellt, ist dieses Muster unumgänglich und sollte früh in gemeinsam genutzten Fragment-Definitionen zentralisiert werden.
# GraphQL query fragment for a Magento product tile in a React storefront
fragment ProductTileFields on ProductInterface {
uid
name
sku
url_key
small_image {
url
label
}
price_range {
minimum_price {
final_price { value currency }
regular_price { value currency }
}
}
... on ConfigurableProduct {
configurable_options {
attribute_code
label
values { value_index label }
}
}
}
query CategoryProducts($categoryId: String!, $pageSize: Int!, $currentPage: Int!) {
products(filter: { category_id: { eq: $categoryId } }, pageSize: $pageSize, currentPage: $currentPage) {
total_count
page_info { current_page page_size total_pages }
items { ...ProductTileFields }
}
}
Der Vorteil dieser Fragment-basierten Struktur zeigt sich beim Skalieren des React Storefronts: neue Seiten, die dieselben Produktkacheln darstellen, importieren einfach das bestehende Fragment, statt Felder erneut aufzulisten. Das reduziert Inkonsistenzen zwischen Kategorieseite, Suchergebnis und Cross-Selling-Widgets erheblich, weil alle drei exakt dieselben Felder anfragen und damit auch denselben Apollo-Cache-Eintrag teilen.
3. Apollo Client konfigurieren und einrichten
Für einen produktionsreifen React Storefront hat sich Apollo Client als GraphQL-Client durchgesetzt, weil er normalisiertes Caching, optimistische Updates und eine ausgereifte DevTools-Integration mitbringt. Die Alternative urql ist leichter und schneller eingerichtet, bietet aber ein weniger granulares Cache-Modell für komplexe Produktdaten mit verschachtelten Preisstrukturen, wie sie bei Bundle- und Konfigurationsprodukten in Magento auftreten.
Bei der Einrichtung des Apollo Clients für einen React Storefront ist die korrekte Konfiguration der InMemoryCache entscheidend. Magento GraphQL liefert für die meisten Entitäten eine uid, die als eindeutiger Cache-Key dient. Ohne explizite typePolicies normalisiert Apollo Produktdaten zwar automatisch über die id, aber Magento nutzt konsequent uid, weshalb eine eigene Key-Funktion nötig ist, damit Cache-Updates nach Mutationen wie dem Hinzufügen zum Warenkorb korrekt greifen.
// apolloClient.js — Apollo Client setup for a React storefront on Magento GraphQL
import { ApolloClient, InMemoryCache, createHttpLink, from } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error';
const httpLink = createHttpLink({ uri: process.env.NEXT_PUBLIC_MAGENTO_GRAPHQL_URL });
// Attach store and customer context headers on every request
const authLink = setContext((_, { headers }) => {
const token = typeof window !== 'undefined' ? localStorage.getItem('customerToken') : null;
return {
headers: {
...headers,
Store: process.env.NEXT_PUBLIC_MAGENTO_STORE_CODE,
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
};
});
const errorLink = onError(({ graphQLErrors, networkError }) => {
graphQLErrors?.forEach((err) => console.error('[GraphQL error]', err.message, err.extensions));
if (networkError) console.error('[Network error]', networkError);
});
export const apolloClient = new ApolloClient({
link: from([errorLink, authLink, httpLink]),
cache: new InMemoryCache({
typePolicies: {
ProductInterface: { keyFields: ['uid'] },
ConfigurableProduct: { keyFields: ['uid'] },
Cart: { keyFields: ['id'] },
},
}),
});
Ein Detail, das in vielen React Storefront Projekten unterschätzt wird, ist der Store-Header. Magento nutzt ihn, um in Multi-Store-Setups die richtige Store-View und damit Preise, Sprache und Verfügbarkeit zu bestimmen. Fehlt der Header, greift die Default-Store-View, was in internationalen Shops zu falschen Preisen oder fehlenden Übersetzungen führt, ein Fehler, der oft erst im Staging bei einem zweiten Store auffällt.
4. Produktlisten, Facetten und Pagination laden
Kategorieseiten sind der Bereich, in dem ein React Storefront seine Performance-Vorteile gegenüber Luma am deutlichsten zeigt. Statt eines vollständigen Seiten-Reloads bei jedem Filter-Klick aktualisiert React nur die betroffenen Komponenten, während Apollo Client die Anfrage im Hintergrund abfeuert und das Ergebnis normalisiert cached. Die aggregations im GraphQL-Response liefern die Facetten-Daten (Größe, Farbe, Preis-Range) inklusive der jeweiligen Trefferzahl pro Option, was clientseitig direkt für Filter-Badges genutzt werden kann.
Für die Pagination empfiehlt sich in einem React Storefront das Cursor-ähnliche Muster mit currentPage und pageSize, kombiniert mit der Apollo fetchMore-Funktion für Infinite-Scroll-Varianten oder klassischer Seitennavigation. Wichtig ist, den Filter-State in der URL zu spiegeln, damit gefilterte Kategorieseiten teilbar und für Suchmaschinen crawlbar bleiben, ein Punkt, der bei rein clientseitigem State schnell übersehen wird.
// CategoryProductGrid.jsx — filterable product grid for a React storefront
import { useQuery } from '@apollo/client';
import { useSearchParams } from 'next/navigation';
import { CATEGORY_PRODUCTS_QUERY } from './queries';
export function CategoryProductGrid({ categoryId }) {
const searchParams = useSearchParams();
const page = Number(searchParams.get('p') ?? '1');
const priceFilter = searchParams.get('price');
const { data, loading, fetchMore } = useQuery(CATEGORY_PRODUCTS_QUERY, {
variables: {
categoryId,
pageSize: 24,
currentPage: page,
filter: priceFilter ? { price: { from: priceFilter.split('-')[0], to: priceFilter.split('-')[1] } } : {},
},
notifyOnNetworkStatusChange: true,
});
if (loading && !data) return <ProductGridSkeleton count={24} />;
const { items, total_count, page_info } = data.products;
return (
<>
<FacetSidebar aggregations={data.products.aggregations} />
<ProductTiles items={items} />
<Pagination current={page_info.current_page} total={page_info.total_pages} totalCount={total_count} />
</>
);
}
5. Produktdetailseite mit konfigurierbaren Produkten
Die Produktdetailseite ist der komplexeste Einzelbaustein jedes React Storefronts, weil konfigurierbare Produkte mehrdimensionale Varianten-Logik erfordern. Magento GraphQL liefert über configurable_options die verfügbaren Attribute (etwa Größe und Farbe) mit allen möglichen Werten, aber nicht direkt, welche Kombinationen tatsächlich lagernd sind. Diese Information steckt in variants, einem Array aus konkreten Produkt-Varianten mit ihrer jeweiligen Attribut-Kombination und SKU.
Ein robustes Auswahl-Pattern für den React Storefront baut aus variants eine Lookup-Tabelle, die anhand der gewählten Attribut-Werte in Sekundenbruchteilen die passende Variante findet, inklusive Lagerbestand und variantenspezifischem Bild. Ohne diese Vorverarbeitung müsste bei jedem Klick auf eine Farboption eine neue GraphQL-Anfrage gestellt werden, was sich spürbar unruhig anfühlt und unnötige Serverlast erzeugt.
// useConfigurableSelection.js — variant lookup for React storefront PDPs
import { useMemo, useState } from 'react';
export function useConfigurableSelection(configurableProduct) {
const [selected, setSelected] = useState({});
// Build a lookup map: "64_red" -> variant
const variantMap = useMemo(() => {
const map = new Map();
configurableProduct.variants.forEach((variant) => {
const key = variant.attributes
.map((a) => `${a.code}_${a.value_index}`)
.sort()
.join('|');
map.set(key, variant);
});
return map;
}, [configurableProduct.variants]);
const activeVariant = useMemo(() => {
const key = Object.entries(selected)
.map(([code, value]) => `${code}_${value}`)
.sort()
.join('|');
return variantMap.get(key) ?? null;
}, [selected, variantMap]);
const selectOption = (code, valueIndex) =>
setSelected((prev) => ({ ...prev, [code]: valueIndex }));
return { selected, selectOption, activeVariant, inStock: activeVariant?.product.stock_status === 'IN_STOCK' };
}
6. Customer Token und Session-Handling
Authentifizierung ist einer der Bereiche, in denen ein selbst gebauter React Storefront deutlich mehr Sorgfalt erfordert als ein Server-Rendering-Ansatz. Magento GraphQL nutzt Bearer-Token-Authentifizierung über die Mutation generateCustomerToken, die einen Token mit begrenzter Gültigkeit zurückgibt. Dieser Token muss sicher gespeichert werden, wobei localStorage zwar praktisch, aber anfällig für XSS ist, während HttpOnly-Cookies über eine eigene Backend-for-Frontend-Schicht mehr Schutz bieten, aber zusätzliche Infrastruktur benötigen.
Für Gäste-Checkouts arbeitet ein React Storefront zusätzlich mit einem cart_id, der unabhängig vom Customer-Token existiert und in einem Cookie oder localStorage persistiert wird. Der entscheidende Punkt beim Übergang von Gast zu eingeloggtem Kunden ist die Mutation mergeCarts, die den anonymen Warenkorb mit dem des Kunden zusammenführt, ein Schritt, der in vielen Implementierungen vergessen wird und zu verlorenen Warenkörben nach dem Login führt.
7. Caching-Strategie für den React Storefront
Caching entscheidet maßgeblich über die gefühlte Geschwindigkeit eines React Storefronts. Statische Daten wie Store-Konfiguration, Kategoriebaum und CMS-Blöcke ändern sich selten und eignen sich hervorragend für serverseitiges Caching mit langer Time-to-live, kombiniert mit einer expliziten Invalidierung über Magentos Cache-Tags, sofern die Deployment-Plattform Incremental Static Regeneration unterstützt. Produktpreise und Lagerbestände hingegen sind volatiler und sollten client-seitig mit kurzer Apollo-Cache-Time-to-live oder network-only Fetch-Policy behandelt werden.
Ein bewährtes Muster für den React Storefront ist die Kombination aus cache-first für Navigationsdaten und cache-and-network für Produktlisten: der Nutzer sieht sofort den zwischengespeicherten Stand, während im Hintergrund aktualisierte Preise und Verfügbarkeiten nachgeladen werden. Das vermeidet sichtbares Laden bei wiederholten Besuchen derselben Kategorie, ohne veraltete Preise anzuzeigen, sobald die frische Antwort eintrifft.
8. Fehlerbehandlung bei Magento GraphQL Antworten
Magento GraphQL gibt Fehler auf zwei Ebenen zurück: als HTTP-Statuscode für Transport-Probleme und als errors-Array innerhalb einer HTTP-200-Antwort für fachliche Fehler wie ungültige SKUs oder abgelaufene Carts. Ein React Storefront, der nur auf HTTP-Status prüft, übersieht diese fachlichen Fehler komplett, weil GraphQL selbst bei einem teilweise fehlgeschlagenen Query mit Status 200 antwortet.
Jeder Magento GraphQL Error trägt in extensions.category eine Kategorie wie graphql-no-such-entity oder graphql-authorization, die sich für gezielte Fehlerbehandlung im React Storefront nutzen lässt: abgelaufene Tokens lösen einen automatischen Re-Login-Flow aus, fehlende Entitäten zeigen eine 404-Seite, und Validierungsfehler werden direkt am betroffenen Formularfeld angezeigt, statt einer generischen Fehlermeldung am Seitenrand.
// errorCategoryHandler.js — routing Magento GraphQL errors by category in a React storefront
export function handleGraphQlError(error, { onAuthExpired, onNotFound, onValidation }) {
const category = error.extensions?.category;
switch (category) {
case 'graphql-authorization':
return onAuthExpired();
case 'graphql-no-such-entity':
return onNotFound();
case 'graphql-input':
return onValidation(error.message);
default:
console.error('[Unhandled GraphQL error]', error.message, category);
}
}
9. React Storefront Ansätze im Vergleich
Es gibt mehrere Wege, wie GraphQL-Daten in einem React Storefront verarbeitet werden können. Die Wahl beeinflusst Caching-Verhalten, Bundle-Größe und Entwicklungsgeschwindigkeit erheblich.
| Ansatz | Caching | Bundle-Größe | Empfehlung |
|---|---|---|---|
| Apollo Client | Normalisiert, granular | ~35 KB gzip | Komplexe Kataloge, viele Mutationen |
| urql | Document-Cache | ~9 KB gzip | Kleinere Storefronts, einfache Queries |
| fetch + TanStack Query | Query-Key-basiert | ~13 KB gzip | Team kennt REST-Patterns bereits |
| PWA Studio (Peregrine) | Vorgegeben, wenig anpassbar | Groß, viel Overhead | Nur bei sehr engem Zeitrahmen |
Für die meisten mittelgroßen bis großen Kataloge ist Apollo Client die tragfähigste Basis für einen React Storefront, weil normalisiertes Caching bei Warenkorb-Mutationen automatisch konsistente UI-Updates über mehrere Komponenten hinweg erzeugt, ohne manuelles Re-Fetching. Kleinere Projekte mit überschaubarem Query-Umfang fahren mit urql oft schneller, weil die Einstiegshürde niedriger ist und weniger Konfigurationsaufwand entsteht.
Mironsoft
React Storefronts auf Magento GraphQL, von der Architektur bis zum Deployment
Ein eigener React Storefront für euren Magento Shop?
Wir bauen React Storefronts auf Basis von Magento GraphQL, mit Apollo Client, sauberem Caching und robuster Fehlerbehandlung, maßgeschneidert auf euren Katalog und euer Design.
Architektur-Beratung
Schema-Analyse, Client-Auswahl und Datenmodell für euren Storefront
Implementierung
Produktseiten, Warenkorb und Checkout mit Magento GraphQL umsetzen
Performance-Tuning
Caching-Strategie, Bundle-Analyse und Core Web Vitals optimieren
10. Zusammenfassung
Ein React Storefront auf Magento GraphQL steht auf drei Säulen: einem gut verstandenen Schema mit Fragmenten für Wiederverwendbarkeit, einem Client wie Apollo, der normalisiertes Caching und Mutationen sauber verwaltet, und einer expliziten Strategie für Authentifizierung, Caching und Fehlerbehandlung. Wer diese drei Bereiche von Anfang an durchdenkt, vermeidet die typischen Stolpersteine bei Konfigurationsprodukten, Multi-Store-Setups und Gast-zu-Kunde-Übergängen.
Der größte Vorteil gegenüber PWA Studio liegt in der vollständigen Kontrolle über Bundle-Größe und Abhängigkeiten. Ein React Storefront, der nur die tatsächlich benötigten GraphQL-Felder abfragt und nur die wirklich genutzten Komponenten bündelt, lädt spürbar schneller als ein generisches Headless-Framework mit ungenutztem Overhead. Diese Kontrolle zahlt sich langfristig in besseren Core Web Vitals und niedrigeren Absprungraten aus.
React Storefront auf Magento GraphQL — Das Wichtigste auf einen Blick
Schema
Relay-Connections für Listen, Inline-Fragmente für Produkttypen. Fragment-Definitionen zentralisieren, um Konsistenz zu sichern.
Client
Apollo Client mit keyFields: ['uid'] für korrektes Cache-Update nach Warenkorb-Mutationen.
Auth & Cart
Bearer-Token für Kunden, cart_id für Gäste, mergeCarts beim Login nicht vergessen.
Fehlerbehandlung
extensions.category im GraphQL-Error auswerten, nicht nur HTTP-Status prüfen.