Server-Side Rendering (SSR) Differences with PWA Kit

PWA Kit and Storefront Next implement SSR, but with fundamentally different architectures that reflect their respective technology stacks. PWA Kit's SSR approach gives developers explicit control through Express and React Query, with optional partial hydration via Islands. Storefront Next uses React Router 7's built-in SSR with automatic streaming, middleware chains, and loader-based data fetching. Storefront Next's approach reduces boilerplate and provides better streaming performance, while the PWA Kit approach offers more granular control over hydration timing.

Key Differences

Aspect PWA Kit Storefront Next
SSR Runtime Express server with runtime.render React Router 7 framework mode
Data Hydration React Query cache serialization Promise streaming with use() hook
Middleware Express middleware React Router middleware chain
Partial Hydration Island component with strategies Suspense boundaries with createPage
Server Context useServerContext() hook Context from middleware chain
Code Splitting @loadable/component React Router's automatic splitting
Cache Control Manual via res.set() Via HTTP response from middleware

Data Flow Comparison

PWA Kit:

  1. Express receives request.
  2. React tree renders.
  3. React Query hooks execute during render.
  4. Data fetched, components re-render with data.
  5. Query cache serialized to HTML.
  6. Client hydrates with cached data.

Storefront Next:

  1. React Router receives request.
  2. Middleware chain runs (auth, config, i18n).
  3. Loaders execute, return promises.
  4. React renders, use() unwraps promises.
  5. HTML streams as promises resolve.
  6. Client hydrates, clientLoader runs.

Hydration Approaches

PWA Kit offers fine-grained control with Island:

<Island hydrateOn="visible">
  <Footer />
</Island>

Storefront Next uses Suspense boundaries:

export default createPage({
  component: ProductDetail,
  fallback: <ProductSkeleton />,
});

Storefront Conversion Considerations

  1. useServerContext vs. Middleware: Server-side logic like setting cache headers moves from component hooks to middleware or loaders.

  2. React Query vs. Loaders: Data fetching moves from hooks inside components to loader functions exported from route files.

  3. Island vs. Suspense: Partial hydration with Island becomes Suspense boundaries with createPage.

  4. Express routes vs. Resource routes: Custom API endpoints move from Express handlers to React Router resource routes.