Breaking Changes
- [Pro] Node Renderer now requires Ruby 3.3+ for the async-http transport: The
react-on-rails-progem now requires Ruby>= 3.3(raised from>= 3.0) becauseasync-httpdepends on Ruby 3.3 features. Upgrade Ruby before moving to this release. Seedocs/pro/updating.mdfor the full upgrade guide. PR 3320 by AbanoubGhadban. - [Pro] Async Rails server deployments need to stay on the HTTPX renderer until support is added: Falcon and async-rails deployments are not currently supported with the new async-http renderer client because calling the renderer from inside an existing Async reactor without an
Async::Task.current?context can create a nested reactor. Keep those deployments on the previous HTTPX renderer client until support is explicitly added. Seedocs/pro/updating.mdfor the full upgrade guide. PR 3320 by AbanoubGhadban. - [Pro]
config.renderer_http_pool_sizenow limits per-request HTTP/2 streams: Existing numeric values now cap concurrent HTTP/2 streams for each request-scoped renderer client instead of sizing a persistent process-wide connection pool. Setting a non-default value emits a warning so the changed meaning is visible during upgrades; settingnilkeeps the default stream limit and does not make the request-scoped client unlimited. Persistent connection reuse is tracked in Issue 3283. Seedocs/pro/updating.mdfor the full upgrade guide. PR 3320 by AbanoubGhadban.
Added
- [Pro] Built-in HTTP rolling-deploy adapter (scaffold): New
ReactOnRailsPro::RollingDeployAdapters::Httpadapter pairs with an auto-mountedReactOnRailsPro::RollingDeploy::BundlesControllerso the currently-deployed Rails server can directly serve previously-deployed bundles to the next deploy's build CI — no S3 bucket, IAM, or extra gem required. The controller exposes authenticatedGET /manifestandGET /bundles/:hashendpoints using bearer-token auth (constant-time compare, 32-byte minimum), and the adapter pulls bundle tarballs (stdlib-only gzip/tar compose-extract with path-traversal proofing, regular-files-only guards, and a 200 MB zip-bomb cap). Configure viaconfig.rolling_deploy_adapter = ReactOnRailsPro::RollingDeployAdapters::Http,config.rolling_deploy_token, andconfig.rolling_deploy_previous_url. Seedocs/pro/rolling-deploy-http-adapter.mdfor setup. This is part 1 of a multi-PR series — a hard HTTPS gate, streaming download, and additional hardening land in follow-ups. PR 3379 by justin808. - [Pro] OpenTelemetry integration for the Node Renderer: New optional integration at
react-on-rails-pro-node-renderer/integrations/opentelemetrythat adds distributed tracing via standard OpenTelemetry. Users enable it by installing the@opentelemetry/*and@fastify/otelpackages (optional peer deps) and callinginit({ fastify: true, tracing: true })from their renderer entrypoint, beforereactOnRailsProNodeRenderer(). Provides auto-instrumented HTTP and Fastify spans, an SSR root span (ror.ssr.request), and render-path sub-spans (ror.bundle.build_execution_context,ror.bundle.upload,ror.vm.execute,ror.result.prepare,ror.incremental.stream,ror.incremental.process_chunk). Configuration follows standard OpenTelemetry env-var conventions (OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_SERVICE_NAME,OTEL_RESOURCE_ATTRIBUTES, etc.); defaults toBatchSpanProcessorin production andSimpleSpanProcessorotherwise. The integration is fully optional — users who do not enable it pay zero runtime cost, and the renderer has no direct dependency on OpenTelemetry. Closes Issue 2156. PR 3382 by justin808. - [Pro] Richer Node Renderer span attributes:
ror.bundle.uploadnow recordsbytes.total(sum of bundle + asset upload source sizes);ror.vm.executerecordsbundle.timestamp;ror.result.preparerecordsresponse.bytes(UTF-8 byte length of the rendered response, omitted for streamed responses). Only byte counts and identifiers are recorded — request payloads and rendered HTML are never written into span attributes. ThesubSpanAPI now passes aSubSpanControllerto the wrapped function so integrations can attach attributes computed during the work; existing implementations must callfn(controller)(a no-op controller is fine when no span is created). Closes Issue 3390. PR 3422 by justin808.
Changed
-
[Pro]
RollingDeployCacheStagernow rejects bundle hashes that start with a hyphen: The sharedReactOnRailsPro::RollingDeploy::SAFE_HASH_PATTERNconstant (also used by the new HTTP rolling-deploy adapter) tightens the cache stager's old local pattern by additionally rejecting leading hyphens. Webpack content hashes never start with-in practice, so this is a no-op for default toolchains, but operators running a custom rolling-deploy adapter that emits hyphen-prefixed hashes will now see those hashes silently dropped from the staged set. If you depend on hyphen-prefixed hashes, rename them to start with an alphanumeric character or_. PR 3379 by justin808. -
Upgrade contributor pnpm tooling to 10.33.4: The monorepo now pins pnpm 10.33.4 with Corepack's hash-qualified
packageManagerformat, keeps the install-generator CI fallback on the same pnpm version, and relies on the root workspace pin instead of duplicate workspacepackageManagerdeclarations. PR 3400 by alexeyr-ci2. -
Allow trusted pnpm 10 build scripts in contributor installs: The root workspace now allowlists required native dependency postinstall checks for
@swc/coreandunrs-resolver, sopnpm installunder pnpm 10 no longer skips those trusted build hooks. PR 3421 by justin808. -
Release publishing now checks
origin/mainCI status before shipping:rake releasenow inspects GitHub Checks fororigin/mainbefore publishing, blocking stable releases on any visible failing or missing checks and prereleases on required checks, with an explicit override path for maintainers. PR 3407 by justin808. -
[Pro] Updated Pino in the Node Renderer: Raised the
react-on-rails-pro-node-rendererpinodependency range to^9.14.0 || ^10.1.0, aligning with the current Fastify dependency. PR 3401 by alexeyr-ci2. -
[Pro] Per-scheduler persistent HTTP connections for Node Renderer:
RendererHttpClientnow reuses HTTP/2 connections across requests within the same Fiber scheduler (Falcon, async Puma), eliminating per-request TCP+TLS+HTTP/2 handshake overhead. Standalone requests (no outer scheduler) continue using ephemeral connections with guaranteed cleanup. The internal connection pool automatically recovers from broken connections without manual eviction. PR 3428 by AbanoubGhadban. -
[Pro] Migrated Node Renderer HTTP transport from HTTPX to
async-http: React on Rails Pro now usesasync-http(~> 0.95) withio-endpoint(~> 0.17) for all Rails→Node Renderer requests (render, streaming render, asset upload), replacing the previous HTTPX adapter and the customhttpx_stream_bidi_patch.rb. The newRendererHttpClientis a request-scoped client (one client per Rails request — no persistent process-wide pool) and integrates with the length-prefixed wire protocol introduced in PR 2903. HTTP/2 bidirectional streaming for async props is now provided bypost_bidion the new adapter. Action required for upgraders:config.ssr_timeoutis now a per-read socket timeout applied to each renderer socket read, rather than a task-level timeout wrapping the entire request.config.renderer_http_pool_timeoutis now the TCP connect timeout; post-connect reads are bounded byssr_timeout.- No implicit transport retry for connection drops: drops surface immediately as
ReactOnRailsPro::Error/connection failures. HTTPX previously performed one implicit transport retry; the new adapter usesretries: 0and leaves retry policy to the existing bundle-upload retry loop.
See
docs/pro/updating.mdfor the full upgrade guide. PR 3320 by AbanoubGhadban.
Fixed
- Client-only Vite setups no longer fail Rails boot on Shakapacker's
packageManagerguard: React on Rails now installs an engine initializer that runs beforeshakapacker.manager_checkerand no-ops Shakapacker'serror_unless_package_manager_is_obvious!when the host app has no Shakapacker config (config/shakapacker.ymlorSHAKAPACKER_CONFIG). This unblocks apps that use thereact-on-rails/clientnpm package from an existing Vite entrypoint and do not use the Ruby render helpers. The Ruby helpers that resolve bundle paths still require Shakapacker configuration. Apps with Shakapacker config keep Shakapacker's guard unchanged. Fixes Issue 3145. PR 3365 by justin808. - [Pro] HTTP rolling-deploy bundle responses now include stronger no-cache headers: The built-in rolling-deploy manifest and bundle endpoints now send
Pragma: no-cacheandX-Content-Type-Options: nosniffalongsideCache-Control: no-store, reducing the risk of legacy caching or MIME-sniffing mishandling authenticated bundle payloads. PR 3439 by justin808. - [Pro] OpenTelemetry shutdown timeout warning never logged:
shutdownProviderWithTimeoutin the Node Renderer's OpenTelemetry integration was missing alog.warn(call, leaving a bare string literal that produced no diagnostic whenprovider.shutdown()exceeded its timeout (and broke the source file's compilation). The timeout message now logs correctly. Follow-up to PR 3382. PR 3420 by justin808. - [Pro] Streaming server-render responses now raise
ReactOnRailsPro::Errorwhen the stream response status is unavailable or the renderer delivers a readable HTTP error status as a streaming body, instead of silently returning no chunks. This is a user-visible behavior change for callers that do not already rescueReactOnRailsPro::Errorfromeach_chunk. PR 3383. - [Pro] TanStack Router hydration now supports the current router stores API:
react-on-rails-pro/tanstack-routerclient hydration now uses TanStack Router's currentrouter.stores.setMatches()API whenrouter.__store.setState()is unavailable, so SSR hydration works with newer@tanstack/react-routerreleases without app-level compatibility shims. Fixes Issue 3375. PR 3376 by justin808. - [Pro] TanStack Router hydration no longer double-calls
loadRouteChunkunder React 18 StrictMode: React 18's StrictMode double-renders components with fresh hook state on each pass, so therouterRef.current === nullguard inclientHydrate.tsfired twice whenoptions.createRouterreturned the same router instance, re-runningloadRouteChunk,__store.setState, and the user-definedhydratecallback. The render-phase init is now memoized via a module-levelWeakMapkeyed on the router instance, dedup'ing per-router side effects across mount cycles. Production behavior is unchanged because each mount creates a fresh router. Fixes Issue 3405. PR 3410 by justin808. - [Pro] Benchmark CI starts the production dummy app on the expected port:
react_on_rails_pro/spec/dummy/bin/prodnow setsPORT=3001by default before launching Foreman, preventing Foreman's defaultPORT=5000from making the Rails server miss the benchmark workflow readiness check onlocalhost:3001. Bothreact_on_rails/spec/dummy/bin/prodandreact_on_rails_pro/spec/dummy/bin/prodrespectPORTwhen it's set. PR 3403 by alexeyr-ci2. - CI fails on stale lockfiles outside minimum-dependency jobs: GitHub Actions now runs Bundler with frozen lockfiles for standard integration, Pro, Playwright, lint, and precompile jobs, and no longer mutates lockfiles with
bundle lock --add-platform.pnpm installis also frozen in Playwright. The intentionally mutable minimum-dependency jobs still use non-frozen installs afterscript/convert. PR 3404, PR 3430 by alexeyr-ci2. - [Pro] Generated
bin/devProcfiles now start the Node Renderer: Pro setup now appends anode-rendererprocess toProcfile.dev,Procfile.dev-static-assets, andProcfile.dev-prod-assetswhen those files exist, so SSR pages work inbin/dev,bin/dev static, andbin/dev prod.react_on_rails:doctornow warns when a Pro NodeRenderer app's launcher Procfiles can serve Rails pages but do not start a renderer onRENDERER_PORT. Fixes Issue 3372. PR 3381 by justin808. - Prerelease changelog auto-versioning now warns for cross-channel reuse:
bundle exec rake update_changelog[rc]and[beta]now correctly warn when an active prerelease base exists only in a different prerelease channel, helping maintainers catch accidental channel switches before stamping a release header. PR 3417 by justin808.
Deprecated
- [Pro]
config.renderer_http_keep_alive_timeoutis deprecated: The setting now has no effect because async-http renderer clients are scoped to individual requests. Setting it emits a deprecation warning; remove the configuration during upgrade. Seedocs/pro/updating.mdfor the full upgrade guide. PR 3320 by AbanoubGhadban.
Removed
- [Pro] Removed HTTPX transport gem dependencies from the Node Renderer: React on Rails Pro no longer depends on
httpx,http-2, orconnection_poolafter migrating toasync-http. Applications that directly pin or require those gems for renderer integration should remove that coupling or add their own explicit dependency. PR 3320 by AbanoubGhadban.