Changes since the last non-beta release.
Added
-
TanStack Router SSR integration (Pro): Added
createTanStackRouterRenderFunctionandserverRenderTanStackAppAsyncviareact-on-rails-pro/tanstack-routerfor TanStack Router SSR with the Pro Node Renderer. Uses TanStack Router's publicrouter.load()API for reliable async SSR. Requiresrendering_returns_promises = truein Pro config. PR 2516 by justin808. -
create-react-on-rails-app --rscflow: Added--rscsupport tonpx create-react-on-rails-appso a single command can scaffold an RSC-ready app. The CLI now installsreact_on_rails_pro, passes--rsctoreact_on_rails:install, and points users to/hello_serverafter 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 runbin/devconcurrently without port conflicts. Includes aPortSelectorthat auto-detects free ports when defaults are occupied, plus a generated.env.exampledocumenting manual overrides. PR 2539 by ihabadham. -
CSP nonce support for RSC streaming and console replay scripts: Added
cspNoncetorails_contextand 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
--proand--rscflags torails g react_on_rails:install, plus standalonereact_on_rails:proandreact_on_rails:rscgenerators 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_subdirectoryconfiguration option (e.g.,"ror_stores") for automatic Redux store registration, following the same pattern as component auto-registration viaror_components. Store files placed inror_stores/directories are automatically discovered, and packs are generated that callReactOnRails.registerStore(), eliminating manual registration boilerplate. Includesauto_load_bundleparameter for theredux_storehelper. PR 2346 by justin808. -
create-react-on-rails-app CLI tool: New
npx create-react-on-rails-appcommand for single-command project setup. Phase 1 supports JavaScript and TypeScript templates with npm/pnpm, orchestratingrails new+bundle add react_on_rails+rails generate react_on_rails:installwith 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 viaReactOnRails::Locales.compile, and improved version manager compatibility. PR 2349 by justin808. -
Database setup check in bin/dev: The
bin/devcommand 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 = falseinconfig/initializers/react_on_rails.rb
- CLI flag:
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
cssExtractLoaderin addition tomini-css-extract-plugin, uses spread syntax to preserve existing CSS module options when settingexportOnlyLocals: true, and adds null guards against undefined entries inrule.usearrays. Note:exportOnlyLocals: trueis no longer applied whencssLoader.options.modulesis falsy (disabled), which is the correct behavior but a change from prior versions. PR 2489 by justin808. - Fixed
private_output_pathnot configured on fresh Shakapacker installs: When runningrails g react_on_rails:installwithout pre-existing Shakapacker configuration,private_output_path: ssr-generatedwas left commented out in the generatedconfig/shakapacker.yml. The generator now detects whether Shakapacker was just installed and passes ashakapacker_just_installedflag toBaseGenerator, which usesforce: truewhen copying the config template to ensure the RoR version replaces Shakapacker's default. PR 2411 by ihabadham. - Install generator
--pretendnow behaves as a safe dry run:react_on_rails:installpreviously executed real Shakapacker setup commands (bundle add,bundle install, andrails shakapacker:install) and could crash onFile.chmodbecause Thor pretend mode does not create files.--pretendnow skips automatic Shakapacker installation and raw chmod calls so dry-run previews complete without side effects. PR 2536 by justin808. bin/devhook script path resolution without Rails.root: Fixedresolve_hook_script_pathfailing in early startup (before Rails is initialized) by adding aproject_roothelper that resolves the project root viaBUNDLE_GEMFILEdirname orDir.pwdwhenRails.rootis unavailable. PR 2568 by ihabadham. Fixes Issue 2438.- Rspack generator config path: Fixed
--rspackgenerator placing config files underconfig/webpack/instead ofconfig/rspack/, causing Shakapacker deprecation warnings. All config file destinations are now dynamically remapped based on the active bundler, andusing_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 bybin/dev) instead of direct script execution. Added a sharedrun_precompile_tasksentry point that works regardless of invocation method. PR 2419 by justin808. Fixes Issue 2195. create-react-on-rails-appvalidation 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-reactfor non-SWC generator installs: The generator now installs@babel/preset-reactas 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:doctorfalse positives for Pro/SWC setups: Doctor now recognizesreact-on-rails-pronpm package for presence and version sync checks, skips@babel/preset-reactcheck 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, andexec_server_render_jswas previously installed at gem load time usingdefined?(ScoutApm)guards, which meant it was silently skipped ifscout_apmappeared afterreact_on_railsin 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 afterscout_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-basedrule.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
MissingEntryErroron fresh RSC installs whereHelloServerControllerfell back to Rails'application.html.erb(which usesjavascript_pack_tag "application"that is not created by the RSC flow). The generator now always copieshello_world.html.erb,HelloServerControllerexplicitly useslayout "hello_world", and post-install output now showsstream_react_componentfor 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_jsoninstead 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 returningfalsefor 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-hookto prevent duplicate execution in HMR mode where two webpack processes (client dev-server + server watcher) each trigger the hook. The script now exits early whenSHAKAPACKER_SKIP_PRECOMPILE_HOOK=trueis set bybin/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: addexit 0 if ENV["SHAKAPACKER_SKIP_PRECOMPILE_HOOK"] == "true"near the top of yourbin/shakapacker-precompile-hookscript. PR 2388 by justin808. - Fix generator inheriting BUNDLE_GEMFILE from parent process: The
react_on_rails:installgenerator now wraps bundler commands withBundler.with_unbundled_envto prevent inheritingBUNDLE_GEMFILEfrom 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_licenserake 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.keyis no longer read. Move your token to theREACT_ON_RAILS_PRO_LICENSEenvironment 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_chunksnot detecting error responses whenstatusdelegation raisesNoMethodError, which masked the original HTTPX error path. PR 2416 by justin808. - Fix empty-string license plan mismatch between Ruby and Node: Aligned Node
checkPlanwith Rubycheck_plansoplan: ""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_filecould receiveHTTPX::ErrorResponseand still callresponse.body, causing an unexpected crash path. The request layer now raisesReactOnRailsPro::Errorwith 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 sharedsafePipeutility 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.messagenotifications when unexpected exceptions occurred inhandleRenderRequest. The handler now returns an errorResponseResultinstead of rethrowing, so the same failure is not reported again byworker.tswhile 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_filenameswas enabled, Rails wrapped NDJSON chunks with HTML comments and broke client-sideJSON.parse. The payload endpoint now renders the template in text format and servesapplication/x-ndjson, and a request spec covers the annotated-view scenario. If you overridecustom_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 ifRack::Deflateris present, because response-transforming middleware can interfere withActionController::LiveNDJSON streaming. PR 2535 by justin808. - Fixed buildVM promise cleanup ordering in the node renderer.
buildVM()cleanup now runs via promise chaining aftervmCreationPromises.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_prois listed in the Gemfile.react_on_rails_pro.rbnever explicitly requiredreact_on_rails, relying onBundler.requireto auto-load it via the user's Gemfile. When installation docs were updated to direct users to only addreact_on_rails_pro, two errors surfaced on boot:NoMethodError: undefined method 'strip_heredoc'(fromlicense_public_key.rb) andNoMethodError: undefined method 'configure' for module ReactOnRails(fromconfig/initializers/react_on_rails.rb). Fixed by explicitly requiringreact_on_railsinreact_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/nodev9 and v10. Replaced@sentry/typesimport (no longer a transitive dependency in v9+) and widened peer dependency range from<9.0.0to<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,ENOENTerrors, 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-assetsand render requests writing to the same bundle directory. The/upload-assetsendpoint 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 fromPromise.alltoPromise.allSettledto prevent theonResponsecleanup 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
onFilecallback. Removed explicitthis: FastifyRequestannotation that was incompatible with@fastify/multiparttype definitions, fixingpnpm buildandpnpm installfailures 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 — causedString.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 manualon('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.