Skip to content

v17.0.0.rc.6

Pre-release
Pre-release

Choose a tag to compare

@justin808 justin808 released this 22 Jun 09:29

Added

  • [Pro] Bidirectional async props streaming (pull mode): stream_react_component_with_async_props can now let React request lazy props during incremental rendering, complementing the existing eager push model. The stream protocol carries propRequest / renderComplete control messages from the node renderer back to Rails, AsyncPropsManager can request or reject props on demand, and the Pro dummy app now covers pure pull, mixed push/pull, Redis-backed fixtures, and rejection/error-boundary scenarios. Closes Issue 4046. PR 4048.
  • Owner Stacks in development error reports: When a React component throws during rendering, React on Rails now enriches its development error reporting with React 19.1+'s dev-only captureOwnerStack output — the chain of components that rendered the failing one (e.g. at Avatar / at PostCard / at PostList). On the server-side rendering path, the owner stack is captured synchronously inside the Pro streaming onError callback and appended to the error's stack, so it flows through to the Rails-side ReactOnRails::PrerenderError / SmartError (:server_rendering_error) output and the streamed shell-error HTML. On the client, recoverable hydration mismatches (onRecoverableError) automatically gain an owner-stack line in the branded development log, and apps that register their own onCaughtError/onUncaughtError handler get an additive [ReactOnRails] Render error ... Owner stack: line for client render errors. To avoid displacing React's own built-in development diagnostics (component stacks, error-boundary hints), React on Rails does not auto-attach caught/uncaught handlers solely to log owner stacks. Owner-stack capture requires React >= 19.1 running its development build, so it is a strict no-op on older React and in all production builds (no capture, no captureOwnerStack call), asserted by tests. The ExecJS rendering path is out of scope (capture must happen JS-side, synchronously, inside React's error callback). Closes Issue 3887. PR 4089 by justin808.
  • hydrate_on scheduling: react_component now accepts a hydrate_on: option to defer client hydration of an island until it is needed — :immediate (default, unchanged), :visible (hydrate when the container scrolls near the viewport via IntersectionObserver), or :idle (hydrate during browser idle time via requestIdleCallback). Deferred roots are cleaned up on Turbo/Turbolinks navigation and re-scheduled if their node is detached and reattached; unsupported modes raise, and non-:immediate modes are rejected when React on Rails Pro is installed. Closes Issue 3890. PR 4037 by justin808.

Changed

  • Breaking (types only): RenderFunction no longer accepts the legacy 3-argument renderer shape: The exported RenderFunction type is now exactly the 2-argument server/client render-function form ((props, railsContext) => RenderFunctionResult), equal to the existing ServerRenderFunction. It previously also accepted a 3-argument (props, railsContext, domNodeId) => RenderFunctionResult arm, which let nonsensical role combinations typecheck (a server render-function "returning" a renderer teardown, or a renderer "returning" a server-render hash). Renderer functions — the 3-argument form that owns its own DOM mount and may return a { teardown } wrapper — should now be typed RendererFunction. ReactComponentOrRenderFunction already includes RendererFunction, so renderer-shaped functions remain registerable. The tighter type also drops the re-narrowing as casts the unified type forced in createReactOutput and the Pro tanstack-router render function. This is a compile-time-only change with no runtime behavior difference; only TypeScript consumers that annotated a 3-argument renderer as RenderFunction need to switch it to RendererFunction. Closes Issue 3592. PR 4096 by justin808.
  • [Pro] Pinned react-on-rails-rsc to the stable 19.0.5 release: The generator default, the root and Pro package manifests, the lockfile, and the Pro RSC install docs now pin the stable react-on-rails-rsc@19.0.5 (previously the 19.0.5-rc.7 prerelease). The native RSC CSS FOUC fix requires react-on-rails-rsc >= 19.0.5. Closes Issue 3634. PR 4080 by justin808.
  • [Pro] RSC peer-compatibility warn-tier floor raised to stable 19.0.5: The Pro node renderer's recommendedMin for react-on-rails-rsc is now the published stable 19.0.5 (previously the dormant 19.0.2). Anyone still on an older 19.x build (19.0.219.0.4) now gets a loud startup warning that they are missing the coordinated RSC fixes shipped in 19.0.5 (FOUC stylesheet preloading, async manifest signatures); 19.0.5+ no longer warns. Refs Issue 3632. PR 4078 by justin808.
  • [Pro] RSC peer wildcard replaced with an explicit range: The Pro npm package's optional react-on-rails-rsc peer dependency is now ^19.0.5 (>= 19.0.5 < 20.0.0) instead of "*", so installs are floored at the RSC CSS FOUC fix release 19.0.5 and capped below the next major 20.0.0, rather than "*" accepting any version including pre-FOUC builds and an unknown future major. Within the 19.x line, per-version compatibility is enforced by the Pro node renderer's runtime version check (rscPeerSupport.ts), not by this advisory peer range. Fixes Issue 3965. PR 4082 by justin808.

Fixed

  • Deferred hydration error reporting handles non-Error thrown values: Delayed hydrate_on renders now normalize strings, null, and frozen Error instances before logging, so reporting the failure does not throw again or mutate user errors. PR 4120 by ihabadham.

  • Explicit Webpack installs now pass the resolved bundler to Shakapacker. rails generate react_on_rails:install --no-rspack and --webpack now set SHAKAPACKER_ASSETS_BUNDLER=webpack before running shakapacker:install, so Shakapacker installs Webpack dependencies instead of falling back to its default bundler. Fixes Issue 4108. PR 4109 by ihabadham.

  • Generated demo paths now honor custom Shakapacker source roots. The install generator resolves demo components, entrypoints, stylesheets, TypeScript includes, Tailwind imports, and RSC hints from the app's Shakapacker source_path / source_entry_path settings, including slash entry roots, while wrapping long source hints in the generated demo views. Fixes Issue 4062. PR 4107 and PR 4130 by justin808.

  • RSC-safe generated i18n locale defaults: The JavaScript locale compiler that generates default.js no longer imports react-intl or wraps messages in defineMessages; it now emits the message descriptor object directly. This lets the generated locale defaults be imported from React Server Component bundles without pulling in the client-oriented react-intl entrypoint, and without raising the minimum supported react-intl version. The exported defaultMessages shape is unchanged, and existing apps regenerate automatically because the compiler treats a default.js still using the old defineMessages template as stale. Fixes Issue 4132. PR 4146 by justin808.

  • Abort the in-flight SSR render when the client disconnects (Pro streaming): Previously, when an HTTP client disconnected (or a request timed out) mid-stream, the Node renderer kept driving the React render to completion against a consumer that was already gone — wasting CPU and, for RSC/cache()-wrapped data fetches, continuing to hit the app's database/APIs. The Pro streaming layer now propagates the consumer-side teardown upstream into ReactDOM's PipeableStream.abort(): when the renderer worker detects the client disconnect it destroys the render's output stream, which aborts the in-flight render and releases the request's RSC payload streams. Normal completion is unaffected (the abort only fires when the output is destroyed before it ends, and never when a render error closes the stream). This also establishes the precondition for React 19.2's cacheSignal, which React settles automatically once a render is aborted (the cacheSignal-specific test and docs remain a follow-up). Part of Issue 3885. PR 4093 by justin808.

  • [Pro] Bounded the RSCProvider RSC payload cache to prevent unbounded growth under high-cardinality props: The provider-scoped promise cache (fetchRSCPromisesRef) and its companion bookkeeping (lastSuccessfulRSCPromisesRef, refetch versions, and the versions/successfulVersions state maps) are now backed by a bounded LRU (default cap 50 distinct RSC payload keys). High-cardinality componentProps (e.g. per-row or per-search-query routes) previously grew these maps without limit for the provider's entire lifetime — a latent memory leak. Eviction only affects cold, least-recently-used keys beyond the cap; same-key cache hits, refetch, recoverOnError restore, and version bumping are unchanged, and an in-flight refetch's key is pinned (with ref-counted pins, so overlapping same-key refetches stay protected until all of them settle) and cannot be evicted out from under its restore path. The per-key useSyncExternalStore subscription/fan-out optimization from the same issue is intentionally deferred pending profiling. Refs Issue 3564. PR 4097 by justin808.

  • [Pro] Enrich deferred-render RSC errors with the bundle diagnostic: When a Server Component failed during React's deferred render phase (a Suspense boundary resolving a lazy RSC element), the error surfaced through renderToPipeableStream's onError as a generic React stream error — the original RSC bundle diagnostic (the real server-side error message and module path) was already out of scope and lost. The Pro streaming layer now threads the captured diagnostic through the request-scoped tracker and merges it into the surfaced error, so ReactOnRails::PrerenderError / SmartError output names the failing RSC component and module instead of a bare React message. Since React's onError carries no component key, attribution is conservative: one captured diagnostic is merged exactly, two or more produce a combined "one of these N RSC components failed" message (never a single false pinpoint), and each captured diagnostic is consumed on first use so an unrelated later failure in the same render is never mislabeled. Completes the deferred-render half of the bundle-diagnostic work (the fetch and preloaded-hydration halves shipped earlier). Closes Issue 3475. PR 4100 by justin808.