Skip to content

Latest commit

 

History

History

solid-start

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

SolidStart example

Development example for exercising Hydrogen APIs in SolidStart. This is not a starter template. See ../README.md for context.

Port of the canonical examples/core design to SolidStart v1 (Vinxi + Solid Router, SSR enabled by default).

What this demonstrates

  • Signals as a first-class citizen. createSignal drives cart, product form, and collection browse state derived from Hydrogen's core stores — no virtual DOM, no useState, no batching. The reactive primitive is the model.
  • query + createAsync as the data path. Each route defines a server-side query, exports a route.preload so the router can kick the fetch off during navigation, and reads the result with createAsync() — Solid's idiomatic SSR-aware fetcher.
  • "use server" on every fetcher. Storefront API calls run on the server during SSR and on subsequent client navigations are issued as RPC, not from the browser.
  • Core Hydrogen primitives for cart, product variant selection, collection filtering/sorting, and Shop Pay without framework bindings.
  • File-based routing via FileRoutes. src/routes/ is the source of truth — folder layout maps directly to URL paths, including [handle].tsx dynamic params.
  • Shared chrome (Header, Footer) at the root. Mounted in src/app.tsx's Router root, not duplicated per-route.
  • Tailwind v4 via @tailwindcss/vite. The design's @theme tokens live in src/app.css.

Pages

Route Source Status
/ examples/core/reference/home.html Live: hero is static; featured products grid pulls from products(first: 3)
/collections examples/core/reference/collections.html Live: queries collections(first: 12)
/collections/:handle examples/core/reference/collection.html Live: queries collection(handle:) with filters, sort, and active filter chips
/products/:handle examples/core/reference/product.html Live: gallery, URL-synced variant options, add-to-cart, Shop Pay, and related products
/cart (Hydrogen primitive) Live: optimistic line updates, discount codes, order note, totals, checkout, and Shop Pay
/blogs/news (new) Live: featured article + grid from blog(handle:"news").articles
/blogs/news/:handle (new) Live: title, date, contentHtml rendered via innerHTML
/account (new) Live: Customer Account OAuth session, basic customer name/email, logout form
/account/login (new) Live: Hydrogen Customer Account handler starts OAuth and stores pending PKCE state
POST /account/logout (new) Live: Hydrogen Customer Account handler clears session and redirects with 303 See Other

Stubbed vs. live

  • Live: product, collection, blog, and article data; prices; images; URL-synced options; cart mutations; collection filters/sort; checkout links; Shop Pay buttons; Customer Account login/session state, basic customer identity, logout.
  • Stubbed: hero links, search, newsletter form.

Customer Account setup

The account flow uses createCustomerSession and createCustomerAccountServerHandlers from @shopify/hydrogen/customer-account, Customer Account values from examples/shared/config.ts, and an encrypted HttpOnly __Host- cookie adapter from examples/shared/customer-session.ts.

Customer Account OAuth requires a public HTTPS origin. To test locally without a tunnel, run:

pnpm --filter @shopify/hydrogen-example-solid-start dev:https

On the first run, restart the command after the Vite plugin provisions the certificate so Vinxi can load it.

When the server starts, the local HTTPS plugin links an unlinked Hydrogen storefront and pushes the Customer Account callback, JavaScript origin, and logout URLs. If automatic setup is unavailable, it prints the values for manual configuration.

Run

# from the repo root
pnpm install
pnpm --filter @shopify/hydrogen-example-solid-start dev

Then open http://localhost:3000.

Note on HOST

Vinxi has no config field for its bind target; it reads HOST (and PORT) from the environment when the listener starts. Shopify-managed dev machines export HOST globally — without an override the dev server tries to bind to that hostname, falls back through alternative ports, and prints an unreachable network URL.

app.config.ts sets process.env.HOST/PORT after evaluating the local HTTPS plugin: local.tryhydrogen.dev:5173 for dev:https, localhost otherwise. Doing it in the config rather than as a HOST=... prefix in the scripts keeps dev and dev:https working on Windows shells, which treat HOST=x as a command. start still inlines HOST=localhost because vinxi start serves the built output and never loads app.config.ts.

Notes for the core SDK

These are calls/patterns that would benefit from a @shopify/hydrogen helper as the core package grows:

  • storefrontClient.graphql() from getRequestStorefrontClient() — now uses the request-scoped client created in src/middleware.ts with gql.tada for zero-config type inference. Error normalization and request-id propagation are handled by the core client.
  • formatMoney() in src/lib/money.ts — every example will need money formatting from a MoneyV2-shaped object.
  • ProductCard reads a narrow product shape (handle, title, featuredImage, priceRange.minVariantPrice). A core fragment + type for "product card" would let routes share GraphQL fragments instead of re-listing fields.
  • Option value swatch data is exposed through createProductFormStore().getState().options[].values[].swatch, so selectors can render API-backed swatches with value.swatch.

Open questions

  • Framework bindings. This example intentionally uses core primitives directly. If Solid bindings are added later, compare them against src/lib/cart.tsx, src/components/CollectionBrowser.tsx, and src/components/ProductPurchasePanel.tsx.
  • start on Windows. vinxi start bypasses app.config.ts, so its HOST=localhost prefix is still shell-specific. A cross-platform fix would need a small Node launcher or a cross-env-style helper; not worth a dependency for a dev-only example yet.