Migrate to TanStack Start and pin the Vercel preset

Vercel auto-detected the Hydrogen preset from the @shopify/hydrogen
dependency and failed building a 'hydrogen' Edge Function. The app is now
TanStack Start (SSR via Nitro), and vercel.json pins the tanstack-start
preset and installs with Corepack so Yarn 4 is used.

- Router factory with per-request QueryClient and SSR query dehydration
- Hono API mounted as a Start server route at /api/*
- Account reads in loaders go through server functions (cookies on SSR)
- Loaders prefetch listing pages so products are in the server HTML
- Add graphql peer dependency for gql.tada

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Rami Bitar
2026-10-03 11:35:35 -04:00
co-authored by Claude Opus 5.5
parent c447c51e82
commit 160e65f0ed
26 changed files with 732 additions and 249 deletions
+35 -24
View File
@@ -1,33 +1,45 @@
# Vite Shopify Storefront
A Shopify storefront built with Vite, React 19, TanStack Router, TanStack Query,
Tailwind CSS v4, Hono and `@shopify/hydrogen`. It's a port of
A server-rendered Shopify storefront built with TanStack Start (Vite + TanStack
Router), TanStack Query, Tailwind CSS v4, Hono and `@shopify/hydrogen` (used
only as a Storefront API client and typed `gql()`). It's a port of
`nextjs-templates/shopify-storefront` without the AI store assistant.
## Getting started
```sh
cp .env.example .env.local # defaults to the tokenless mock.shop
corepack enable # uses the Yarn 4 pinned in package.json
yarn install
yarn dev # http://localhost:5173
yarn dev # http://localhost:3000
```
| Script | What it does |
| ---------------- | --------------------------------------------------------- |
| `yarn dev` | Vite dev server with the Hono API mounted at `/api` |
| `yarn build` | Client build to `dist/client`, server build to `dist/server` |
| `yarn start` | Production Node server (API + static client), `PORT` or 3000 |
| `yarn dev` | Vite dev server with SSR and the `/api` routes |
| `yarn build` | Production build via Nitro (`.output/`, or Vercel's Build Output on Vercel) |
| `yarn start` | Run the Node build from `.output/` |
| `yarn typecheck` | `tsc` plus `hydrogen gql check` for the GraphQL documents |
## Deploying to Vercel
`vercel.json` pins the **TanStack Start** preset. Without it Vercel's
auto-detection sees `@shopify/hydrogen` and picks the Hydrogen preset. It also
installs with Corepack so Vercel uses Yarn 4. Set the `VITE_SHOPIFY_*` variables
in the project; the production domain is picked up for canonical URLs
automatically, or set `VITE_SITE_URL`.
## Layout
```
server/ Hono API — classic customer accounts behind an httpOnly cookie
app.ts /api routes (mounted by @hono/vite-dev-server in dev)
account.ts login, logout, register, recover, reset, activate, me, customer
node.ts production entry: API + dist/client + SPA fallback
src/
routes/ TanStack file routes (route tree is generated)
router.tsx Router + per-request QueryClient, SSR query integration
routes/ File routes; loaders prefetch into TanStack Query
api/$.ts Mounts the Hono app for every /api/* request
server/
app.ts Hono API
account.ts login, logout, register, recover, reset, activate, me
account.functions.ts server functions for account reads in loaders
hooks/ TanStack Query options + hooks over the Storefront API
services/shopify Storefront client, catalogue and customer functions
graphql/ Typed `gql()` documents
@@ -36,17 +48,16 @@ src/
## How the Next.js pieces map
| Next.js | Here |
| -------------------------------- | ----------------------------------------------------- |
| `app/**/page.tsx` | `src/routes/**` (TanStack file routes) |
| `generateMetadata` / `metadata` | route `head()` via `src/lib/seo.ts` + `<HeadContent />` |
| Server-side data fetching | route `loader`s seeding the TanStack Query cache |
| `app/api/account/*` route handlers | `server/account.ts` (Hono) |
| `next/headers` cookies | `hono/cookie` |
| `next/image` | `src/components/ui/image.tsx` (Shopify CDN `srcset`) |
| `useSearchParams` | `validateSearch` + `Route.useSearch()` |
| `NEXT_PUBLIC_*` env | `VITE_*` env |
| Next.js | Here |
| ---------------------------------- | ---------------------------------------------------- |
| `app/**/page.tsx` | `src/routes/**` (TanStack file routes) |
| `generateMetadata` / `metadata` | route `head()` via `src/lib/seo.ts`, server-rendered |
| Server components fetching data | route `loader`s seeding TanStack Query, dehydrated to the client |
| `app/api/account/*` route handlers | `src/server/account.ts` (Hono) |
| `next/headers` cookies | `hono/cookie`, and `getCookie` in server functions |
| `next/image` | `src/components/ui/image.tsx` (Shopify CDN `srcset`) |
| `NEXT_PUBLIC_*` env | `VITE_*` env |
Catalogue and cart requests go straight from the browser to the Storefront API
with the public token. Account requests go through Hono so the customer access
token never reaches client JavaScript.
Cart and catalogue reads after the first page load go straight from the browser
to the Storefront API with the public token. Account requests stay on the
server, so the customer access token never reaches client JavaScript.