Pre-Rendering
Shoppex always serves static files. There is no runtime server-side rendering (SSR). Two independent mechanisms turn a bare SPA shell into fully rendered HTML.| Mechanism | Who owns it | What it does |
|---|---|---|
| Platform Initial-Data Injection | Shoppex platform (automatic) | Injects store data into index.html after build |
| Theme Pre-Render Script (SSG) | Theme author (opt-in) | Renders route-specific HTML files at build time |
Mechanism 1: Platform Initial-Data Injection
Afterbun run build, Shoppex scans dist/index.html for the placeholder <!--initial-data-->. If found, it replaces the comment with a script tag containing the shop’s storefront data.
Add the Placeholder
What Shoppex Injects
At deploy time the platform replaces the placeholder with:This is fully automatic. The theme only needs the
<!--initial-data--> comment in index.html. No build script changes required.window.__SHOPPEX_INITIAL__ is injected at build/deploy time. If your shop data changes later (for example after a migration/import),
the injected HTML can be temporarily stale. Themes should treat initial data as “fast first paint” and still revalidate with
shoppex.getStorefront() on the client.Reading the Injected Data
Your app can read the data before any network request:InitialDataContext (see below).
Mechanism 2: Theme-Owned Pre-Render Script (SSG)
For full SEO and instant paint of every route, a theme can generate static HTML files during the build. This is entirely theme-owned — Shoppex does not run the script; you wire it into your build pipeline.Build Script Setup
Inpackage.json, chain the SSG step after the client and SSR builds:
On publish, Shoppex runs
bun run build. If you only add build:ssg but keep build as vite build, pre-rendering will run locally but not in production.How the Pre-Render Script Works
scripts/prerender.mjs does three things:
- Fetch data — calls the Shoppex API for store and products.
- Render routes — imports
dist-ssr/entry-server.jsand renders each route to an HTML string. - Write files — replaces
<!--app-html-->and<!--initial-data-->in the template and writes the result todist/.
| Route | Output file |
|---|---|
/ | dist/index.html |
/cart | dist/cart/index.html |
/checkout | dist/checkout/index.html |
/product/:slug | dist/product/<slug>/index.html (one per product) |
entry-server.tsx (Reference)
The SSR entry renders the app to a string using a static router:Client-Side Hydration
The client entry (main.tsx) detects whether the page was pre-rendered and chooses hydration or fresh rendering:
InitialDataContext
The reference theme provides the injected (or pre-rendered) data through React context so any component can access it without prop drilling:useInitialData() get the store and products immediately — no loading spinner needed on first paint.
Framework-Agnostic Notes
- The
<!--initial-data-->placeholder works for any framework. Platform injection does not depend on React. - The pre-render script is framework-specific. A Vue or Svelte theme would use the equivalent SSR primitives (
renderToStringfrom vue/server-renderer,renderfrom svelte/server, etc.).
Next Steps
Build Pipeline
Full build lifecycle from source to deployed dist.
Core Contract
The interface between Shoppex and your theme.
Sources
- Reference pre-render script:
themes/default/scripts/prerender.mjs - Client entry:
themes/default/src/main.tsx - SSR entry:
themes/default/src/entry-server.tsx - InitialDataContext:
themes/default/src/context/InitialDataContext.tsx