templates/react-router: add standalone RR7 storefront template#3818
Merged
Conversation
Adds the generated standalone React Router 8 five-page storefront (home, product, collection, collections index, search) with the full cart path, shared chrome, and analytics/consent layer, under a new top-level templates/ dir. This is a self-contained artifact: it ships its own pnpm-lock.yaml, .npmrc, and LICENSE and pins @Shopify/hydrogen to the published "preview" tag, so it runs on its own when copy-pasted into a fresh repo by the build pipeline. It is not a workspace member (templates/ is outside the pnpm-workspace globs), so it is ignored by install/build/typecheck/test/lint. Add templates/** to the oxfmt ignore list (mirroring the source repo) so format:check does not touch generated output. Nothing under examples/ is changed. One-off manual import from the storefront-kit generator; future imports will be automated.
717c875 to
132b4aa
Compare
frandiox
requested changes
Jun 26, 2026
frandiox
left a comment
Contributor
There was a problem hiding this comment.
Thanks Misha! Problem: This template is not compatible with Oxygen. Please check the main branch template/skeleton to see how it works. It needs server.ts, oxygen() vite plugin, different dependencies, and different scripts to run/build.
Also, once this PR is released, this template should be updated like this.
The React Router template is what the "Deploy to Oxygen" button installs, so it must run on Oxygen (workerd). It was a plain React Router 8 Node app and could not deploy. This converts it to the Oxygen worker runtime while staying on RR8 and the framework-agnostic @Shopify/hydrogen (preview) library — no classic Hydrogen (which hard-pins react-router@7.14.0). - Add server.ts (module fetch worker entry: createRequestHandler from react-router + a RouterContextProvider) and worker SSR entries (app/entry.server.tsx via renderToReadableStream, app/entry.client.tsx). - vite.config.ts: add @shopify/mini-oxygen oxygen() (RR-agnostic); no classic hydrogen() plugin. Scripts -> shopify hydrogen dev/build/preview. - Deliver runtime env via the worker `env` binding instead of process.env: server.ts stashes env on the RouterContext; root middleware reads it and builds the request-scoped Storefront client (app/lib/env.ts, env.d.ts, app/lib/storefront.ts, app/lib/shop.ts). NODE_ENV stays (Vite inlines it). - Deps: add @shopify/cli, @shopify/mini-oxygen, @shopify/oxygen-workers-types; drop @react-router/node and @react-router/serve. Regenerate the standalone pnpm-lock.yaml. - README: document the Hydrogen/Oxygen workflow. Track .env.example (force-add; the repo .gitignore's .env.* rule was excluding it, so the README's `cp .env.example .env` would have failed in a deployed copy). Verified: `shopify hydrogen build` (standalone, npm preview lib) produces the worker; it boots and SSR-renders the home page (HTTP 200) in workerd with MOCK_SHOP via the env binding; `pnpm typecheck` (tsc + gql.tada) is clean.
…npm) Replace the RR8 chassis with the proven, Oxygen-deployable React Router 7 + classic Hydrogen + Oxygen template, verified end-to-end (npm install + build + `shopify hydrogen deploy` green on Oxygen). - React Router 7.14.0 (the exact @shopify/hydrogen-classic peer; npm-strict-safe) + classic hydrogen() + oxygen() Vite plugins; buildDirectory "dist". - Worker entry (server.ts), Web-Streams server/client entries, worker env typing. - Storefront mode auto-detects: real store when PRIVATE_STOREFRONT_API_TOKEN is present (Oxygen injects it + PUBLIC_STORE_DOMAIN for a linked storefront), mock.shop fallback otherwise, so a fresh deploy always renders. MOCK_SHOP=1 forces mock. - npm-flavored: ships package-lock.json (the Oxygen workflow runs `npm ci`), npm README; pnpm-lock.yaml dropped. - patch-hydrogen-exports.mjs (postinstall): temporary shim adding the missing "./package.json" export to @Shopify/hydrogen so `shopify hydrogen deploy` builds under npm. Remove once the lib ships that export.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One-off manual import of the generated standalone React Router 8 storefront template from the storefront-kit generator, added under a new top-level
templates/dir. Nothing underexamples/is changed.What's here: the full five-page storefront (home, product, collection, collections index, search) with the real cart path, shared chrome, and analytics/consent layer.
Standalone by design — meant to be copy-pasted into a fresh repo by the build pipeline, so it runs on its own:
pnpm-lock.yaml,.npmrc, andLICENSE@shopify/hydrogento the publishedpreviewtag (notworkspace:*)Not a workspace member (
templates/is outside the pnpm-workspace globs), so install / build / typecheck / test / lint ignore it. The one supporting change is addingtemplates/**to the oxfmt ignore list (mirroring the source repo) soformat:checkdoesn't reformat generated output.Future imports will be automated; this is a one-off to test the flow.