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
+20 -14
View File
@@ -1,30 +1,36 @@
import { defineConfig } from 'vite';
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
import { nitro } from 'nitro/vite';
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';
import { tanstackRouter } from '@tanstack/router-plugin/vite';
import devServer from '@hono/vite-dev-server';
import { fileURLToPath, URL } from 'node:url';
// Absolute origin for canonical and Open Graph URLs. Inlined at build time so
// the server render and the client agree on it. Vercel provides the production
// domain; set VITE_SITE_URL to override it anywhere.
const siteUrl =
process.env.VITE_SITE_URL ??
(process.env.VERCEL_PROJECT_PRODUCTION_URL
? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
: 'http://localhost:3000');
export default defineConfig({
server: { port: 3000 },
plugins: [
// Must run before the React plugin so the generated route tree is in place.
tanstackRouter({ target: 'react', autoCodeSplitting: true }),
// Start must come before the React plugin.
tanstackStart(),
// Builds the server for the host: Vercel's Build Output when deployed
// there, a standalone Node server (.output/) everywhere else.
nitro(),
react(),
tailwindcss(),
// Serves the Hono API in dev. Everything outside /api falls through to
// Vite, which serves the SPA.
devServer({
entry: 'server/app.ts',
exclude: [/^(?!\/api(\/|$)).*/],
injectClientScript: false,
}),
],
define: {
'import.meta.env.VITE_SITE_URL': JSON.stringify(siteUrl),
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
build: {
outDir: 'dist/client',
},
});