github shakacode/react_on_rails v16.4.0.rc.8

pre-release10 hours ago

Changes since the last non-beta release.

Added

  • TanStack Router SSR integration (Pro): Added createTanStackRouterRenderFunction and serverRenderTanStackAppAsync via react-on-rails-pro/tanstack-router for TanStack Router SSR with the Pro Node Renderer. Uses TanStack Router's public router.load() API for reliable async SSR. Requires rendering_returns_promises = true in Pro config. PR 2516 by justin808.

  • create-react-on-rails-app --rsc flow: Added --rsc support to npx create-react-on-rails-app so a single command can scaffold an RSC-ready app. The CLI now installs react_on_rails_pro, passes --rsc to react_on_rails:install, and points users to /hello_server after setup. PR 2430 by justin808.

  • Environment-variable-driven ports in Procfile templates: Procfile templates now use ${PORT:-3000} and ${SHAKAPACKER_DEV_SERVER_PORT:-3035} instead of hardcoded ports, enabling multiple worktrees to run bin/dev concurrently without port conflicts. Includes a PortSelector that auto-detects free ports when defaults are occupied, plus a generated .env.example documenting manual overrides. PR 2539 by ihabadham.

  • CSP nonce support for RSC streaming and console replay scripts: Added cspNonce to rails_context and threaded nonce values through Pro RSC streaming paths (server-side HTML stream injection and client-side console replay script insertion), with nonce sanitization. PR 2418 by justin808.

  • Pro and RSC generator flags: Added --pro and --rsc flags to rails g react_on_rails:install, plus standalone react_on_rails:pro and react_on_rails:rsc generators for upgrading existing apps to Pro and React Server Components. Includes idempotent setup modules, webpack config transforms, prerequisite validation, and example components. PR 2284 by ihabadham.

  • Auto-registration for Redux stores: Added stores_subdirectory configuration option (e.g., "ror_stores") for automatic Redux store registration, following the same pattern as component auto-registration via ror_components. Store files placed in ror_stores/ directories are automatically discovered, and packs are generated that call ReactOnRails.registerStore(), eliminating manual registration boilerplate. Includes auto_load_bundle parameter for the redux_store helper. PR 2346 by justin808.

  • create-react-on-rails-app CLI tool: New npx create-react-on-rails-app command for single-command project setup. Phase 1 supports JavaScript and TypeScript templates with npm/pnpm, orchestrating rails new + bundle add react_on_rails + rails generate react_on_rails:install with prerequisite validation and progress output. PR 2375 by justin808.

  • Extensible bin/dev precompile pattern: New alternative approach for handling precompile tasks directly in bin/dev, providing better support for projects with custom build steps (ReScript, TypeScript), direct Ruby API access via ReactOnRails::Locales.compile, and improved version manager compatibility. PR 2349 by justin808.

  • Database setup check in bin/dev: The bin/dev command now checks database connectivity before starting the development server. This provides clear error messages when the database is missing or unavailable, instead of buried errors in the logs. Note: This adds ~1-2 seconds to startup time as it spawns a Rails runner process.

    Opt-out options (for apps without databases or when faster startup is needed):

    • CLI flag: bin/dev --skip-database-check
    • Environment variable: SKIP_DATABASE_CHECK=true bin/dev
    • Configuration: config.check_database_on_dev_start = false in config/initializers/react_on_rails.rb

    PR 2340 by justin808.

Improved

  • Smarter duplicate registration warnings: Component and store registration now only warns when a different component or store is registered under an already-used name. Re-registering the same component (common with HMR) is silently accepted. PR 2354 by justin808.

Fixed

  • CSS module SSR fixes for rspack: Fixed CSS module class name divergence between client and server bundles when using rspack. Server webpack config now filters rspack's cssExtractLoader in addition to mini-css-extract-plugin, uses spread syntax to preserve existing CSS module options when setting exportOnlyLocals: true, and adds null guards against undefined entries in rule.use arrays. Note: exportOnlyLocals: true is no longer applied when cssLoader.options.modules is falsy (disabled), which is the correct behavior but a change from prior versions. PR 2489 by justin808.
  • Fixed private_output_path not configured on fresh Shakapacker installs: When running rails g react_on_rails:install without pre-existing Shakapacker configuration, private_output_path: ssr-generated was left commented out in the generated config/shakapacker.yml. The generator now detects whether Shakapacker was just installed and passes a shakapacker_just_installed flag to BaseGenerator, which uses force: true when copying the config template to ensure the RoR version replaces Shakapacker's default. PR 2411 by ihabadham.
  • Install generator --pretend now behaves as a safe dry run: react_on_rails:install previously executed real Shakapacker setup commands (bundle add, bundle install, and rails shakapacker:install) and could crash on File.chmod because Thor pretend mode does not create files. --pretend now skips automatic Shakapacker installation and raw chmod calls so dry-run previews complete without side effects. PR 2536 by justin808.
  • bin/dev hook script path resolution without Rails.root: Fixed resolve_hook_script_path failing in early startup (before Rails is initialized) by adding a project_root helper that resolves the project root via BUNDLE_GEMFILE dirname or Dir.pwd when Rails.root is unavailable. PR 2568 by ihabadham. Fixes Issue 2438.
  • Rspack generator config path: Fixed --rspack generator placing config files under config/webpack/ instead of config/rspack/, causing Shakapacker deprecation warnings. All config file destinations are now dynamically remapped based on the active bundler, and using_rspack? auto-detects rspack projects for standalone generators (react_on_rails:rsc, react_on_rails:pro). PR 2417 by justin808.
  • Precompile hook load-based execution path: Fixed the precompile hook not executing its tasks when invoked via load (as used by bin/dev) instead of direct script execution. Added a shared run_precompile_tasks entry point that works regardless of invocation method. PR 2419 by justin808. Fixes Issue 2195.
  • create-react-on-rails-app validation improvements: Tightened CLI validation to enforce Rails 7+ and app-name leading-letter requirements, with clearer error messages for invalid names containing hyphens or underscores. PR 2577 by justin808.
  • Install @babel/preset-react for non-SWC generator installs: The generator now installs @babel/preset-react as a dev dependency when the project uses Babel (not SWC) as the transpiler, fixing JSX compilation errors on fresh installs with older Shakapacker defaults. PR 2421 by justin808.
  • Fix react_on_rails:doctor false positives for Pro/SWC setups: Doctor now recognizes react-on-rails-pro npm package for presence and version sync checks, skips @babel/preset-react check when SWC is the transpiler, and fixes a nil-safety bug where missing "dependencies" in package.json silently dropped devDependencies from checks. PR 2581 by ihabadham.
  • Fixed ScoutApm instrumentation depending on Gemfile ordering. ScoutApm instrumentation for react_component, react_component_hash, and exec_server_render_js was previously installed at gem load time using defined?(ScoutApm) guards, which meant it was silently skipped if scout_apm appeared after react_on_rails in the Gemfile, and produced noisy INFO log messages if it appeared before (since ScoutApm wasn't yet initialized). Moved instrumentation into an initializer that runs after scout_apm.start, ensuring it works regardless of gem ordering and only after ScoutApm is fully configured. PR 2442 by tonyta.
  • RSC WebpackLoader with SWC transpiler: Fixed RSC WebpackLoader never being injected when using SWC (Shakapacker's default transpiler). The RSC config only handled array-based rule.use (Babel) but SWC uses a function-based rule.use, so 'use client' files passed through untransformed into the RSC bundle. Now handles both array and function loader declarations. PR 2476 by AbanoubGhadban.
  • RSC Generator Layout Wiring: Fixed MissingEntryError on fresh RSC installs where HelloServerController fell back to Rails' application.html.erb (which uses javascript_pack_tag "application" that is not created by the RSC flow). The generator now always copies hello_world.html.erb, HelloServerController explicitly uses layout "hello_world", and post-install output now shows stream_react_component for RSC installs. PR 2429 by justin808.
  • Fixed string values interpolated into generated JS code without proper escaping. All string values (component names, DOM IDs, Redux store names) embedded in server-rendering JavaScript now use .to_json instead of unescaped single-quoted interpolation, preventing potential JS breakage from special characters. PR 2440 by AbanoubGhadban.
  • Precompile Hook Detection: Fixed shakapacker_precompile_hook_configured? always returning false for apps created with the React on Rails generator. The detection logic only matched the rake task pattern (react_on_rails:generate_packs) but the generator template uses the Ruby method (generate_packs_if_stale). Now correctly detects both patterns, including resolving script file contents. PR 2282 by ihabadham.
  • Precompile Hook Self-Guard for HMR: Added self-guard to the generator template's bin/shakapacker-precompile-hook to prevent duplicate execution in HMR mode where two webpack processes (client dev-server + server watcher) each trigger the hook. The script now exits early when SHAKAPACKER_SKIP_PRECOMPILE_HOOK=true is set by bin/dev, regardless of Shakapacker version. The version warning is now smarter: it only warns for hooks that lack the self-guard or use direct commands. Existing users: add exit 0 if ENV["SHAKAPACKER_SKIP_PRECOMPILE_HOOK"] == "true" near the top of your bin/shakapacker-precompile-hook script. PR 2388 by justin808.
  • Fix generator inheriting BUNDLE_GEMFILE from parent process: The react_on_rails:install generator now wraps bundler commands with Bundler.with_unbundled_env to prevent inheriting BUNDLE_GEMFILE from the parent process, which caused "injected gems" conflicts when running generators inside a bundled context. PR 2288 by ihabadham.

Pro

Added
  • CSP nonce for immediate hydration scripts: The immediate hydration inline <script> tags now include the CSP nonce attribute, fixing browsers blocking them when strict Content Security Policy is enabled. PR 2398 by AbanoubGhadban.
  • License verification rake task: New react_on_rails_pro:verify_license rake task for checking license status with human-readable text and JSON output (FORMAT=json) for CI/CD integration. Includes exit codes, automatic renewal warnings for licenses expiring within 30 days, and a GitHub Actions workflow example. PR 2385 by justin808.
Changed
  • Breaking: removed legacy key-file license fallback: config/react_on_rails_pro_license.key is no longer read. Move your token to the REACT_ON_RAILS_PRO_LICENSE environment variable. A migration warning is logged at startup when the legacy file is detected and the environment variable is missing. PR 2454 by ihabadham.
Improved
  • Better error messages when component is missing 'use client' with RSC. When RSC support is enabled, components without 'use client' silently crash at runtime with confusing errors. Improved error messages at multiple layers: runtime server and client bundles now include the component name and suggest adding 'use client', build-time heuristic scans for client-only patterns and emits warnings, and generated server component pack files explain the classification. PR 2403 by AbanoubGhadban.
Fixed
  • Fix streaming deadlock, exception masking, and cache poisoning on client disconnect: Fixed async streaming bugs where client disconnect could cause deadlocks, mask producer exceptions, or cache partial results. PR 2562 by AbanoubGhadban.
  • Fix StreamResponse status fallback for non-streaming errors: Fixed StreamRequest#process_response_chunks not detecting error responses when status delegation raises NoMethodError, which masked the original HTTPX error path. PR 2416 by justin808.
  • Fix empty-string license plan mismatch between Ruby and Node: Aligned Node checkPlan with Ruby check_plan so plan: "" is treated as invalid in both runtimes. Previously, an empty-string plan passed validation in Node but failed in Ruby. PR 2566 by AbanoubGhadban.
  • Handle HTTPX error responses when fetching dev-server bundle/assets for upload: During development startup races, get_form_body_for_file could receive HTTPX::ErrorResponse and still call response.body, causing an unexpected crash path. The request layer now raises ReactOnRailsPro::Error with HTTPX error details before body access and includes regression tests for local path, HTTP success, and HTTP error cases. PR 2532 by justin808.
  • Fix streaming SSR hangs and silent error absorption in RSC payload injection: Fixed two related issues: (1) streaming SSR renders hanging forever when errors occur because Node.js stream.pipe() doesn't propagate errors or closure from source to destination, and (2) errors in the RSC payload injection pipeline being silently absorbed, preventing them from reaching error reporters like Sentry. Introduced a shared safePipe utility and used 'close' events as reliable termination signals across the streaming pipeline (Node renderer, RSC payload injection, transform streams, and Ruby async task). Also added a Ruby safety net to prevent Rails request hangs when async rendering tasks raise before the first chunk. PR 2407 by AbanoubGhadban.
  • Node renderer duplicate error reports for render failures: Fixed duplicate errorReporter.message notifications when unexpected exceptions occurred in handleRenderRequest. The handler now returns an error ResponseResult instead of rethrowing, so the same failure is not reported again by worker.ts while still returning a 400 response. PR 2531 by justin808.
  • Fix RSC payload JSON corruption from Rails view annotations in development: RSC payload responses were rendered through an HTML template, so when annotate_rendered_view_with_filenames was enabled, Rails wrapped NDJSON chunks with HTML comments and broke client-side JSON.parse. The payload endpoint now renders the template in text format and serves application/x-ndjson, and a request spec covers the annotated-view scenario. If you override custom_rsc_payload_template, ensure it resolves to a text or format-neutral template (for example, .text.erb) rather than .html.erb. When RSC support is enabled, startup now also warns if Rack::Deflater is present, because response-transforming middleware can interfere with ActionController::Live NDJSON streaming. PR 2535 by justin808.
  • Fixed buildVM promise cleanup ordering in the node renderer. buildVM() cleanup now runs via promise chaining after vmCreationPromises.set(), preventing failed synchronous VM builds from leaving stale rejected promises that block retries for the same bundle path. PR 2484 by justin808.
  • Boot failure when only react_on_rails_pro is listed in the Gemfile. react_on_rails_pro.rb never explicitly required react_on_rails, relying on Bundler.require to auto-load it via the user's Gemfile. When installation docs were updated to direct users to only add react_on_rails_pro, two errors surfaced on boot: NoMethodError: undefined method 'strip_heredoc' (from license_public_key.rb) and NoMethodError: undefined method 'configure' for module ReactOnRails (from config/initializers/react_on_rails.rb). Fixed by explicitly requiring react_on_rails in react_on_rails_pro.rb, completing the same design the JS package split already established for npm. PR 2492 by ihabadham.
  • Sentry SDK v9/v10 compatibility: The node renderer Sentry integration now supports @sentry/node v9 and v10. Replaced @sentry/types import (no longer a transitive dependency in v9+) and widened peer dependency range from <9.0.0 to <11.0.0. PR 2434 by alexeyr-ci2.
  • Fixed node renderer upload race condition causing ENOENT errors and asset corruption during concurrent requests. Concurrent multipart uploads (e.g., during pod rollovers) all wrote to a single shared path (uploads/<filename>), causing file overwrites, ENOENT errors, and cross-contamination between requests. Each request now gets its own isolated upload directory (uploads/<uuid>/), eliminating all shared-path collisions. PR 2456 by AbanoubGhadban.
  • Fixed node renderer race condition between /upload-assets and render requests writing to the same bundle directory. The /upload-assets endpoint used a global lock while render requests used per-bundle locks, so both could write to the same bundle directory concurrently, risking asset corruption. Now both endpoints share the same per-bundle lock key. Also switched parallel bundle processing from Promise.all to Promise.allSettled to prevent the onResponse cleanup hook from deleting uploaded files while in-flight copies are still reading from them. PR 2464 by AbanoubGhadban.
  • Fixed TS2769 build error in node renderer onFile callback. Removed explicit this: FastifyRequest annotation that was incompatible with @fastify/multipart type definitions, fixing pnpm build and pnpm install failures on fresh runners. PR 2469 by AbanoubGhadban.
  • Fixed RSC rendering corruption when props contain $-patterns. Props containing $` (dollar-backtick), $', or $& — common in markdown with bash variables — caused String.prototype.replace() to interpret these as special replacement patterns, corrupting the generated JavaScript and hanging the RSC payload stream. Fixed by using a function replacement callback which disables all $-pattern interpretation. PR 2440 by AbanoubGhadban.
  • Fixed RSC stream tee backpressure deadlock for large payloads. Replaced pipe()-based stream teeing with manual on('data') + push() forwarding to prevent deadlocks when RSC payloads exceed the 32KB default highWaterMark buffer, which caused the stream to hang indefinitely. PR 2444 by AbanoubGhadban.

Don't miss a new react_on_rails release

NewReleases is sending notifications on new releases.