Skip to content

Fix doctor false positives and stabilize default RSC starter#2478

Open
justin808 wants to merge 1 commit intomasterfrom
codex/fix-rsc-doctor-and-sample-issues
Open

Fix doctor false positives and stabilize default RSC starter#2478
justin808 wants to merge 1 commit intomasterfrom
codex/fix-rsc-doctor-and-sample-issues

Conversation

@justin808
Copy link
Member

@justin808 justin808 commented Feb 23, 2026

Summary

Addresses two RSC follow-ups:

  1. Fixes rails react_on_rails:doctor false positives for Pro + SWC setups:

    • Treats react-on-rails-pro as a valid npm package for React on Rails checks.
    • Uses package-aware version sync messaging (react-on-rails or react-on-rails-pro).
    • Only requires @babel/preset-react when Shakapacker javascript_transpiler is babel (skips that warning for swc).
  2. Stabilizes generated --rsc starter output:

    • Keeps default HelloServer sample server-only (removes default LikeButton usage) to avoid fragile client-hook demo behavior in initial scaffold.
    • Adds install generator assertions to prevent reintroducing default client-component rendering in the starter.

Closes #2431
Closes #2432

Testing

  • mise exec ruby@3.3 -- bundle exec rspec react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
  • NPM_CONFIG_CACHE=/tmp/npm-cache-ror-2431-2432 mise exec ruby@3.3 -- bundle exec rspec react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb:785 react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb:873
  • mise exec ruby@3.3 -- bundle exec rubocop react_on_rails/lib/react_on_rails/system_checker.rb react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb

Note

Medium Risk
Touches the SystemChecker/doctor logic and adds YAML+ERB config parsing, which can affect setup diagnostics across environments; the RSC starter change is low impact but alters generated output expectations.

Overview
Improves rails react_on_rails:doctor checks to avoid false positives by recognizing react-on-rails-pro as a valid npm package, making gem/npm version-sync messages package-aware, and only requiring @babel/preset-react when Shakapacker is configured to use the babel transpiler (not swc, with shakapacker.yml parsed via ERB+YAML).

Stabilizes the --rsc scaffold by removing the default LikeButton usage from the generated HelloServer (JS + TS) and updating the demo view copy accordingly, plus adds generator specs to ensure the starter remains server-only by default.

Written by Cursor Bugbot for commit e1bf0b7. Configure here.

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced npm package detection to support both standard and pro versions of React on Rails
    • Improved JavaScript transpiler recognition with automatic Babel configuration detection
    • Expanded React dependency validation based on active transpiler configuration
  • Documentation

    • Clarified starter component scaffolding to emphasize server-only behavior by default

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

Walkthrough

This pull request removes the LikeButton client component from generated RSC templates to keep the scaffold server-only and clean, while enhancing the system checker to properly detect react-on-rails-pro packages, parse Shakapacker YAML configuration with ERB, identify the active JavaScript transpiler, and conditionally require Babel dependencies only when applicable.

Changes

Cohort / File(s) Summary
RSC/JS/TS Template Cleanup
react_on_rails/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.jsx, HelloServer.tsx
Removed LikeButton import and component usage; replaced commentary about client components with note that scaffold is server-only.
Template View Update
react_on_rails/lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb
Updated inline comment to reflect server-only scaffold design instead of referencing interactive LikeButton JS shipping.
System Checker Enhancements
react_on_rails/lib/react_on_rails/system_checker.rb
Added methods to parse Shakapacker YAML config with ERB rendering, detect react-on-rails-pro as alternative npm package, identify active JavaScript transpiler (Babel vs SWC), and conditionally require @babel/preset-react only for Babel setups.
System Checker Tests
react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
Added test coverage for react-on-rails-pro detection, version synchronization with pro package, and conditional dependency checks across SWC and Babel transpiler configurations.
Generator Tests
react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb
Added three tests verifying HelloServer components (JS, TS, and RSC variants) do not import or render LikeButton by default.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A rabbit hops through code so fine,
Says "goodbye" to buttons that intertwine,
Server-only now, so clean and pure,
Pro packages detected, warnings for sure,
Transpilers checked with careful delight! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main objectives: fixing doctor false positives and stabilizing the RSC starter by removing client components.
Linked Issues check ✅ Passed The PR fully addresses both linked issues: treats react-on-rails-pro as valid, requires @babel/preset-react only with babel transpiler, and makes HelloServer server-only with regression tests.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the stated objectives: system_checker enhancements for doctor fixes, HelloServer template updates for stability, and comprehensive test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-rsc-doctor-and-sample-issues

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link

greptile-apps bot commented Feb 23, 2026

Greptile Summary

This PR makes two targeted improvements:

  1. Doctor false positive fixes (system_checker.rb): Recognizes react-on-rails-pro as a valid NPM package, uses package-aware naming in all diagnostic messages, and conditionally requires @babel/preset-react only when Shakapacker's javascript_transpiler is set to babel (skipping for SWC setups). The shakapacker config is parsed with ERB + YAML support, matching Shakapacker's own config loading behavior.

  2. RSC starter stabilization (templates + tests): Removes the default LikeButton client-component import/usage from HelloServer JSX/TSX templates so the --rsc scaffold runs cleanly without fragile client-hook behavior. LikeButton files are still generated and available for users to wire up manually. Regression tests in the install generator spec prevent reintroduction.

  • Both changes include thorough test coverage for the new behavior paths.
  • The react_on_rails_npm_package_details helper centralizes package detection, giving Pro priority when both packages exist.
  • The pre-existing dependencies&.merge(devDependencies || {}) || {} pattern has a minor edge case when dependencies is nil — not a regression but worth a future cleanup pass.

Confidence Score: 4/5

  • This PR is safe to merge — it fixes legitimate false positives and stabilizes template output with good test coverage.
  • Score reflects well-structured, focused changes with comprehensive tests. The only minor concern is a pre-existing edge case in dependency merging (nil dependencies key) which is not a regression from this PR.
  • react_on_rails/lib/react_on_rails/system_checker.rb has a pre-existing nil-safety edge case in dependency merging worth a follow-up.

Important Files Changed

Filename Overview
react_on_rails/lib/react_on_rails/system_checker.rb Adds Pro package detection, transpiler-aware Babel check, and shakapacker config parsing. Clean implementation with proper fallbacks and error handling.
react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb Adds comprehensive test coverage for Pro package detection, version sync with Pro, and SWC/Babel transpiler-aware dependency checks.
react_on_rails/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.jsx Removes LikeButton import and usage to keep default RSC starter server-only. Clean removal with updated fact text.
react_on_rails/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.tsx TypeScript variant mirrors the JSX change — removes LikeButton import and usage for a server-only default scaffold.
react_on_rails/lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb Updates ERB comment to reflect the server-only nature of the starter example. No logic changes.
react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb Adds regression tests asserting HelloServer templates do not include LikeButton in both JSX and TSX variants.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[rails react_on_rails:doctor] --> B[check_react_on_rails_npm_package]
    B --> C{react_on_rails_npm_package_details}
    C -->|react-on-rails-pro found| D["✅ Pro package detected"]
    C -->|react-on-rails found| E["✅ OSS package detected"]
    C -->|neither found| F["⚠️ Warning with both options"]

    A --> G[check_react_dependencies]
    G --> H{required_react_dependencies}
    H --> I[using_babel_transpiler?]
    I --> J{detected_javascript_transpiler}
    J -->|shakapacker.yml exists| K[parsed_shakapacker_config]
    K --> L{javascript_transpiler value}
    L -->|babel / nil| M["Include @babel/preset-react check"]
    L -->|swc| N["Skip @babel/preset-react check"]
    J -->|no config file| M

    A --> O[check_package_version_sync]
    O --> C
Loading

Last reviewed commit: e1bf0b7

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

end

def react_on_rails_npm_package_details(package_json)
all_deps = package_json["dependencies"]&.merge(package_json["devDependencies"] || {}) || {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing: nil dependencies drops devDependencies

If package_json["dependencies"] is nil (e.g., a project that only has devDependencies), the safe-navigation &.merge(...) returns nil, and nil || {} yields an empty hash — silently dropping everything in devDependencies. A package listed only in devDependencies would not be found.

This is a pre-existing pattern used throughout the file (7 occurrences), so not a regression from this PR, but worth noting since this method is now the single source of truth for Pro/OSS detection. A safer alternative would be:

all_deps = (package_json["dependencies"] || {}).merge(package_json["devDependencies"] || {})

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is ON, but it could not run because Privacy Mode (Legacy) is turned on. To enable Bugbot Autofix, switch your privacy mode in the Cursor dashboard.

end

def react_on_rails_npm_package_details(package_json)
all_deps = package_json["dependencies"]&.merge(package_json["devDependencies"] || {}) || {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge pattern loses devDependencies when dependencies key absent

Medium Severity

The react_on_rails_npm_package_details method uses package_json["dependencies"]&.merge(package_json["devDependencies"] || {}) || {} to combine deps. When a package.json has no "dependencies" key at all (only "devDependencies"), the safe navigation operator returns nil, and nil || {} discards all devDependencies. This is a regression from the old code which used independent dig calls for each section, correctly finding packages in either location regardless of whether the other key existed.

Fix in Cursor Fix in Web

@claude
Copy link

claude bot commented Feb 23, 2026

Review: Fix doctor false positives and stabilize default RSC starter

Overall this is a solid, well-scoped fix. The logic is correct and the test coverage is good. A few things worth discussing:


rescue StandardError is too broad in parsed_shakapacker_config

This silently swallows any error — including ERB::SyntaxError if the user has a malformed ERB expression in their shakapacker.yml, or Psych::DisallowedClass if the YAML contains types that safe_load rejects. In those cases the method returns nil, using_babel_transpiler? falls back to true, and the developer gets a confusing @babel/preset-react warning with no explanation why. Rescuing Errno::ENOENT, Errno::EACCES, YAML::SyntaxError, Psych::SyntaxError, and ERB::SyntaxError explicitly would make failures much easier to diagnose.


Version sync check for react-on-rails-pro compares against ReactOnRails::VERSION

In check_package_version_sync, the npm version (now potentially the Pro package) is compared against ReactOnRails::VERSION. If the react-on-rails-pro npm package version is decoupled from the open-source gem's version number, this will always produce a false "version mismatch" warning for Pro users. Is the Pro npm package guaranteed to match ReactOnRails::VERSION? If not, the check should either skip the version comparison when the Pro package is detected, or compare against a Pro-specific constant.


LikeButton is still generated but no longer referenced

LikeButton.jsx and LikeButton.tsx are still scaffolded (the existing test at line 770/829/870 asserts their presence), but HelloServer no longer imports them. The result is an orphaned component in the generated app. Consider adding a brief comment in HelloServer pointing to LikeButton as a usage example, or a note in LikeButton itself explaining it can be imported into HelloServer to demonstrate RSC + client component interaction.


Missing test: shakapacker.yml present but no javascript_transpiler key

There is no test covering the case where config/shakapacker.yml exists but has no javascript_transpiler entry. The current code returns nil from detected_javascript_transpiler, causing using_babel_transpiler? to return true (fall back to requiring babel). This is the correct behavior but it is an untested code path and an important boundary condition.


Minor: devDependencies wins over dependencies on collision in react_on_rails_npm_package_details

Merging devDependencies into dependencies means devDependencies takes precedence when the same key appears in both. The original code checked dependencies first (and thus gave it higher priority). This edge case is unlikely to matter in practice, but the behavior reversal is worth noting or the merge order should be flipped to restore original precedence.

raw_content = File.read(shakapacker_config_path)
rendered_content = ERB.new(raw_content).result
YAML.safe_load(rendered_content, aliases: true) || {}
rescue StandardError
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The broad rescue StandardError here will silently swallow meaningful errors. If shakapacker.yml contains invalid ERB (e.g., <%= undefined_method %>), the ERB::SyntaxError is caught, nil is returned, and using_babel_transpiler? falls back to true — causing a spurious @babel/preset-react warning with no indication of why. Consider rescuing specific, expected exceptions instead:

Suggested change
rescue StandardError
rescue Errno::ENOENT, Errno::EACCES, Psych::SyntaxError, YAML::SyntaxError
nil
rescue ERB::SyntaxError, SyntaxError
# ERB evaluation failed — fall back to requiring babel but don't crash doctor
nil

Or at minimum log the error via warn so developers can diagnose the issue.

deps
end

def react_on_rails_npm_package_details(package_json)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge here gives devDependencies precedence over dependencies when the same package key exists in both. The original code checked dependencies first (higher precedence). To restore that behavior:

Suggested change
def react_on_rails_npm_package_details(package_json)
all_deps = (package_json["devDependencies"] || {}).merge(package_json["dependencies"] || {})

This is a minor edge case (unlikely anyone has the same package in both sections), but the intent should be explicit.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
react_on_rails/lib/react_on_rails/system_checker.rb (1)

488-497: Consider the safety of ERB.new(raw_content).result in edge cases.

ERB#result without an explicit binding uses the top-level binding. If shakapacker.yml contains ERB tags referencing Rails helpers (e.g., Rails.root), this will fail before Rails is fully loaded. The rescue StandardError covers it gracefully, but it silently swallows the error — a debug-level log could help users diagnose why the transpiler wasn't detected.

That said, for a diagnostic tool this is an acceptable trade-off.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/lib/react_on_rails/system_checker.rb` around lines 488 - 497,
In parsed_shakapacker_config, ERB.new(raw_content).result can raise errors when
shakapacker.yml references top-level bindings; update the rescue in
parsed_shakapacker_config to log the caught exception at debug level (e.g.,
process or Rails.logger.debug) including the error message and backtrace along
with a short context string like "failed to parse config/shakapacker.yml"; keep
returning nil after logging so behavior is unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@react_on_rails/lib/react_on_rails/system_checker.rb`:
- Around line 488-497: In parsed_shakapacker_config, ERB.new(raw_content).result
can raise errors when shakapacker.yml references top-level bindings; update the
rescue in parsed_shakapacker_config to log the caught exception at debug level
(e.g., process or Rails.logger.debug) including the error message and backtrace
along with a short context string like "failed to parse config/shakapacker.yml";
keep returning nil after logging so behavior is unchanged.

@justin808 justin808 added codex PRs created from codex-named branches release:16.4.0-must-have Must-have for 16.4.0: critical bug/perf/usability labels Feb 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex PRs created from codex-named branches release:16.4.0-must-have Must-have for 16.4.0: critical bug/perf/usability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Doctor emits false positives for Pro/RSC + SWC setups RSC generator sample can emit useState client-component errors in payload

1 participant