Nt 3090 nextjs csr#262
Merged
Merged
Conversation
Restructure the bare create-next-app scaffold into a proper monorepo implementation with both React Web SDK and Node SDK dependencies, PM2-managed mock/serve scripts, env config, and AGENTS.md aligned with existing implementation patterns.
and client-resolved demo
localStorage crash
Replace the useState/useEffect mount guard with a dedicated
ClientProviderWrapper that uses next/dynamic({ ssr: false }). This is
the standard Next.js pattern for browser-only third-party SDKs and
keeps OptimizationProvider clean without SSR workarounds.
- Add Node SDK server singleton and Next.js middleware for cookie lifecycle (ctfl-opt-aid profile management). - Add server-resolved page: Server Component fetches entries and resolves them via Node SDK, renders pure server HTML with zero client JS for content. - Add InteractiveControls as a small 'use client' component for consent/identify on the server-resolved route. - Isolate SDK setup per route: each route has its own layout with its own ClientProviderWrapper, root layout is neutral. - Remove custom OptimizationProvider wrapper; use SDK's OptimizationRoot directly via dynamic import.
Document isolated route layouts, server-resolved vs client-resolved patterns, design decisions, cookie-based profile management, and the singleton dev-mode recovery tip.
… direction Add context on why this reference implementation exists, the known singleton conflict when navigating between routes, and plans to gather customer architecture patterns from pre/post-sales to inform which setups to prioritize.
Remove server-resolved route, middleware, Node SDK dependency, and all server-side resolution code. This implementation now uses only @contentful/optimization-react-web for pure client-side entry resolution. The SSR hybrid pattern lives in a separate react-web-sdk+node-sdk_nextjs implementation.
Superseded by the actual reference implementations.
The root ESLint (v10) is incompatible with eslint-plugin-react pulled by eslint-config-next. The Next.js implementations have their own local eslint.config.mjs and are linted via their own setup.
Convert from pure CSR to hybrid pattern: Server Component first paint via Node SDK, Client Component interactive page via useOptimization(). Add middleware for cookie lifecycle, Node SDK singleton, and Link-based SPA navigation between SSR and CSR routes.
Pass server-resolved profile, selectedOptimizations, and changes into OptimizationRoot via defaults prop. Eliminates the state gap between SSR first paint and client takeover. Provider moved to page level to receive server data as props.
Prime the layout-level OptimizationRoot from shared request-scoped optimization data so SSR and CSR takeover use the same evaluated state. This keeps the provider stable across navigations while preserving a seamless first-paint handoff.
Charles Hudson (phobetron)
approved these changes
May 8, 2026
Collaborator
Charles Hudson (phobetron)
left a comment
There was a problem hiding this comment.
I think this looks great!! If you're happy with it too, 🚢 👍🏻
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.
Hybrid SSR + CSR Takeover personalization pattern for Next.js App Router. First paint is server-resolved via the Node SDK (zero flicker, personalized HTML in the initial response). After hydration, the React Web SDK takes over for entry resolution; identify, consent, and reset re-resolve variants immediately without a server roundtrip. Subsequent navigations via are SPA-style, with entries fetched and resolved client-side. The cookie ctfl-opt-aid bridges identity between server and client. Known gap: OptimizationRoot cannot accept pre-fetched server data, so the Web SDK makes a redundant Experience API call on hydration before client-side reactivity activates.
Use the layout-level OptimizationRoot and prime it with server-resolved defaults (profile, selectedOptimizations, changes) from a shared request-scoped getOptimizationData() helper. This keeps the Web SDK stable across navigations, avoids provider remounts, and gives the client the same optimization state the server used for first paint, making the SSR→CSR takeover seamless
Note: The root implementation:lint script runs ESLint 10 (installed at the repo root) against all implementations/ code. When it hits the Next.js implementation, ESLint 10 resolves eslint-plugin-react@7.37.5 from that implementation's node_modules. That plugin version uses context.getFilename(), an API removed in ESLint 10, causing a TypeError that crashes the entire lint run.
vercel/next.js#89764