Luxwearz Storefront

A premium leather-goods storefront that builds its own SEO surface — redirects, sitemap, robots and agent-readable twins emitted as real files at build time.

Client
Luxwearz
Category
Frontend Engineering
Completed
2026-08-14
Built with
React.js, TypeScript, Vite, Tailwind CSS, REST API
Topics
E-commerce, Frontend, SEO
Luxwearz Storefront

React SPA Storefront Static Build Live

The customer-facing storefront for a premium leather-goods brand. It ships no backend of its own — every read and write goes to Custom Store Management, the headless commerce platform behind it.


The interesting part is the build

Most storefronts hardcode their SEO surface. This one fetches it from the admin at build time and emits real static files, through five bespoke build plugins:

What it emitsBuilt fromWhat it fixed
.htaccessoperator-managed redirects301s that a client-side router simply cannot serve
sitemap.xmlpublished catalogue plus evergreen routesthe SPA fallback was serving HTML for the sitemap path, so no valid sitemap existed at all
robots.txtthe AI-crawler policy set in the admincrawler rules drifting from what the operator configured
llms.txtcontent feedsan agent-readable summary of the site
per-entity markdown twinsproducts and pagesagents fetch markdown instead of JavaScript-rendered HTML

All five fail open. An unreachable API leaves the build green rather than shipping a broken site — deliberate, because a stale sitemap is recoverable and a failed deploy at 2am is not.


Performance decisions, each with a reason

Route-level code splitting. The home route stays eager; thirty-plus others are lazy. One small helper was moved out of the chat module specifically because re-exporting it from the widget dragged the entire chat bundle, markdown renderer included, into the entry chunk on every page load.

The chat widget loads with no fallback UI. Roughly 800 KB with its rendering pipeline, it renders nothing at all until tapped.

Manual vendor chunking keeps the framework core, data fetching, animation and charting in separate named chunks, so the framework stays cached across deploys instead of being invalidated by unrelated changes.

Fonts load without blocking render, with a no-JavaScript fallback, and the API origin is preconnected to protect the largest-contentful-paint measurement.


Talking to the backend

One HTTP client, with the rules written into it:

  • The API envelope is unwrapped once in an interceptor, and failures normalise into a typed error carrying a code and a status.
  • The cart header is attached only on cart and checkout paths — attaching it globally would trigger a preflight request on every catalogue read.
  • Retries apply to idempotent reads only: two attempts with backoff on network failure, server error, or throttling. Writes are never retried.
  • An expired session clears auth and the chat token but preserves the guest cart key — otherwise the assistant kept answering as the previous customer.

Shipping it

Continuous integration typechecks and runs unit tests as a hard gate before the build. Deploy is a synchronised file transfer over SSH on push to main, with a retry loop. The backend enforces a merge guard that reads the CI result and blocks any merge that is not green.


Stack

React 18.3 TypeScript 5.5 Vite 5 Tailwind 3.4 Redux Toolkit TanStack Query 5 React Router 6 Radix UI Stripe Elements Framer Motion Vitest

Sixty routes, lazily loaded, over a single static build.

All projects