Fix #2606: reduce doctor false positives for custom layouts#2612
Fix #2606: reduce doctor false positives for custom layouts#2612
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR introduces dynamic path resolution for package.json and webpack configuration files within the ReactOnRails diagnostic system. New resolver methods are added to both Doctor and SystemChecker classes to discover configurations in non-root JS workspaces and custom Shakapacker directories, replacing hardcoded path references with resolved paths throughout existing checks. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment |
Greptile SummaryThis PR fixes false positives in
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Doctor / SystemChecker needs package.json] --> B{node_modules_location configured?}
B -->|empty / Rails.root| C[Use root package.json]
B -->|custom path e.g. 'client'| D["Use client/package.json"]
E[Doctor / SystemChecker needs webpack config] --> F[Build candidate list]
F --> G["1. config/webpack/webpack.config.js"]
F --> H["2. Shakapacker config directory paths"]
F --> I["3. Dir.glob config/**/webpack.config.*"]
G --> J{First candidate that exists?}
H --> J
I --> J
J -->|Found| K[Return discovered path]
J -->|None found| L["Return nil → warning instead of error"]
|
|
Review The direction here is solid — resolving package.json via node_modules_location and broadening webpack config discovery are good fixes for the reported false positives. Code duplication between doctor.rb and system_checker.rb resolved_package_json_path, resolved_webpack_config_path / webpack_config_candidates, and shakapacker_webpack_config_directory are implemented nearly identically in both files, but with a subtle inconsistency in candidate ordering (see inline comment). These helpers should live in a shared module (e.g. ReactOnRails::DiagnosticHelpers) so future changes do not silently diverge. parse_package_json rescues only JSON::ParserError File.read raises Errno::ENOENT when the file is absent — not JSON::ParserError. The method is safe today because check_react_dependencies guards with File.exist? beforehand, but parse_package_json is not independently safe to call. Consider adding Errno::ENOENT to the rescue clause or adding a guard inside the method itself. Minor nits
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Inconsistent webpack config search order between files
- I moved both classes to a shared resolver that prioritizes Shakapacker-configured webpack config candidates before glob matches, so they now resolve the same file.
- ✅ Fixed: Duplicated helper methods across doctor and system checker
- I extracted the duplicated path-resolution helpers into a single
ConfigPathResolvermodule and included it in both classes to keep logic unified.
- I extracted the duplicated path-resolution helpers into a single
Or push these changes by commenting:
@cursor push 2b3b6e1e5a
Preview (2b3b6e1e5a)
diff --git a/react_on_rails/lib/react_on_rails/config_path_resolver.rb b/react_on_rails/lib/react_on_rails/config_path_resolver.rb
new file mode 100644
--- /dev/null
+++ b/react_on_rails/lib/react_on_rails/config_path_resolver.rb
@@ -1,0 +1,43 @@
+# frozen_string_literal: true
+
+module ReactOnRails
+ module ConfigPathResolver
+ private
+
+ def resolved_package_json_path
+ node_modules_location = ReactOnRails.configuration.node_modules_location.to_s
+ return "package.json" if node_modules_location.empty? || node_modules_location == Rails.root.to_s
+
+ File.join(node_modules_location, "package.json")
+ rescue StandardError
+ "package.json"
+ end
+
+ def resolved_webpack_config_path
+ webpack_config_candidates.find { |path| File.exist?(path) }
+ end
+
+ def webpack_config_candidates
+ candidates = ["config/webpack/webpack.config.js"]
+
+ shakapacker_config_dir = shakapacker_webpack_config_directory
+ if shakapacker_config_dir
+ candidates.concat(%w[js ts cjs mjs].map { |ext| File.join(shakapacker_config_dir, "webpack.config.#{ext}") })
+ end
+
+ candidates.concat(Dir.glob("config/**/webpack.config.{js,ts,cjs,mjs}"))
+ candidates.uniq
+ end
+
+ def shakapacker_webpack_config_directory
+ require "shakapacker"
+ path = Shakapacker.config.assets_bundler_config_path.to_s
+ return nil if path.empty?
+
+ rails_root = Rails.root.to_s
+ path.start_with?("#{rails_root}/") ? path.sub("#{rails_root}/", "") : path
+ rescue LoadError, StandardError
+ nil
+ end
+ end
+end
diff --git a/react_on_rails/lib/react_on_rails/doctor.rb b/react_on_rails/lib/react_on_rails/doctor.rb
--- a/react_on_rails/lib/react_on_rails/doctor.rb
+++ b/react_on_rails/lib/react_on_rails/doctor.rb
@@ -5,6 +5,7 @@
require "yaml"
require_relative "utils"
require_relative "version_syntax_converter"
+require_relative "config_path_resolver"
require_relative "system_checker"
begin
@@ -39,6 +40,8 @@
module ReactOnRails
# rubocop:disable Metrics/ClassLength, Metrics/AbcSize
class Doctor
+ include ConfigPathResolver
+
MESSAGE_COLORS = {
error: :red,
warning: :yellow,
@@ -1178,37 +1181,6 @@
"app/javascript/packs/#{bundle_filename}"
end
- def resolved_package_json_path
- node_modules_location = ReactOnRails.configuration.node_modules_location.to_s
- return "package.json" if node_modules_location.empty? || node_modules_location == Rails.root.to_s
-
- File.join(node_modules_location, "package.json")
- rescue StandardError
- "package.json"
- end
-
- def resolved_webpack_config_path
- candidates = ["config/webpack/webpack.config.js"]
- candidates.concat(Dir.glob("config/**/webpack.config.{js,ts,cjs,mjs}"))
- shakapacker_dir = shakapacker_webpack_config_directory
- if shakapacker_dir
- candidates.concat(%w[js ts cjs mjs].map { |ext| File.join(shakapacker_dir, "webpack.config.#{ext}") })
- end
-
- candidates.uniq.find { |path| File.exist?(path) }
- end
-
- def shakapacker_webpack_config_directory
- require "shakapacker"
- path = Shakapacker.config.assets_bundler_config_path.to_s
- return nil if path.empty?
-
- rails_root = Rails.root.to_s
- path.start_with?("#{rails_root}/") ? path.sub("#{rails_root}/", "") : path
- rescue LoadError, StandardError
- nil
- end
-
def server_bundle_filename
# Try to read from React on Rails initializer
initializer_path = "config/initializers/react_on_rails.rb"
diff --git a/react_on_rails/lib/react_on_rails/system_checker.rb b/react_on_rails/lib/react_on_rails/system_checker.rb
--- a/react_on_rails/lib/react_on_rails/system_checker.rb
+++ b/react_on_rails/lib/react_on_rails/system_checker.rb
@@ -3,12 +3,15 @@
require "erb"
require "open3"
require "yaml"
+require_relative "config_path_resolver"
module ReactOnRails
# SystemChecker provides validation methods for React on Rails setup
# Used by install generator and doctor rake task
# rubocop:disable Metrics/ClassLength
class SystemChecker
+ include ConfigPathResolver
+
attr_reader :messages
def initialize
@@ -709,41 +712,6 @@
end
end
- def resolved_package_json_path
- node_modules_location = ReactOnRails.configuration.node_modules_location.to_s
- return "package.json" if node_modules_location.empty? || node_modules_location == Rails.root.to_s
-
- File.join(node_modules_location, "package.json")
- rescue StandardError
- "package.json"
- end
-
- def resolved_webpack_config_path
- webpack_config_candidates.find { |path| File.exist?(path) }
- end
-
- def webpack_config_candidates
- candidates = ["config/webpack/webpack.config.js"]
-
- shakapacker_config_dir = shakapacker_webpack_config_directory
- if shakapacker_config_dir
- candidates.concat(%w[js ts cjs mjs].map { |ext| File.join(shakapacker_config_dir, "webpack.config.#{ext}") })
- end
-
- candidates.concat(Dir.glob("config/**/webpack.config.{js,ts,cjs,mjs}"))
- candidates.uniq
- end
-
- def shakapacker_webpack_config_directory
- require "shakapacker"
- path = Shakapacker.config.assets_bundler_config_path.to_s
- return nil if path.empty?
-
- rails_root = Rails.root.to_s
- path.start_with?("#{rails_root}/") ? path.sub("#{rails_root}/", "") : path
- rescue LoadError, StandardError
- nil
- end
end
# rubocop:enable Metrics/ClassLength
end
diff --git a/react_on_rails/spec/lib/react_on_rails/doctor_spec.rb b/react_on_rails/spec/lib/react_on_rails/doctor_spec.rb
--- a/react_on_rails/spec/lib/react_on_rails/doctor_spec.rb
+++ b/react_on_rails/spec/lib/react_on_rails/doctor_spec.rb
@@ -191,6 +191,23 @@
end
end
+ describe "webpack config path resolution" do
+ it "prefers shakapacker-configured paths over glob-discovered paths" do
+ allow(doctor).to receive(:shakapacker_webpack_config_directory).and_return("config/custom")
+ allow(Dir).to receive(:glob).with("config/**/webpack.config.{js,ts,cjs,mjs}")
+ .and_return(["config/old/webpack.config.js"])
+
+ allow(File).to receive(:exist?).with("config/webpack/webpack.config.js").and_return(false)
+ allow(File).to receive(:exist?).with("config/custom/webpack.config.js").and_return(false)
+ allow(File).to receive(:exist?).with("config/custom/webpack.config.ts").and_return(true)
+ allow(File).to receive(:exist?).with("config/custom/webpack.config.cjs").and_return(false)
+ allow(File).to receive(:exist?).with("config/custom/webpack.config.mjs").and_return(false)
+ allow(File).to receive(:exist?).with("config/old/webpack.config.js").and_return(true)
+
+ expect(doctor.send(:resolved_webpack_config_path)).to eq("config/custom/webpack.config.ts")
+ end
+ end
+
describe "#check_async_usage" do
let(:checker) { instance_double(ReactOnRails::SystemChecker) }
diff --git a/react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb b/react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
--- a/react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
+++ b/react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
@@ -706,6 +706,23 @@
expect(checker.send(:shakapacker_configured?)).to be true
end
end
+
+ describe "#resolved_webpack_config_path" do
+ it "prefers shakapacker-configured paths over glob-discovered paths" do
+ allow(checker).to receive(:shakapacker_webpack_config_directory).and_return("config/custom")
+ allow(Dir).to receive(:glob).with("config/**/webpack.config.{js,ts,cjs,mjs}")
+ .and_return(["config/old/webpack.config.js"])
+
+ allow(File).to receive(:exist?).with("config/webpack/webpack.config.js").and_return(false)
+ allow(File).to receive(:exist?).with("config/custom/webpack.config.js").and_return(false)
+ allow(File).to receive(:exist?).with("config/custom/webpack.config.ts").and_return(true)
+ allow(File).to receive(:exist?).with("config/custom/webpack.config.cjs").and_return(false)
+ allow(File).to receive(:exist?).with("config/custom/webpack.config.mjs").and_return(false)
+ allow(File).to receive(:exist?).with("config/old/webpack.config.js").and_return(true)
+
+ expect(checker.send(:resolved_webpack_config_path)).to eq("config/custom/webpack.config.ts")
+ end
+ end
end
describe "version reporting" doThere was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
react_on_rails/lib/react_on_rails/system_checker.rb (2)
430-435:⚠️ Potential issue | 🟡 MinorKeep the failed-configuration copy aligned with custom webpack paths.
This predicate now accepts any resolved webpack config, but
check_shakapacker_configurationstill enumeratesconfig/webpack/webpack.config.jsas a required file. Apps with a valid custom config will still get sent to the default path whenever one of the other prerequisites is missing.🤖 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 430 - 435, The failing-configuration message in check_shakapacker_configuration is still hard-coded to list "config/webpack/webpack.config.js" even though shakapacker_configured? accepts any resolved webpack config via resolved_webpack_config_path; update check_shakapacker_configuration to reference resolved_webpack_config_path (or include it in the enumerated required files) so the error/copy shows the actual resolved webpack config path when present, and fall back to the default path only when resolved_webpack_config_path is nil. Ensure you update any messages that list required files to use resolved_webpack_config_path and keep checks using shakapacker_configured? consistent.
311-355:⚠️ Potential issue | 🟡 MinorHandle both CommonJS and TypeScript/ESM Shakapacker configs in debug hints.
The
suggest_webpack_inspectionmethod instructs users to adddebugger;beforemodule.exports, but sinceresolved_webpack_config_pathcan now resolve.ts/.mjsfiles, Shakapacker v9 stock configs usingimport/export defaultwill receive incorrect guidance. Stock Shakapacker v9 configs usegenerateWebpackConfigwithmodule.exports = generateWebpackConfig(...)in CommonJS orexport default configin TypeScript; both are legitimate. Updatestandard_shakapacker_config?and the debug hints to recognize both patterns and suggest the appropriate syntax for each format.🤖 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 311 - 355, The debug hints in suggest_webpack_inspection assume a CommonJS file (tell users to add "debugger;" before module.exports) but resolved_webpack_config_path may point to .ts/.mjs ESM files; update suggest_webpack_inspection to detect file format (use resolved_webpack_config_path extension and/or content) and emit format-appropriate guidance (e.g., "add 'debugger;' before module.exports" for CommonJS and "add 'debugger;' before export default / before generateWebpackConfig(...)" or the TS/ESM equivalent for .ts/.mjs), and update standard_shakapacker_config? to recognize both CommonJS patterns (module.exports = generateWebpackConfig(...)) and ESM/TS patterns (export default ... or export default generateWebpackConfig(...)) so the hint chooses the correct instruction; use the existing method names suggest_webpack_inspection, resolved_webpack_config_path, and standard_shakapacker_config? to locate where to change behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@react_on_rails/lib/react_on_rails/doctor.rb`:
- Around line 1190-1198: The resolver in resolved_webpack_config_path currently
checks generic candidates before Shakapacker, which can return a stale config;
update the method to prefer the Shakapacker-resolved paths (and any explicit
assets_bundler_config_path) before falling back to Dir.glob results so Doctor
and ReactOnRails::SystemChecker agree: compute shakapacker candidates from
shakapacker_webpack_config_directory and prepend them (and prepend
assets_bundler_config_path if set) to the candidates array before calling
candidates.uniq.find { |path| File.exist?(path) }.
---
Outside diff comments:
In `@react_on_rails/lib/react_on_rails/system_checker.rb`:
- Around line 430-435: The failing-configuration message in
check_shakapacker_configuration is still hard-coded to list
"config/webpack/webpack.config.js" even though shakapacker_configured? accepts
any resolved webpack config via resolved_webpack_config_path; update
check_shakapacker_configuration to reference resolved_webpack_config_path (or
include it in the enumerated required files) so the error/copy shows the actual
resolved webpack config path when present, and fall back to the default path
only when resolved_webpack_config_path is nil. Ensure you update any messages
that list required files to use resolved_webpack_config_path and keep checks
using shakapacker_configured? consistent.
- Around line 311-355: The debug hints in suggest_webpack_inspection assume a
CommonJS file (tell users to add "debugger;" before module.exports) but
resolved_webpack_config_path may point to .ts/.mjs ESM files; update
suggest_webpack_inspection to detect file format (use
resolved_webpack_config_path extension and/or content) and emit
format-appropriate guidance (e.g., "add 'debugger;' before module.exports" for
CommonJS and "add 'debugger;' before export default / before
generateWebpackConfig(...)" or the TS/ESM equivalent for .ts/.mjs), and update
standard_shakapacker_config? to recognize both CommonJS patterns (module.exports
= generateWebpackConfig(...)) and ESM/TS patterns (export default ... or export
default generateWebpackConfig(...)) so the hint chooses the correct instruction;
use the existing method names suggest_webpack_inspection,
resolved_webpack_config_path, and standard_shakapacker_config? to locate where
to change behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4d2df55f-c157-4de3-b28b-78f7e703a7ac
📒 Files selected for processing (4)
react_on_rails/lib/react_on_rails/doctor.rbreact_on_rails/lib/react_on_rails/system_checker.rbreact_on_rails/spec/lib/react_on_rails/doctor_spec.rbreact_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
ReviewThe approach here is solid. Resolving package.json from node_modules_location and broadening webpack config discovery are the right fixes for the false-positive problem. One blocking bug and a few smaller issues to address before merging. Bug: shakapacker_webpack_config_directory returns a file path, not a directory Shakapacker.config.assets_bundler_config_path returns the path to the webpack config FILE (e.g. /app/config/webpack/webpack.config.js). After stripping the Rails root the method still returns config/webpack/webpack.config.js — a file path. It is then used as a directory in File.join(shakapacker_config_dir, webpack.config.EXT), yielding bogus paths like config/webpack/webpack.config.js/webpack.config.ts that will never exist. The Shakapacker-specific candidates are therefore silently dead; only the Dir.glob fallback actually finds configs. This masks the bug but means the Shakapacker path logic provides zero benefit. Fix: add File.dirname before stripping the Rails root (see inline comment for a code suggestion). The same fix is needed in both system_checker.rb and doctor.rb. Code duplication resolved_package_json_path, resolved_webpack_config_path, webpack_config_candidates, and shakapacker_webpack_config_directory are now copy-pasted between SystemChecker and Doctor. This is a maintenance hazard. Extracting these into a shared module (e.g. ReactOnRails::ConfigPathResolver) would be cleaner, but at minimum they must stay in sync. Minor issues
|
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
react_on_rails/lib/react_on_rails/doctor.rb (1)
1190-1199:⚠️ Potential issue | 🟠 MajorPrefer Shakapacker-resolved webpack candidates before default fallback.
On Line 1191, default
config/webpack/webpack.config.jsis checked before Shakapacker-derived paths. If both exist, doctor can report the wrong config and reintroduce false positives for custom layouts.🔧 Suggested fix
def resolved_webpack_config_path - candidates = ["config/webpack/webpack.config.js"] shakapacker_dir = shakapacker_webpack_config_directory + candidates = [] if shakapacker_dir candidates.concat(%w[js ts cjs mjs].map { |ext| File.join(shakapacker_dir, "webpack.config.#{ext}") }) end + candidates << "config/webpack/webpack.config.js" candidates.concat(Dir.glob("config/**/webpack.config.{js,ts,cjs,mjs}")) candidates.uniq.find { |path| File.exist?(path) } end🤖 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/doctor.rb` around lines 1190 - 1199, The method resolved_webpack_config_path currently checks the default "config/webpack/webpack.config.js" before Shakapacker-derived paths, which can cause the wrong config to be selected; update resolved_webpack_config_path to prefer Shakapacker candidates first by building the candidate list with shakapacker_webpack_config_directory-derived entries placed before the default path (and still include Dir.glob results), then call uniq.find { |path| File.exist?(path) } so Shakapacker-resolved webpack.config.* files are selected prior to the fallback default.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@react_on_rails/lib/react_on_rails/system_checker.rb`:
- Around line 723-733: The method webpack_config_candidates currently places the
hardcoded "config/webpack/webpack.config.js" before Shakapacker-derived paths,
causing the default to be chosen when both exist; update
webpack_config_candidates so that if shakapacker_webpack_config_directory
returns a value you first add the Shakapacker candidates
(File.join(shakapacker_config_dir, "webpack.config.<ext>") for js,ts,cjs,mjs)
and only then append the hardcoded default "config/webpack/webpack.config.js"
and the Dir.glob("config/**/webpack.config.{js,ts,cjs,mjs}") results, finally
returning candidates.uniq — this ensures shakapacker_webpack_config_directory
takes precedence over the default fallback.
---
Duplicate comments:
In `@react_on_rails/lib/react_on_rails/doctor.rb`:
- Around line 1190-1199: The method resolved_webpack_config_path currently
checks the default "config/webpack/webpack.config.js" before Shakapacker-derived
paths, which can cause the wrong config to be selected; update
resolved_webpack_config_path to prefer Shakapacker candidates first by building
the candidate list with shakapacker_webpack_config_directory-derived entries
placed before the default path (and still include Dir.glob results), then call
uniq.find { |path| File.exist?(path) } so Shakapacker-resolved webpack.config.*
files are selected prior to the fallback default.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d7663e15-c0df-4e28-b746-7dbbdee250b9
📒 Files selected for processing (2)
react_on_rails/lib/react_on_rails/doctor.rbreact_on_rails/lib/react_on_rails/system_checker.rb
There was a problem hiding this comment.
🧹 Nitpick comments (1)
react_on_rails/lib/react_on_rails/doctor.rb (1)
1181-1210: Consider consolidating resolver helpers shared withSystemChecker.These resolver methods now exist in both classes with near-identical logic. Centralizing them in one shared helper/module would reduce drift risk and keep Doctor/SystemChecker behavior aligned over time.
🤖 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/doctor.rb` around lines 1181 - 1210, The resolver methods resolved_package_json_path, resolved_webpack_config_path and shakapacker_webpack_config_directory are duplicated between Doctor and SystemChecker; extract them into a single shared module (e.g., ReactOnRails::ResolverHelpers or PathResolvers) and remove the duplicates in both classes, then include or extend that module from Doctor and SystemChecker so both use the same implementations; ensure the module contains the same logic (including the LoadError/StandardError rescue) and update any internal references to call the module methods instead of the local copies.
🤖 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/doctor.rb`:
- Around line 1181-1210: The resolver methods resolved_package_json_path,
resolved_webpack_config_path and shakapacker_webpack_config_directory are
duplicated between Doctor and SystemChecker; extract them into a single shared
module (e.g., ReactOnRails::ResolverHelpers or PathResolvers) and remove the
duplicates in both classes, then include or extend that module from Doctor and
SystemChecker so both use the same implementations; ensure the module contains
the same logic (including the LoadError/StandardError rescue) and update any
internal references to call the module methods instead of the local copies.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: fe95b184-c8ef-4e37-ab36-192e91bca1a1
📒 Files selected for processing (6)
docs/README.mddocs/oss/migrating/rsc-troubleshooting.mdreact_on_rails/lib/react_on_rails/doctor.rbreact_on_rails/lib/react_on_rails/system_checker.rbreact_on_rails/spec/lib/react_on_rails/doctor_spec.rbreact_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
✅ Files skipped from review due to trivial changes (1)
- docs/oss/migrating/rsc-troubleshooting.md
Review SummaryThe core logic — resolving Must Fix
Should FixCode duplication across Inconsistency between the two Nits
Positive notes
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
react_on_rails/lib/react_on_rails/system_checker.rb (1)
301-308: Consider listing searched locations in the warning message.The warning mentions only
config/webpack/webpack.config.js, butwebpack_config_candidatesnow searches Shakapacker-derived paths and glob patterns. Listing the searched locations would help users understand whether their custom path was checked.💡 Optional: More informative warning message
else add_warning(<<~MSG.strip) ⚠️ Webpack configuration not found at common paths. - Expected default: config/webpack/webpack.config.js + Searched locations: + #{webpack_config_candidates.take(5).map { |p| "• #{p}" }.join("\n")} If your app uses a custom webpack config location, this may be informational. Run: rails generate react_on_rails:install MSG end🤖 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 301 - 308, The warning added in the add_warning call only names the default path but not the actual locations checked; update the message emitted by the method that calls add_warning (the code around add_warning in system_checker.rb) to include the list returned by webpack_config_candidates (or otherwise reference webpack_config_candidates and any Shakapacker-derived/glob candidate arrays) so users see exactly which paths/globs were searched; construct the warning string to append a joined, human-readable list of webpack_config_candidates results before calling add_warning.
🤖 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 301-308: The warning added in the add_warning call only names the
default path but not the actual locations checked; update the message emitted by
the method that calls add_warning (the code around add_warning in
system_checker.rb) to include the list returned by webpack_config_candidates (or
otherwise reference webpack_config_candidates and any Shakapacker-derived/glob
candidate arrays) so users see exactly which paths/globs were searched;
construct the warning string to append a joined, human-readable list of
webpack_config_candidates results before calling add_warning.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6c9d85c7-8728-4f73-b258-28596496a915
📒 Files selected for processing (2)
docs/oss/migrating/rsc-troubleshooting.mdreact_on_rails/lib/react_on_rails/system_checker.rb
✅ Files skipped from review due to trivial changes (1)
- docs/oss/migrating/rsc-troubleshooting.md
Review SummaryThe direction here is correct - resolving package.json via node_modules_location and broadening webpack config discovery are clear improvements over hard-coding config/webpack/webpack.config.js. A few issues worth addressing before merge: Code duplication across two files (structural) resolved_package_json_path, resolved_webpack_config_path / webpack_config_candidates, and shakapacker_webpack_config_directory are copy-pasted verbatim into both system_checker.rb and doctor.rb. Any bug fix or enhancement has to be applied twice. These should live in a shared module (e.g. ReactOnRails::WebpackPathHelpers) included in both classes, or a small utility object both can delegate to. (See inline comments on system_checker.rb lines 710-744.) resolved_package_json_path: relative path assumption When node_modules_location is a relative string like client, the method returns client/package.json - a path relative to the process CWD. This works as long as the CWD is Rails.root, which is conventional but not guaranteed. The node_modules_location == Rails.root.to_s guard also misses variants like a trailing slash or a symlink-resolved path, which would slip through and produce a doubly-joined path. Normalising via Pathname to an absolute path makes the contract explicit. (Inline suggestion on line 712.) Dir.glob in candidate list produces non-deterministic ordering Dir.glob already returns only existing paths, so the subsequent File.exist? call is redundant for those entries. More subtly, glob result ordering is filesystem-dependent; .find will return whichever file the OS lists first if multiple matches exist. For a diagnostic tool this is low risk, but a comment explaining the intended fallback semantics would help. Minor
|
| candidates.concat(%w[js ts cjs mjs].map { |ext| File.join(shakapacker_config_dir, "webpack.config.#{ext}") }) | ||
| end | ||
|
|
||
| candidates << "config/webpack/webpack.config.js" |
There was a problem hiding this comment.
Default fallback only covers .js
The Shakapacker-derived candidates cover js, ts, cjs, and mjs, but the hardcoded fallback only covers .js. Projects that aren't using Shakapacker but store their webpack config at the default location with a non-.js extension (e.g. config/webpack/webpack.config.ts) won't be found.
| candidates << "config/webpack/webpack.config.js" | |
| candidates.concat(%w[js ts cjs mjs].map { |ext| "config/webpack/webpack.config.#{ext}" }) |
| if webpack_config_path | ||
| checker.add_success("✅ Webpack configuration: #{webpack_config_path}") | ||
| else | ||
| checker.add_warning("⚠️ Missing Webpack configuration: config/webpack/webpack.config.js") |
There was a problem hiding this comment.
Misleading warning: hardcodes the default path even when others were tried
When resolved_webpack_config_path returns nil, several candidates (including Shakapacker-derived paths) were already searched. Showing only config/webpack/webpack.config.js in the warning makes it look like only one location was checked and doesn't help the developer understand what was actually searched.
Consider listing all checked candidates or keeping the message generic:
| checker.add_warning("⚠️ Missing Webpack configuration: config/webpack/webpack.config.js") | |
| checker.add_warning("⚠️ No Webpack configuration file found in common locations") |
| msg[:type] == :success && msg[:content].include?("react-on-rails-pro NPM package") | ||
| end).to be true | ||
| end | ||
| end |
There was a problem hiding this comment.
Existing tests may silently break after the refactor
The existing tests for check_react_on_rails_npm_package, check_package_version_sync, etc. (outside this PR's added blocks) still stub File.exist? with the relative "package.json". Those stubs only fire correctly if resolved_package_json_path still returns "package.json", which depends on ReactOnRails.configuration.node_modules_location.to_s == Rails.root.to_s at test time.
Since Rails.root is not stubbed in those tests, this is environment-dependent and fragile. Those tests should explicitly stub node_modules_location (or Rails.root + node_modules_location) to remain robust as the new resolver path is now in the call chain.
Review: Fix #2606 - reduce doctor false positives for custom layoutsOverall the direction is right -- resolving paths from Bug: mixed relative/absolute paths from The default branch returns the bare string Code duplication with
Default webpack-config fallback only covers Shakapacker-derived candidates cover js/ts/cjs/mjs, but the hardcoded fallback Warning message is misleading When no webpack config is found, the warning still names only Pre-existing tests may silently break Tests outside the new workspace blocks stub |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Config resolver ignores rspack configs causing false positives
- Updated config candidate resolution to include rspack filenames and fallback paths (with specs), so rspack configs are correctly detected instead of reported missing.
Or push these changes by commenting:
@cursor push f9dc52a097
Preview (f9dc52a097)
diff --git a/react_on_rails/lib/react_on_rails/config_path_resolver.rb b/react_on_rails/lib/react_on_rails/config_path_resolver.rb
--- a/react_on_rails/lib/react_on_rails/config_path_resolver.rb
+++ b/react_on_rails/lib/react_on_rails/config_path_resolver.rb
@@ -20,10 +20,18 @@
shakapacker_config_dir = shakapacker_webpack_config_directory
if shakapacker_config_dir
- candidates.concat(%w[js ts cjs mjs].map { |ext| File.join(shakapacker_config_dir, "webpack.config.#{ext}") })
+ candidates.concat(%w[js ts cjs mjs].flat_map do |ext|
+ [
+ File.join(shakapacker_config_dir, "webpack.config.#{ext}"),
+ File.join(shakapacker_config_dir, "rspack.config.#{ext}")
+ ]
+ end)
end
candidates << "config/webpack/webpack.config.js"
+ candidates << "config/webpack/webpack.config.ts"
+ candidates << "config/rspack/rspack.config.js"
+ candidates << "config/rspack/rspack.config.ts"
candidates.uniq
end
diff --git a/react_on_rails/spec/lib/react_on_rails/doctor_spec.rb b/react_on_rails/spec/lib/react_on_rails/doctor_spec.rb
--- a/react_on_rails/spec/lib/react_on_rails/doctor_spec.rb
+++ b/react_on_rails/spec/lib/react_on_rails/doctor_spec.rb
@@ -1302,6 +1302,22 @@
expect(doctor.send(:resolved_webpack_config_path)).to eq("config/custom/webpack.config.ts")
end
+
+ it "resolves rspack config candidates from the shakapacker-derived directory" do
+ allow(File).to receive(:exist?).and_return(false)
+ allow(File).to receive(:exist?).with("config/rspack/rspack.config.ts").and_return(true)
+ allow(doctor).to receive(:shakapacker_webpack_config_directory).and_return("config/rspack")
+
+ expect(doctor.send(:resolved_webpack_config_path)).to eq("config/rspack/rspack.config.ts")
+ end
+
+ it "falls back to default rspack config paths when shakapacker directory is unavailable" do
+ allow(File).to receive(:exist?).and_return(false)
+ allow(File).to receive(:exist?).with("config/rspack/rspack.config.js").and_return(true)
+ allow(doctor).to receive(:shakapacker_webpack_config_directory).and_return(nil)
+
+ expect(doctor.send(:resolved_webpack_config_path)).to eq("config/rspack/rspack.config.js")
+ end
end
describe "#shakapacker_webpack_config_directory" do|
Codex Review: Didn't find any major issues. You're on a roll. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Applied via @cursor push command
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Webpack config discovery inconsistency causes contradictory doctor output
- Updated SystemChecker to use the same resolved_webpack_config_path lookup as Doctor key-file checks so custom webpack config locations no longer trigger a contradictory hard error.
Or push these changes by commenting:
@cursor push 4a92e0e876
Preview (4a92e0e876)
diff --git a/react_on_rails/lib/react_on_rails/system_checker.rb b/react_on_rails/lib/react_on_rails/system_checker.rb
--- a/react_on_rails/lib/react_on_rails/system_checker.rb
+++ b/react_on_rails/lib/react_on_rails/system_checker.rb
@@ -295,7 +295,7 @@
# Webpack configuration validation
def check_webpack_configuration
- config_path = detect_bundler_config_path
+ config_path = resolved_webpack_config_path
if config_path
add_success("✅ Bundler configuration exists (#{config_path})")
check_webpack_config_content(config_path)
diff --git a/react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb b/react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
--- a/react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
+++ b/react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb
@@ -559,6 +559,38 @@
end
end
+ describe "#check_webpack_configuration" do
+ context "when webpack config is resolved from a custom shakapacker location" do
+ before do
+ allow(checker).to receive(:resolved_webpack_config_path).and_return("config/custom/webpack.config.ts")
+ allow(checker).to receive(:check_webpack_config_content)
+ allow(checker).to receive(:suggest_webpack_inspection)
+ end
+
+ it "reports success instead of an error" do
+ checker.check_webpack_configuration
+
+ expect(checker.messages.any? do |msg|
+ msg[:type] == :success && msg[:content].include?("config/custom/webpack.config.ts")
+ end).to be true
+ expect(checker.errors?).to be false
+ end
+ end
+
+ context "when no webpack config can be resolved" do
+ before do
+ allow(checker).to receive(:resolved_webpack_config_path).and_return(nil)
+ end
+
+ it "reports an error" do
+ checker.check_webpack_configuration
+
+ expect(checker.errors?).to be true
+ expect(checker.messages.last[:content]).to include("Bundler configuration not found")
+ end
+ end
+ end
+
describe "#check_react_dependencies" do
let(:base_package_json) do
{| # React dependencies validation | ||
| def check_react_dependencies | ||
| return unless File.exist?("package.json") | ||
| return unless File.exist?(resolved_package_json_path) |
There was a problem hiding this comment.
Webpack config discovery inconsistency causes contradictory doctor output
High Severity
Doctor#check_key_configuration_files now uses the new broad resolved_webpack_config_path (which checks Shakapacker-configured and custom locations), but SystemChecker#check_webpack_configuration — called by the Doctor in a separate section — still uses the narrow detect_bundler_config_path which only checks hardcoded paths. For apps with custom webpack config locations, the Doctor will show ✅ in "Key Configuration Files" and 🚫 ERROR in "Webpack Configuration", and exit(1). The PR description states this method was to be downgraded from hard error to contextual warning, but that change was not applied.
Additional Locations (1)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8da3444502
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| candidates.concat(%w[js ts cjs mjs].flat_map do |ext| | ||
| [ | ||
| File.join(shakapacker_config_dir, "webpack.config.#{ext}"), | ||
| File.join(shakapacker_config_dir, "rspack.config.#{ext}") | ||
| ] |
There was a problem hiding this comment.
Check configured bundler config path before guessing names
resolved_webpack_config_path now derives candidates from the configured directory but never checks Shakapacker.config.assets_bundler_config_path itself, so a missing configured file can be masked by any leftover webpack.config.*/rspack.config.* file in the same folder. In that case Doctor#check_key_configuration_files reports a success even though Shakapacker is pointed at a broken path, which hides a real configuration error.
Useful? React with 👍 / 👎.
- resolve `package.json` from `ReactOnRails.configuration.node_modules_location` (instead of assuming repo root) - broaden webpack config discovery to common custom locations/extensions and Shakapacker-configured paths - downgrade missing webpack config in `SystemChecker#check_webpack_configuration` from hard error to contextual warning - add regression specs for non-root JS workspace and custom webpack config discovery Fixes false positives reported in `react_on_rails:doctor` for apps that keep JS dependencies in a subdirectory (for example `client/package.json`) and/or use non-default webpack config locations. - `bundle exec rspec react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb react_on_rails/spec/lib/react_on_rails/doctor_spec.rb` - `bundle exec rubocop react_on_rails/lib/react_on_rails/system_checker.rb react_on_rails/lib/react_on_rails/doctor.rb react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb react_on_rails/spec/lib/react_on_rails/doctor_spec.rb` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk because changes are limited to diagnostic path detection and messaging; no runtime application behavior or data/security logic is modified. > > **Overview** > Reduces `react_on_rails:doctor` false positives in non-standard project layouts by introducing `ConfigPathResolver`, which resolves `package.json` via `ReactOnRails.configuration.node_modules_location` and discovers webpack/rspack config files across common extensions and Shakapacker-configured locations. > > Updates `Doctor` and `SystemChecker` to use these resolved paths, and changes the Doctor key-file check to report missing bundler config as a *contextual warning* (instead of assuming `config/webpack/webpack.config.js`). Adds specs covering workspace `package.json` resolution and bundler config discovery behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8da3444. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> * **New Features** * Enhanced configuration detection for webpack and package.json files across flexible project layouts, including custom workspace locations * Improved diagnostic messages when configuration files are missing or misconfigured * **Bug Fixes** * Robust error handling for missing configuration paths * **Documentation** * Code formatting improvements in troubleshooting guide * **Tests** * Added test coverage for dynamic configuration path resolution <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <[email protected]> Co-authored-by: Cursor Agent <[email protected]>
- resolve `package.json` from `ReactOnRails.configuration.node_modules_location` (instead of assuming repo root) - broaden webpack config discovery to common custom locations/extensions and Shakapacker-configured paths - downgrade missing webpack config in `SystemChecker#check_webpack_configuration` from hard error to contextual warning - add regression specs for non-root JS workspace and custom webpack config discovery Fixes false positives reported in `react_on_rails:doctor` for apps that keep JS dependencies in a subdirectory (for example `client/package.json`) and/or use non-default webpack config locations. - `bundle exec rspec react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb react_on_rails/spec/lib/react_on_rails/doctor_spec.rb` - `bundle exec rubocop react_on_rails/lib/react_on_rails/system_checker.rb react_on_rails/lib/react_on_rails/doctor.rb react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb react_on_rails/spec/lib/react_on_rails/doctor_spec.rb` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk because changes are limited to diagnostic path detection and messaging; no runtime application behavior or data/security logic is modified. > > **Overview** > Reduces `react_on_rails:doctor` false positives in non-standard project layouts by introducing `ConfigPathResolver`, which resolves `package.json` via `ReactOnRails.configuration.node_modules_location` and discovers webpack/rspack config files across common extensions and Shakapacker-configured locations. > > Updates `Doctor` and `SystemChecker` to use these resolved paths, and changes the Doctor key-file check to report missing bundler config as a *contextual warning* (instead of assuming `config/webpack/webpack.config.js`). Adds specs covering workspace `package.json` resolution and bundler config discovery behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 8da3444. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> * **New Features** * Enhanced configuration detection for webpack and package.json files across flexible project layouts, including custom workspace locations * Improved diagnostic messages when configuration files are missing or misconfigured * **Bug Fixes** * Robust error handling for missing configuration paths * **Documentation** * Code formatting improvements in troubleshooting guide * **Tests** * Added test coverage for dynamic configuration path resolution <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <[email protected]> Co-authored-by: Cursor Agent <[email protected]>



Summary
package.jsonfromReactOnRails.configuration.node_modules_location(instead of assuming repo root)SystemChecker#check_webpack_configurationfrom hard error to contextual warningWhy
Fixes false positives reported in
react_on_rails:doctorfor apps that keep JS dependencies in a subdirectory (for exampleclient/package.json) and/or use non-default webpack config locations.Testing
bundle exec rspec react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb react_on_rails/spec/lib/react_on_rails/doctor_spec.rbbundle exec rubocop react_on_rails/lib/react_on_rails/system_checker.rb react_on_rails/lib/react_on_rails/doctor.rb react_on_rails/spec/lib/react_on_rails/system_checker_spec.rb react_on_rails/spec/lib/react_on_rails/doctor_spec.rbNote
Low Risk
Low risk because changes are limited to diagnostic path detection and messaging; no runtime application behavior or data/security logic is modified.
Overview
Reduces
react_on_rails:doctorfalse positives in non-standard project layouts by introducingConfigPathResolver, which resolvespackage.jsonviaReactOnRails.configuration.node_modules_locationand discovers webpack/rspack config files across common extensions and Shakapacker-configured locations.Updates
DoctorandSystemCheckerto use these resolved paths, and changes the Doctor key-file check to report missing bundler config as a contextual warning (instead of assumingconfig/webpack/webpack.config.js). Adds specs covering workspacepackage.jsonresolution and bundler config discovery behavior.Written by Cursor Bugbot for commit 8da3444. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests