WORK-091
ID:WORK-091Status:done

Create @refrakt-md/next adapter package

Build the Next.js framework adapter. Uses React Server Components + renderToHtml() for zero-hydration content rendering, with a thin client component for behavior initialization.

Priority:mediumComplexity:moderateMilestone:v1.0.0
claude/align-sidenav-styling-4MuxV View source

Criteria completion

No incremental history — criteria tracking started on Apr 17.

Branches 3
History 4
  1. 4765c91
    Content editedby Claude
    Mark WORK-090, WORK-091, WORK-092 as done with resolution summaries
  2. 11e81a8
    Content editedby Claude
    Add framework work items to v1.0.0 milestone
  3. 982a9db
    Content editedby Claude
    Add documentation ACs to adapter work items and create WORK-093
  4. ead9531
    Created (done)by Claude
    Add work items WORK-088 through WORK-092 for framework adapter system

Acceptance Criteria

  • packages/next/ package exists with correct package.json (peer dep next@^14.0.0 || ^15.0.0)
  • RefraktContent Server Component renders via renderToHtml() + dangerouslySetInnerHTML (no 'use client')
  • BehaviorInit Client Component ('use client') initializes behaviors via useEffect, cleans up on unmount, re-initializes on route change
  • metadata.ts helper transforms page SEO data into Next.js Metadata objects for generateMetadata()
  • loader.ts wraps loadContent() for Next.js patterns (caching, revalidation)
  • Content loading works via generateStaticParams() + async Server Component
  • CSS injection works via import '@refrakt-md/lumina' in root app/layout.tsx
  • Lumina Next.js adapter exports theme config + types
  • Custom elements (rf-*) render correctly via raw HTML string (bypasses React's custom element issues)
  • Example site renders core runes, layouts, behaviors, and web components correctly
  • Adapter documentation page at site/content/docs/adapters/nextjs.md with installation, project structure, configuration, code examples (RefraktContent server component, BehaviorInit client component, generateMetadata helper, generateStaticParams, CSS import, layout setup), and getting-started guide matching the depth of existing SvelteKit adapter docs

Approach

The key insight is that renderToHtml() produces complete HTML strings, and RSC can inject them via dangerouslySetInnerHTML with zero hydration cost. This sidesteps all React custom element issues since React never processes the rf-* elements as components.

Behaviors need a separate 'use client' component since they require DOM access. This component renders nothing (return null) and manages behavior lifecycle via useEffect.

No custom HMR in Phase 1 — rely on Next.js dev server defaults. Custom Webpack/Turbopack plugin for content HMR is a future optimization.

Dependencies

  • WORK-088 (shared utility extraction)

References

  • SPEC-030 (Phase 3)
  • ADR-002 (Next.js section)

Resolution

Completed: 2026-04-04

Branch: claude/implement-spec-030-F0LFn

What was done

  • Created packages/next/ with RefraktContent server component, BehaviorInit client component, buildMetadata helper
  • Separate ./client export for tree-shaking (client code stays out of server bundles)
  • Uses moduleResolution: bundler in tsconfig for Next.js compatibility
  • Lumina Next.js adapter at packages/lumina/next/index.ts
  • Docs page at site/content/docs/adapters/nextjs.md

Notes

  • RefraktContent uses dangerouslySetInnerHTML — zero hydration cost
  • BehaviorInit manages lifecycle via useEffect, re-inits on pathname change
  • hasInteractiveRunes uses getBehaviorNames() from @refrakt-md/behaviors registry