← Back to blog
by rn00m

Headless Shopify Project


SHOPIFY

PROJECT ARCHITECTURE & RECENT FIXES RECAP

Core Tech Stack:

  • Frontend Framework:
    Astro v6 (configured for full SSR via output: ‘server’)
  • Routing:
    Astro View Transitions () enabled globally inside BaseLayout.astro.
  • Backend Integration:
    Headless Shopify Storefront API (@shopify/storefront-api-client).
  • Styling Framework:
    Tailwind CSS v4 / Vite.
  • Component Paradigm:
    Vanilla JavaScript, Event Delegation, and Custom Browser Events (No heavy frontend framework runtimes like React/Svelte on the client side).

1. API Route Optimization (src/pages/api/add-to-cart.ts)

The Problem:

The route was missing session persistence for live Shopify stores and didn’t flatten quantities for simple frontend reading.

What We Did:

  • Fixed TypeScript error TS2345 by importing and applying Astro’s native AstroCookies type rather than using inline type assertions.
  • Added code to read and update the live shopify_cart_id cookie (path: ’/’, maxAge: 30 days) so the shopping session persists seamlessly across page refreshes and server-side navigation.
  • Map-reduced Shopify’s GraphQL nested nodes array (cart.lines.nodes) into a flat totalQuantity integer and returned it directly inside the final successful 200 JSON response.

2. View Transitions & Router Lifecycle Fixes

The Problem:

When navigating between pages via , elements are dynamically swapped in the DOM. Top-level script variables and standard event listeners were becoming stale/dead because they only executed once on initial site load.

What We Did:

  • Wrapped event listeners and element selection queries inside local bootstrap functions (initHeader, initProductPage, setupCartDrawer) and bound them to Astro’s custom lifecycle hook: document.addEventListener(‘astro:page-load’, initFunction).
  • This guarantees selectors find the fresh DOM elements after every page swap.

3. Frontend State & Event Unification

The Problem:

Adding an item to the cart caused a race condition where CartDrawer.astro instantly called GET /api/cart and finished in 1ms, displaying empty markup before Shopify’s server completed the POST request (which takes 600ms–1000ms).

What We Did:

  • Unified the custom event payload. The add-to-cart button now waits for Shopify to finish, then dispatches a single custom browser event:
    document.dispatchEvent(new CustomEvent(‘cart-updated’, { detail: { …data.cart, totalQuantity } })).
  • Header.astro listens for this event to instantly update the visual badge counter without layout flashes.
  • CartDrawer.astro intercepts the exact same event and passes the layout object directly into its renderCart() method, drawing the visual item list instantly without needing a secondary background network request.

4. Tailwind CSS v4 IntelliSense Conflict Resolution

The Problem:

Elements like the cart badge and the product page’s scroll-based sticky bar (#sticky-atc) were throwing linting cssConflict warnings because flex and hidden utilities both try to manipulate the CSS display property.

What We Did:

  • Replaced the standard class toggling with a clean, attribute-driven approach. The HTML element tracks its visibility state natively via data-visible=“false”.
  • Removed hidden and leveraged Tailwind v4 modifier styling:
    data-[visible=false]:invisible
    data-[visible=true]:visible
  • Connected this to an IntersectionObserver that alters .setAttribute(‘data-visible’, ‘true’/‘false’).
  • This cleared all linting errors and allowed smooth entrance transitions (transition-all duration-300 transform data-[visible=false]:translate-y-full data-[visible=false]:opacity-0) to play perfectly.

NEXT STEPS ON THE ROADMAP

  • Live Data Integration: Populate real products with descriptive data, assets, and multiple variant options (size/color) inside the Shopify Admin panel to test path handling for /collections/[handle] and /products/[handle].
  • Variant Option Selection: Ensure client-side interactions with option dropdowns successfully swap the primary data-variant-id attached to the add-to-cart firing function.
  • Composed Content Tiers: Integrate Sanity CMS via @sanity/astro to render marketing pages and blocks natively using Astro structures, while using Sanity Connect to bridge Shopify IDs seamlessly into the content workspace.
  • Localization: Activate Shopify Markets to configure multi-currency data payloads based on locale routing parameters.