Skip to content

Conversation

@ihabadham
Copy link
Collaborator

@ihabadham ihabadham commented Jan 4, 2026

Summary

  • Fixes the shakapacker_precompile_hook_configured? method to properly detect hooks created by the generator template

Problem

The detection logic was looking for the react_on_rails:generate_packs rake task pattern, but the generator template (bin/shakapacker-precompile-hook) uses the generate_packs_if_stale Ruby method directly. This mismatch caused the detection to always return false for apps created with the generator.

Root Cause Analysis

Investigation revealed this was a historical divergence:

  • Oct 24: Original hook template created using generate_packs_if_stale Ruby method
  • Nov 5: Detection logic added looking for react_on_rails:generate_packs rake task
  • The tests only used mock data, so the mismatch was never caught

The Ruby method approach is actually more efficient (no shell overhead), so the template is correct. The detection logic needed to be updated to recognize both valid patterns.

Solution

Added a GENERATE_PACKS_PATTERN constant that matches both valid approaches:

  • The rake task: react_on_rails:generate_packs (used by test/dummy implementation)
  • The Ruby method: generate_packs_if_stale (used by generator template)

Test Plan

  • Created fresh Rails 8.0.4 app with Shakapacker 9.4.0
  • Ran rails generate react_on_rails:install
  • Verified shakapacker_precompile_hook_configured? returns true

Before fix:

shakapacker_precompile_hook_configured? returns: false

After fix:

shakapacker_precompile_hook_configured? returns: true

Fixes #2279

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Improved detection of pack-generation signals in precompile hooks, added safer resolution of referenced hook scripts, and made detection tolerant of errors—defaults to running pack generation when detection is uncertain.
  • Tests
    • Added comprehensive tests for precompile hook scenarios: direct commands, referenced script contents, missing scripts, and non-generation cases.

✏️ Tip: You can customize this high-level summary in your review settings.

The detection logic was looking for `react_on_rails:generate_packs` rake
task pattern, but the generator template uses `generate_packs_if_stale`
Ruby method directly. This mismatch caused the detection to always return
false for apps created with the generator.

Updated the regex pattern to match both valid approaches:
- The rake task: `react_on_rails:generate_packs`
- The Ruby method: `generate_packs_if_stale`

Fixes #2279

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 4, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Add a regex constant and helper methods to ReactOnRails::PackerUtils to detect Shakapacker precompile hooks that invoke pack generation (including generate_packs_if_stale), resolve script paths, and safely read hook values; update detection logic and add tests for direct commands, script contents, missing scripts, and Rails.root resolution.

Changes

Cohort / File(s) Summary
Packer utils
react_on_rails/lib/react_on_rails/packer_utils.rb, react_on_rails/sig/react_on_rails/packer_utils.rbs
Add GENERATE_PACKS_PATTERN constant; add resolve_hook_script_path and nullable shakapacker_precompile_hook_value helper; update hook_contains_generate_packs? to use the pattern, check script contents, swallow errors on detection failure, and adjust RBS for nullable return.
Specs
react_on_rails/spec/react_on_rails/packer_utils_spec.rb
Add tests for precompile hook detection: direct command containing generate_packs_if_stale, script-file cases (contains generator call, contains rake task, does not contain generate_packs), non-existent script file, and Rails.root resolution; add RuboCop pragmas around spec.

Sequence Diagram(s)

(omitted — changes are localized detection logic and tests, not multi-component control-flow requiring a sequence diagram)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #2279 — Fixes the regex-detection mismatch where generate_packs_if_stale wasn't recognized; this PR implements the pattern and resolution suggested.
  • #2090 — Similar objective: improve detection of Shakapacker precompile hooks invoking pack generation; changes align with that goal.

Possibly related PRs

Suggested reviewers

  • justin808
  • Judahmeek
  • AbanoubGhadban

Poem

🐰 I nibble code and trace the tracks,
Sniff out hooks and follow cracks.
generate_packs I now detect,
Scripts and paths I gladly check.
Builds hop smooth — that's that, in fact! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title accurately describes the main change: fixing precompile hook detection to align with generator template behavior.
Linked Issues check ✅ Passed PR fully addresses all coding requirements from issue #2279: pattern matches both detection methods, resolves script paths, handles errors gracefully, and updates type signatures.
Out of Scope Changes check ✅ Passed All changes directly support the primary objective of fixing precompile hook detection; no extraneous modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ihabadham/fix/issue-2279-hook-detection

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.

@claude
Copy link

claude bot commented Jan 4, 2026

Code Review - PR #2282

Summary

This PR fixes a critical bug where shakapacker_precompile_hook_configured? always returned false for apps created with the React on Rails generator. The issue was a pattern mismatch between the detection logic (looking for rake task) and the generator template (using Ruby method).


✅ Positives

1. Root Cause Analysis

Excellent investigation! The PR correctly identifies:

  • The historical divergence between template creation (Oct 24) and detection logic (Nov 5)
  • Why the tests didn't catch it (mock data only)
  • That the Ruby method approach is more efficient (no shell overhead)

2. Minimal, Focused Fix

The solution is elegantly simple:

  • Adds a well-documented constant GENERATE_PACKS_PATTERN
  • Updates only two call sites (direct command check + script contents check)
  • No over-engineering or unnecessary changes

3. Clear Documentation

The inline comment clearly explains both patterns:

# Matches both:
# - The rake task: react_on_rails:generate_packs
# - The Ruby method: generate_packs_if_stale (used by generator template)

4. Real-World Testing

The PR includes manual testing with a fresh Rails 8.0.4 app, which is exactly what CLAUDE.md requires:

"CRITICAL - LOCAL TESTING REQUIREMENTS: NEVER claim a test is 'fixed' without running it locally first"


⚠️ Issues & Recommendations

1. Missing Test Coverage ⚠️ CRITICAL

The test at packer_utils_spec.rb:151-156 only tests the rake task pattern:

it "returns true when hook command contains generate_packs rake task" do
  hook_value = "bundle exec rake react_on_rails:generate_packs"
  # ...
end

Required action: Add a test case for the generate_packs_if_stale pattern:

it "returns true when hook command contains generate_packs_if_stale method" do
  hook_value = "bin/shakapacker-precompile-hook"
  allow(described_class).to receive(:resolve_hook_script_path)
    .with(hook_value).and_return(Rails.root.join("bin/shakapacker-precompile-hook"))
  allow(File).to receive(:exist?).and_return(true)
  allow(File).to receive(:read).and_return(
    "ReactOnRails::PacksGenerator.instance.generate_packs_if_stale"
  )
  allow(mock_config).to receive(:send).with(:data)
    .and_return({ precompile_hook: hook_value })
  
  expect(described_class.shakapacker_precompile_hook_configured?).to be true
end

Why this matters: Without this test, we could regress to only detecting the rake task pattern again.

2. Regex Pattern Considerations ℹ️ MINOR

The current pattern: /(react_on_rails:generate_packs|generate_packs_if_stale)/

Potential false positives:

  • Would match comments: # Old code used generate_packs_if_stale
  • Would match in strings: puts "About to call generate_packs_if_stale"

Recommendation (optional): Consider adding word boundaries if you want stricter matching:

GENERATE_PACKS_PATTERN = /\b(react_on_rails:generate_packs|generate_packs_if_stale)\b/

However, for a precompile hook script, false positives are unlikely to be an issue since:

  • These are dedicated scripts with specific purposes
  • The current pattern is already being used for the rake task side
  • Over-strictness could cause false negatives

Verdict: Current implementation is acceptable, but documenting this trade-off would help future maintainers.

3. RBS Signature Compatibility ✅ OK

The RBS signature in sig/react_on_rails/packer_utils.rbs doesn't need updates since no method signatures changed. The constant is internal implementation detail.


🔍 Security & Performance

Security

No concerns. The code:

  • Uses File.read only on resolved script paths under Rails.root
  • Has proper error handling (rescue StandardError)
  • Returns safe default (false) on errors

Performance

No concerns. The regex is simple and only runs:

  • Once per precompile (not in hot path)
  • On small script files (typically <50 lines)

📋 Checklist

  • Code quality: Clean, well-commented, follows project conventions
  • Bug fix: Correctly addresses the reported issue precompile_hook detection always returns false due to regex mismatch #2279
  • Manual testing: Verified with fresh Rails 8.0.4 app
  • Breaking changes: None
  • Documentation: Clear inline comments
  • Test coverage: NEEDS test case for generate_packs_if_stale pattern ⚠️
  • Changelog: Should this be in CHANGELOG.md? (Per CLAUDE.md, user-visible bug fixes should be documented)

🎯 Final Recommendation

Approve with minor improvements requested:

  1. Before merge: Add test case for the generate_packs_if_stale pattern
  2. Consider: Adding entry to CHANGELOG.md (this is a user-visible bug fix)
  3. Optional: Add comment about false positive trade-offs in regex pattern

This is a high-quality fix that solves a real problem affecting all apps created with the generator. The only critical gap is test coverage for the new pattern.


Great work on the investigation and fix! The root cause analysis was particularly thorough. 🎉

@greptile-apps
Copy link

greptile-apps bot commented Jan 4, 2026

Greptile Summary

Fixed shakapacker_precompile_hook_configured? detection to recognize both valid hook patterns:

  • Rake task: react_on_rails:generate_packs (used in test/dummy)
  • Ruby method: generate_packs_if_stale (used by generator template at lib/generators/react_on_rails/templates/base/base/bin/shakapacker-precompile-hook:25)

The mismatch was causing false negatives for apps created with the generator, as the detection only looked for the rake task pattern while the generator template uses the more efficient Ruby method approach (no shell overhead).

Issue found: Regex lacks word boundaries, which could match unintended substrings.

Confidence Score: 4/5

  • Safe to merge with one regex boundary issue that should be fixed
  • The fix correctly addresses the root cause and properly detects both valid patterns. However, the regex lacks word boundaries which could cause false positives. Impact is low since the patterns are unlikely to appear as substrings, but should be fixed for robustness.
  • regex pattern in packer_utils.rb:208 needs word boundaries

Important Files Changed

Filename Overview
react_on_rails/lib/react_on_rails/packer_utils.rb Adds GENERATE_PACKS_PATTERN constant to detect both rake task and Ruby method patterns, fixing detection for generator-created hooks. One regex boundary issue found.

Sequence Diagram

sequenceDiagram
    participant App as Rails App
    participant RoR as ReactOnRails
    participant Utils as PackerUtils
    participant Hook as precompile_hook script
    participant Generator as PacksGenerator

    Note over App,Generator: Detection Flow

    App->>RoR: Check if hook configured
    RoR->>Utils: shakapacker_precompile_hook_configured?()
    Utils->>Utils: extract_precompile_hook()
    Utils-->>Utils: Returns "bin/shakapacker-precompile-hook"
    
    Utils->>Utils: hook_contains_generate_packs?(hook_value)
    Utils->>Utils: Check direct command with GENERATE_PACKS_PATTERN
    Note over Utils: Pattern: /(react_on_rails:generate_packs|generate_packs_if_stale)/
    Utils-->>Utils: No match (it's a script path)
    
    Utils->>Utils: resolve_hook_script_path(hook_value)
    Utils-->>Utils: Returns Rails.root/bin/shakapacker-precompile-hook
    
    Utils->>Hook: Read script contents
    Hook-->>Utils: Returns script with "generate_packs_if_stale"
    
    Utils->>Utils: Match against GENERATE_PACKS_PATTERN
    Note over Utils: ✅ Matches "generate_packs_if_stale"
    Utils-->>RoR: true (hook configured)
    RoR-->>App: Skip redundant generation
    
    Note over App,Generator: Hook Execution Flow
    
    App->>Hook: Execute precompile_hook
    Hook->>Generator: ReactOnRails::PacksGenerator.instance.generate_packs_if_stale
    Generator-->>Generator: Check if packs are stale
    Generator-->>Hook: Generate packs if needed
    Hook-->>App: Complete
Loading

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.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

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.

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/packer_utils.rb (2)

231-237: Mark helper method as private.

The resolve_hook_script_path method is an internal helper for hook_contains_generate_packs? and should not be part of the public API.

🔎 Proposed fix to mark method as private

Add a private declaration before the helper methods:

     end
 
+    private
+
     def self.resolve_hook_script_path(hook_value)
       # Hook value might be a script path relative to Rails root
       return nil unless defined?(Rails) && Rails.respond_to?(:root)

Note: This requires also moving shakapacker_precompile_hook_value after the private declaration if it should remain public, or before if you want it to be public.


239-247: Fix critical RBS type signature errors in sig/react_on_rails/packer_utils.rbs.

Two issues found in the RBS signatures:

  1. shakapacker_precompile_hook_value return type is incorrect: Currently declared as () -> String but the implementation returns nil when Shakapacker is not defined or on error (lines 242, 246). Should be () -> String?.

  2. resolve_hook_script_path is missing from RBS: This is a public method (lines 231-237) but has no type signature. Should add: def self.resolve_hook_script_path: (untyped hook_value) -> Pathname?

Update sig/react_on_rails/packer_utils.rbs:

  • Change line 10 from def self.shakapacker_precompile_hook_value: () -> String to def self.shakapacker_precompile_hook_value: () -> String?
  • Add missing signature: def self.resolve_hook_script_path: (untyped hook_value) -> Pathname?
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 619cb78 and a073e52.

📒 Files selected for processing (1)
  • react_on_rails/lib/react_on_rails/packer_utils.rb
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rb

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rb: Run bundle exec rubocop and fix ALL violations before every commit/push
Run bundle exec rubocop (MANDATORY) before every commit to ensure zero offenses

Files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /{CHANGELOG.md,CHANGELOG_PRO.md} : Use format `[PR 1818](https://github.com/shakacode/react_on_rails/pull/1818) by [username](https://github.com/username)` in changelog entries (no hash in PR number)
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to {package.json,webpack.config.js,packages/*/package.json,react_on_rails_pro/package.json} : When resolving merge conflicts in build configuration files, verify file paths are correct by running `grep -r 'old/path' .` and test affected scripts like `pnpm run prepack` before continuing the merge
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes in the open-source react_on_rails gem and npm package (features, bug fixes, breaking changes, deprecations, performance improvements)
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to sig/react_on_rails/**/*.rbs : RBS signatures in `sig/react_on_rails/` should be added for new Ruby files in `lib/react_on_rails/`, included in Steepfile, validated with `bundle exec rake rbs:validate`, and type-checked with `bundle exec rake rbs:steep`
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Shakapacker configuration should be tested by creating debug scripts in dummy app root (debug-webpack-rules.js, debug-webpack-with-config.js) to inspect webpack rules before committing configuration changes
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for user-visible changes in the Pro-only react_on_rails_pro gem and npm packages
Learnt from: justin808
Repo: shakacode/react_on_rails PR: 1770
File: lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx:2-2
Timestamp: 2025-09-16T08:01:11.146Z
Learning: React on Rails uses webpack CSS Modules configuration with namedExports: true, which requires the import syntax `import * as style from './file.module.css'` rather than the default export pattern. This configuration enables better tree shaking and bundle size optimization for CSS modules.
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.074Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. The `react_on_rails_pro?` method validates licenses and should raise errors early (including during path resolution in methods like `server_bundle?`) to enforce licensing requirements rather than failing later with obscure errors.
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Git pre-commit hooks automatically run RuboCop (auto-fix), ESLint (auto-fix), Prettier (auto-format), and trailing newline checks on all changed files before each commit
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for user-visible changes in the Pro-only react_on_rails_pro gem and npm packages

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes in the open-source react_on_rails gem and npm package (features, bug fixes, breaking changes, deprecations, performance improvements)

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to sig/react_on_rails/**/*.rbs : RBS signatures in `sig/react_on_rails/` should be added for new Ruby files in `lib/react_on_rails/`, included in Steepfile, validated with `bundle exec rake rbs:validate`, and type-checked with `bundle exec rake rbs:steep`

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Shakapacker configuration should be tested by creating debug scripts in dummy app root (debug-webpack-rules.js, debug-webpack-with-config.js) to inspect webpack rules before committing configuration changes

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
📚 Learning: 2025-09-16T08:01:11.146Z
Learnt from: justin808
Repo: shakacode/react_on_rails PR: 1770
File: lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx:2-2
Timestamp: 2025-09-16T08:01:11.146Z
Learning: React on Rails uses webpack CSS Modules configuration with namedExports: true, which requires the import syntax `import * as style from './file.module.css'` rather than the default export pattern. This configuration enables better tree shaking and bundle size optimization for CSS modules.

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
📚 Learning: 2025-07-08T05:57:29.630Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1745
File: node_package/src/RSCRequestTracker.ts:8-14
Timestamp: 2025-07-08T05:57:29.630Z
Learning: The global `generateRSCPayload` function in React on Rails Pro (RORP) is provided by the framework during rendering requests, not implemented in application code. The `declare global` statements are used to document the expected interface that RORP will inject at runtime.

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to {package.json,webpack.config.js,packages/*/package.json,react_on_rails_pro/package.json} : When resolving merge conflicts in build configuration files, verify file paths are correct by running `grep -r 'old/path' .` and test affected scripts like `pnpm run prepack` before continuing the merge

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
📚 Learning: 2025-04-26T21:55:55.874Z
Learnt from: alexeyr-ci2
Repo: shakacode/react_on_rails PR: 1732
File: spec/dummy/client/app-react16/startup/ReduxSharedStoreApp.client.jsx:40-44
Timestamp: 2025-04-26T21:55:55.874Z
Learning: In the react_on_rails project, files under `app-react16` directories are copied/moved to corresponding `/app` directories during the conversion process (removing the `-react16` suffix), which affects their relative import paths at runtime.

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
📚 Learning: 2025-02-12T16:38:06.537Z
Learnt from: Romex91
Repo: shakacode/react_on_rails PR: 1697
File: package-scripts.yml:28-28
Timestamp: 2025-02-12T16:38:06.537Z
Learning: The file `node_package/lib/ReactOnRails.full.js` is autogenerated during the build process and should not be present in the repository.

Applied to files:

  • react_on_rails/lib/react_on_rails/packer_utils.rb
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: dummy-app-integration-tests (3.4, 22, latest)
  • GitHub Check: rspec-package-tests (3.4, latest)
  • GitHub Check: build
  • GitHub Check: Greptile Review
  • GitHub Check: claude-review
🔇 Additional comments (2)
react_on_rails/lib/react_on_rails/packer_utils.rb (2)

217-217: LGTM!

The use of GENERATE_PACKS_PATTERN correctly detects both the rake task and Ruby method invocations in direct hook commands.


225-225: LGTM!

The pattern matching in script contents correctly detects both pack generation patterns, with appropriate error handling that fails safe.

Address review feedback:
- Add \b word boundaries to GENERATE_PACKS_PATTERN to prevent false
  positives on substrings like 'my_generate_packs_if_stale_helper'
- Add test for direct command containing generate_packs_if_stale
- Add tests for script file reading path (both patterns)
- Add test for script file not existing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@claude
Copy link

claude bot commented Jan 5, 2026

Code Review - Fix precompile hook detection to match generator template

✅ Overall Assessment

Excellent fix! This PR correctly addresses the mismatch between the detection logic and the generator template. The implementation is clean, well-tested, and follows best practices.


🎯 Strengths

  1. Root Cause Analysis: The PR description provides excellent historical context explaining how this divergence occurred (Oct 24 vs Nov 5). This is exactly the kind of analysis that helps prevent similar issues.

  2. Correct Solution: Using a regex pattern that matches both valid approaches is the right design:

    • Supports the efficient Ruby method approach (generate_packs_if_stale) from the generator template
    • Maintains backward compatibility with rake task approach used in test/dummy
    • Follows the principle of "detect what's actually being used" rather than forcing one pattern
  3. Comprehensive Test Coverage: The new tests in packer_utils_spec.rb cover all the important scenarios:

    • Direct command with generate_packs_if_stale method ✅
    • Script file with generate_packs_if_stale method ✅
    • Script file with react_on_rails:generate_packs rake task ✅
    • Script file without generate_packs (negative case) ✅
    • Non-existent script file (error case) ✅
  4. Code Quality:

    • Clear, descriptive constant name: GENERATE_PACKS_PATTERN
    • Good inline comments explaining what each pattern matches
    • Proper use of word boundaries (\b) in regex to avoid false matches
    • Consistent application of the pattern in both places it's needed
  5. Manual Verification: The PR author tested with a fresh Rails 8.0.4 app and verified the fix works as expected. This follows the CLAUDE.md requirement to test locally before pushing.


📋 Minor Suggestions (Optional)

  1. Consider Edge Cases: The regex uses alternation (A|B) which is fine, but if more patterns are added in the future, consider documenting why each pattern is valid. The current comments are good though.

  2. Potential Future Enhancement: If the project ever needs to support additional pack generation patterns, consider making this configurable rather than hardcoded. But for now, the two patterns are the only valid ones, so this is not a blocker.


🔍 Security & Performance

  • No security concerns: The regex is simple and doesn't introduce ReDoS vulnerabilities
  • No performance concerns: The pattern is compiled once as a constant and used for simple string matching
  • Error handling: Proper rescue block prevents failures if script can't be read

🧪 Test Coverage

The test coverage is excellent. The new tests cover:

  • Both valid patterns (Ruby method and rake task)
  • Both contexts (direct command and script file)
  • Error cases (missing file, wrong content)
  • Integration with Rails.root path resolution

The only thing missing is a test for the error rescue block (e.g., file read permission errors), but this is not critical since the error handling is defensive and returns false safely.


📝 Documentation

The PR description is exemplary:

This follows all the best practices from CLAUDE.md.


✅ Recommendation

APPROVE - This PR is ready to merge once CI passes.

The fix is:

  • ✅ Correct and complete
  • ✅ Well-tested with comprehensive specs
  • ✅ Backward compatible
  • ✅ Follows project conventions
  • ✅ Properly documented

Great work @ihabadham! This is a textbook example of how to fix a bug: identify the root cause, implement the minimal correct fix, test thoroughly, and document clearly. 🎉

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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
react_on_rails/spec/react_on_rails/packer_utils_spec.rb (1)

173-225: Excellent test coverage for script-file detection scenarios.

The new context block thoroughly covers:

  • Script containing generate_packs_if_stale method
  • Script containing rake task
  • Script without pack generation
  • Non-existent script file

The mocking structure is clean and appropriate.

💡 Optional: Consider adding test for file read errors

The implementation includes error handling (rescue block), so testing that File.read errors are swallowed and return false would verify the fail-safe behavior:

it "returns false when script file cannot be read" do
  allow(script_full_path).to receive(:file?).and_return(true)
  allow(File).to receive(:exist?).with(script_full_path).and_return(true)
  allow(File).to receive(:read).with(script_full_path).and_raise(Errno::EACCES, "Permission denied")

  expect(described_class.shakapacker_precompile_hook_configured?).to be false
end
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a073e52 and d45f17f.

📒 Files selected for processing (2)
  • react_on_rails/lib/react_on_rails/packer_utils.rb
  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
🚧 Files skipped from review as they are similar to previous changes (1)
  • react_on_rails/lib/react_on_rails/packer_utils.rb
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rb

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rb: Run bundle exec rubocop and fix ALL violations before every commit/push
Run bundle exec rubocop (MANDATORY) before every commit to ensure zero offenses

Files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /{CHANGELOG.md,CHANGELOG_PRO.md} : Use format `[PR 1818](https://github.com/shakacode/react_on_rails/pull/1818) by [username](https://github.com/username)` in changelog entries (no hash in PR number)
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to {package.json,webpack.config.js,packages/*/package.json,react_on_rails_pro/package.json} : When resolving merge conflicts in build configuration files, verify file paths are correct by running `grep -r 'old/path' .` and test affected scripts like `pnpm run prepack` before continuing the merge
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes in the open-source react_on_rails gem and npm package (features, bug fixes, breaking changes, deprecations, performance improvements)
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for user-visible changes in the Pro-only react_on_rails_pro gem and npm packages
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Shakapacker configuration should be tested by creating debug scripts in dummy app root (debug-webpack-rules.js, debug-webpack-with-config.js) to inspect webpack rules before committing configuration changes
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to sig/react_on_rails/**/*.rbs : RBS signatures in `sig/react_on_rails/` should be added for new Ruby files in `lib/react_on_rails/`, included in Steepfile, validated with `bundle exec rake rbs:validate`, and type-checked with `bundle exec rake rbs:steep`
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Shakapacker configuration should be tested by creating debug scripts in dummy app root (debug-webpack-rules.js, debug-webpack-with-config.js) to inspect webpack rules before committing configuration changes

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to react_on_rails/spec/dummy/e2e/playwright/app_commands/**/*.rb : Create custom Rails app commands in `e2e/playwright/app_commands/` directory with .rb files for reusable helpers in Playwright tests

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to react_on_rails/spec/dummy/e2e/playwright/e2e/**/*.spec.js : Use Playwright E2E tests in `react_on_rails/spec/dummy/e2e/playwright/` for React component integration testing. Tests automatically start Rails server on port 5017 before running

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to sig/react_on_rails/**/*.rbs : RBS signatures in `sig/react_on_rails/` should be added for new Ruby files in `lib/react_on_rails/`, included in Steepfile, validated with `bundle exec rake rbs:validate`, and type-checked with `bundle exec rake rbs:steep`

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to {package.json,webpack.config.js,packages/*/package.json,react_on_rails_pro/package.json} : When resolving merge conflicts in build configuration files, verify file paths are correct by running `grep -r 'old/path' .` and test affected scripts like `pnpm run prepack` before continuing the merge

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: For infrastructure/config changes, perform comprehensive local testing including: finding all affected files with grep, testing build pipeline, running relevant specs, and linting everything before pushing

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for user-visible changes in the Pro-only react_on_rails_pro gem and npm packages

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to react_on_rails/spec/dummy/e2e/playwright/e2e/**/*.spec.js : Use `app('clean')`, `appEval(code)`, `appFactories(options)`, and `appScenario(name)` helpers from cypress-on-rails in Playwright tests for Rails integration

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-02-18T13:08:01.477Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: lib/react_on_rails/helper.rb:190-197
Timestamp: 2025-02-18T13:08:01.477Z
Learning: RSC support validation in React on Rails Pro is handled through a chain of validations:
1. Pro version check in `run_stream_inside_fiber`
2. RSC support check during pack generation via `ReactOnRailsPro.configuration.enable_rsc_support`
3. RSC support validation during component registration
This makes additional validation in the helper methods unnecessary.

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-09-29T14:45:42.687Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1833
File: lib/react_on_rails/dev/process_manager.rb:72-83
Timestamp: 2025-09-29T14:45:42.687Z
Learning: In Ruby bundler contexts, when bundler intercepts system commands for executables not in the Gemfile, both version checks (like `system("foreman", "--version")`) and execution commands (like `system("foreman", "start", ...)`) fail equally, both returning false. This means availability checks using version flags accurately reflect whether execution commands will work in the current bundler context.

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
📚 Learning: 2025-10-23T17:22:01.074Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.074Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. The `react_on_rails_pro?` method validates licenses and should raise errors early (including during path resolution in methods like `server_bundle?`) to enforce licensing requirements rather than failing later with obscure errors.

Applied to files:

  • react_on_rails/spec/react_on_rails/packer_utils_spec.rb
🧬 Code graph analysis (1)
react_on_rails/spec/react_on_rails/packer_utils_spec.rb (1)
react_on_rails/lib/react_on_rails/packer_utils.rb (1)
  • shakapacker_precompile_hook_configured? (178-192)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: dummy-app-integration-tests (3.4, 22, latest)
  • GitHub Check: rspec-package-tests (3.4, latest)
  • GitHub Check: build
  • GitHub Check: claude-review
🔇 Additional comments (3)
react_on_rails/spec/react_on_rails/packer_utils_spec.rb (3)

5-5: RuboCop pragmas are appropriate for comprehensive test coverage.

The disable/enable pair for Metrics/ModuleLength is properly placed and reasonable for a test file with extensive coverage. Ensure bundle exec rubocop is run before committing to verify no other violations are introduced.

Also applies to: 287-287


159-164: LGTM! Test correctly verifies detection of generate_packs_if_stale.

The test appropriately covers the new detection pattern for Ruby method invocation, complementing the existing rake task test.


144-253: Test suite successfully covers the enhanced precompile hook detection.

The expanded test coverage correctly verifies:

  1. Detection of both react_on_rails:generate_packs and generate_packs_if_stale patterns
  2. Direct hook command scenarios
  3. Script-file-based hook scenarios
  4. Error cases (missing Shakapacker, config errors, missing files)

The tests align well with the PR objectives to fix detection for generator-template-created hooks.

The method can return nil when Shakapacker is not defined or on error,
but the RBS signature declared it as returning String. Updated to String?
to match the actual implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@claude
Copy link

claude bot commented Jan 5, 2026

Code Review

Overall Assessment

LGTM - This is a well-executed fix with excellent problem analysis, comprehensive testing, and clean implementation.


Strengths

1. Problem Analysis 🔍

  • Excellent root cause analysis identifying the historical divergence between the generator template (Oct 24) and detection logic (Nov 5)
  • Clear documentation of the issue in both the PR description and the related issue precompile_hook detection always returns false due to regex mismatch #2279
  • Proper understanding of why the Ruby method approach (generate_packs_if_stale) is actually more efficient than the rake task

2. Solution Design

  • Simple, elegant fix using a constant GENERATE_PACKS_PATTERN that matches both valid patterns
  • Pattern is well-documented with clear comments explaining what each part matches
  • No breaking changes - the fix is purely additive (supports both old and new patterns)

3. Test Coverage

Comprehensive test coverage covering all scenarios:

  • Direct command with rake task
  • Direct command with Ruby method (new case)
  • Script file with generate_packs_if_stale (new case)
  • Script file with rake task
  • Script file without pack generation
  • Missing script file
  • Nil/empty hook values

The tests use realistic code samples (heredoc with actual script content) rather than just mock strings, which increases confidence.

4. Type Safety 🔒

  • Updated RBS signature to correctly mark return type as String? (was String)
  • This accurately reflects that shakapacker_precompile_hook_value can return nil

5. Manual Testing 🧪

  • Tested with fresh Rails 8.0.4 + Shakapacker 9.4.0 app
  • Verified before/after behavior
  • Follows the CLAUDE.md requirement: "NEVER claim a test is 'fixed' without running it locally first"

Code Quality

Maintainability

  • Constant extraction: Using GENERATE_PACKS_PATTERN makes the pattern reusable and self-documenting
  • Clear comments: The constant has a helpful comment explaining both patterns it matches
  • No duplication: Pattern is defined once and used in both places

Error Handling

  • Existing error handling is appropriate (rescue StandardError → false)
  • Fail-safe behavior: when detection fails, it runs pack generation (safer than skipping)

Performance

  • No performance impact - still just regex matching and file reading
  • The fix adds minimal overhead (one additional alternation in regex)

Potential Concerns

1. Pattern Specificity ⚠️

The regex /\b(react_on_rails:generate_packs|generate_packs_if_stale)\b/ uses word boundaries (\b).

Potential edge case: What if someone comments out the line?

# ReactOnRails::PacksGenerator.instance.generate_packs_if_stale

The regex would still match. However, this is acceptable because:

  • If someone commented it out, they probably broke their hook
  • The fail-safe behavior (running pack generation) is appropriate
  • Trying to parse Ruby/shell syntax correctly would be complex and fragile

Recommendation: This is fine as-is. The current approach is pragmatic.

2. Missing Private Method Signature 📝

The RBS file doesn't include signatures for the private helper methods:

  • hook_contains_generate_packs?
  • extract_precompile_hook
  • resolve_hook_script_path

Impact: Low - these are private methods, so external type checking doesn't need them.

Recommendation: Consider adding them for completeness in a follow-up (not blocking).


Security Considerations

No security concerns:

  • File path resolution uses Rails.root.join() which is safe
  • Only reads files, doesn't execute them
  • Regex is simple and not vulnerable to ReDoS attacks
  • No user input is directly interpolated

Performance Considerations

No performance concerns:

  • File reading is only done when hook is configured (rare code path)
  • Regex is simple with no backtracking
  • Results are not cached, but this method is called infrequently (only during precompile setup)

Compliance with CLAUDE.md Guidelines

All requirements met:


Suggestions (Non-Blocking)

  1. Consider documenting the pattern in code comments near where shakapacker_precompile_hook_configured? is called, so future maintainers understand why both patterns are supported.

  2. Follow-up RBS enhancement: Add private method signatures to the RBS file for better internal type coverage:

    # In sig/react_on_rails/packer_utils.rbs
    def self.hook_contains_generate_packs?: (String? hook_value) -> bool
    def self.extract_precompile_hook: () -> String?
    def self.resolve_hook_script_path: (String hook_value) -> Pathname?
  3. Documentation: Consider adding a comment in the generator template (bin/shakapacker-precompile-hook) mentioning that both the rake task and Ruby method approaches are supported, in case users want to customize it.


Final Verdict

Approved - Ship it!

This PR:

  • Fixes a real bug that affects all users of the generator
  • Has comprehensive test coverage
  • Includes excellent documentation
  • Follows all repository conventions
  • Was properly tested manually

Great work on the thorough investigation and clean implementation! 🎉

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.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d45f17f and 4c55093.

📒 Files selected for processing (1)
  • react_on_rails/sig/react_on_rails/packer_utils.rbs
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /{CHANGELOG.md,CHANGELOG_PRO.md} : Use format `[PR 1818](https://github.com/shakacode/react_on_rails/pull/1818) by [username](https://github.com/username)` in changelog entries (no hash in PR number)
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to sig/react_on_rails/**/*.rbs : RBS signatures in `sig/react_on_rails/` should be added for new Ruby files in `lib/react_on_rails/`, included in Steepfile, validated with `bundle exec rake rbs:validate`, and type-checked with `bundle exec rake rbs:steep`
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to {package.json,webpack.config.js,packages/*/package.json,react_on_rails_pro/package.json} : When resolving merge conflicts in build configuration files, verify file paths are correct by running `grep -r 'old/path' .` and test affected scripts like `pnpm run prepack` before continuing the merge
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes in the open-source react_on_rails gem and npm package (features, bug fixes, breaking changes, deprecations, performance improvements)
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for user-visible changes in the Pro-only react_on_rails_pro gem and npm packages
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Shakapacker configuration should be tested by creating debug scripts in dummy app root (debug-webpack-rules.js, debug-webpack-with-config.js) to inspect webpack rules before committing configuration changes
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to react_on_rails/spec/dummy/e2e/playwright/app_commands/**/*.rb : Create custom Rails app commands in `e2e/playwright/app_commands/` directory with .rb files for reusable helpers in Playwright tests
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: lib/react_on_rails/helper.rb:190-197
Timestamp: 2025-02-18T13:08:01.477Z
Learning: RSC support validation in React on Rails Pro is handled through a chain of validations:
1. Pro version check in `run_stream_inside_fiber`
2. RSC support check during pack generation via `ReactOnRailsPro.configuration.enable_rsc_support`
3. RSC support validation during component registration
This makes additional validation in the helper methods unnecessary.
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Git pre-commit hooks automatically run RuboCop (auto-fix), ESLint (auto-fix), Prettier (auto-format), and trailing newline checks on all changed files before each commit
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to sig/react_on_rails/**/*.rbs : RBS signatures in `sig/react_on_rails/` should be added for new Ruby files in `lib/react_on_rails/`, included in Steepfile, validated with `bundle exec rake rbs:validate`, and type-checked with `bundle exec rake rbs:steep`

Applied to files:

  • react_on_rails/sig/react_on_rails/packer_utils.rbs
📚 Learning: 2025-12-19T18:57:59.314Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for user-visible changes in the Pro-only react_on_rails_pro gem and npm packages

Applied to files:

  • react_on_rails/sig/react_on_rails/packer_utils.rbs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: dummy-app-integration-tests (3.4, 22, latest)
  • GitHub Check: examples (3.4, latest)
  • GitHub Check: rspec-package-tests (3.4, latest)
  • GitHub Check: build
  • GitHub Check: pro-lint-js-and-ruby
  • GitHub Check: build-dummy-app-webpack-test-bundles
  • GitHub Check: build-dummy-app-webpack-test-bundles
  • GitHub Check: claude-review
🔇 Additional comments (1)
react_on_rails/sig/react_on_rails/packer_utils.rbs (1)

10-10: LGTM: Nullable return type correctly reflects implementation behavior.

The change from String to String? appropriately handles cases where the precompile hook value may be absent (missing configuration, missing script files, or read errors).

def self.precompile?: () -> bool
def self.shakapacker_precompile_hook_configured?: () -> bool
def self.shakapacker_precompile_hook_value: () -> String
def self.shakapacker_precompile_hook_value: () -> String?
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 5, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Extract public class methods from the Ruby implementation
echo "=== Public class methods in packer_utils.rb ==="
rg -n "^\s*def self\." react_on_rails/lib/react_on_rails/packer_utils.rb

echo ""
echo "=== Current RBS signatures ==="
cat react_on_rails/sig/react_on_rails/packer_utils.rbs

echo ""
echo "=== Checking for resolve_hook_script_path method ==="
rg -n "resolve_hook_script_path" react_on_rails/lib/react_on_rails/packer_utils.rb

Repository: shakacode/react_on_rails

Length of output: 2308


🏁 Script executed:

#!/bin/bash
# Validate RBS signatures
cd react_on_rails
bundle exec rake rbs:validate

# Run Steep type-checking
bundle exec rake rbs:steep

Repository: shakacode/react_on_rails

Length of output: 154


Add RBS signature for the public resolve_hook_script_path method.

The resolve_hook_script_path(hook_value) method is defined as public at line 231 in lib/react_on_rails/packer_utils.rb but is missing from the RBS signature file. Add the corresponding method signature to sig/react_on_rails/packer_utils.rbs.

🤖 Prompt for AI Agents
In react_on_rails/sig/react_on_rails/packer_utils.rbs around line 10, add an RBS
signature for the public class method resolve_hook_script_path taking a
hook_value and returning an optional string; specifically, declare def
self.resolve_hook_script_path: (String?) -> String? so the public method defined
at lib/react_on_rails/packer_utils.rb line 231 is represented in the signature
file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

resolve_hook_script_path is only called internally by hook_contains_generate_packs? (line 220). It's not part of the intended public API.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ihabadham, thank you for the clarification! You're absolutely right—if resolve_hook_script_path is internal and not part of the public API, it shouldn't be included in the RBS signature file.

To make the internal nature explicit in the Ruby code, consider marking it as private:

class << self
  private

  def resolve_hook_script_path(hook_value)
    # implementation
  end
end

This way, Ruby will enforce that it can only be called from within the module, making the intention clear to future maintainers.


🧠 Learnings used
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Shakapacker configuration should be tested by creating debug scripts in dummy app root (debug-webpack-rules.js, debug-webpack-with-config.js) to inspect webpack rules before committing configuration changes

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to sig/react_on_rails/**/*.rbs : RBS signatures in `sig/react_on_rails/` should be added for new Ruby files in `lib/react_on_rails/`, included in Steepfile, validated with `bundle exec rake rbs:validate`, and type-checked with `bundle exec rake rbs:steep`

Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1745
File: node_package/src/RSCRequestTracker.ts:8-14
Timestamp: 2025-07-08T05:57:29.630Z
Learning: The global `generateRSCPayload` function in React on Rails Pro (RORP) is provided by the framework during rendering requests, not implemented in application code. The `declare global` statements are used to document the expected interface that RORP will inject at runtime.

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for user-visible changes in the Pro-only react_on_rails_pro gem and npm packages

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes in the open-source react_on_rails gem and npm package (features, bug fixes, breaking changes, deprecations, performance improvements)

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /{CHANGELOG.md,CHANGELOG_PRO.md} : Use format `[PR 1818](https://github.com/shakacode/react_on_rails/pull/1818) by [username](https://github.com/username)` in changelog entries (no hash in PR number)

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to {package.json,webpack.config.js,packages/*/package.json,react_on_rails_pro/package.json} : When resolving merge conflicts in build configuration files, verify file paths are correct by running `grep -r 'old/path' .` and test affected scripts like `pnpm run prepack` before continuing the merge

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

valid suggestion, but out of scope for this PR, no?

Copy link
Contributor

Choose a reason for hiding this comment

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

@ihabadham, you're absolutely right—marking it as private would be out of scope for this PR, which is focused on fixing the hook detection logic. That's a good refactoring for a separate change if needed in the future, but not necessary here. 👍


🧠 Learnings used
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Shakapacker configuration should be tested by creating debug scripts in dummy app root (debug-webpack-rules.js, debug-webpack-with-config.js) to inspect webpack rules before committing configuration changes

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to sig/react_on_rails/**/*.rbs : RBS signatures in `sig/react_on_rails/` should be added for new Ruby files in `lib/react_on_rails/`, included in Steepfile, validated with `bundle exec rake rbs:validate`, and type-checked with `bundle exec rake rbs:steep`

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for user-visible changes in the Pro-only react_on_rails_pro gem and npm packages

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes in the open-source react_on_rails gem and npm package (features, bug fixes, breaking changes, deprecations, performance improvements)

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to /{CHANGELOG.md,CHANGELOG_PRO.md} : Use format `[PR 1818](https://github.com/shakacode/react_on_rails/pull/1818) by [username](https://github.com/username)` in changelog entries (no hash in PR number)

Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-19T18:57:59.314Z
Learning: Applies to {package.json,webpack.config.js,packages/*/package.json,react_on_rails_pro/package.json} : When resolving merge conflicts in build configuration files, verify file paths are correct by running `grep -r 'old/path' .` and test affected scripts like `pnpm run prepack` before continuing the merge

@claude
Copy link

claude bot commented Jan 5, 2026

Code Review for PR #2282

✅ Summary

This PR successfully fixes the precompile hook detection issue by updating the regex pattern to match both the rake task approach and the Ruby method approach used by the generator template. The implementation is solid with excellent test coverage.


🎯 Strengths

  1. Root Cause Analysis: The PR description provides excellent historical context explaining how the mismatch occurred (Oct 24 template vs Nov 5 detection logic).

  2. Comprehensive Test Coverage: The new test suite covers all critical scenarios:

    • Direct command with generate_packs_if_stale method ✅
    • Script file with generate_packs_if_stale method ✅
    • Script file with react_on_rails:generate_packs rake task ✅
    • Missing script file handling ✅
    • Non-generation scripts ✅
  3. Clean Implementation: Using a constant (GENERATE_PACKS_PATTERN) for the regex is good practice - it's self-documenting and DRY.

  4. Backward Compatibility: The fix maintains support for both approaches, ensuring existing implementations using the rake task continue to work.

  5. RBS Type Safety: Correctly updated the signature for shakapacker_precompile_hook_value to return String? instead of String, reflecting the actual nil return possibility in lines 236-240.


💡 Suggestions

1. Consider Adding Edge Case Tests

While test coverage is good, consider these additional scenarios:

# Test with whitespace variations
"  generate_packs_if_stale  "  # Should match
"generate_packs_if_stale()"   # Should match (method call with parens)
"#generate_packs_if_stale"    # Should NOT match (commented out)

The current regex (\b(react_on_rails:generate_packs|generate_packs_if_stale)\b) should handle these correctly, but explicit tests would provide confidence.

2. Documentation Enhancement

Consider adding a code comment explaining why both patterns exist:

# Regex pattern to detect pack generation in hook scripts
# Matches both:
# - The rake task: react_on_rails:generate_packs (used by some legacy setups)
# - The Ruby method: generate_packs_if_stale (used by generator template - more efficient, no shell overhead)
GENERATE_PACKS_PATTERN = /\b(react_on_rails:generate_packs|generate_packs_if_stale)\b/

This helps future maintainers understand the rationale.

3. Minor: RuboCop Disable Comment

The test file adds # rubocop:disable Metrics/ModuleLength at the top and # rubocop:enable at the bottom. While this works, consider if the module could be split in a future refactor (not blocking for this PR).


🔒 Security Review

No security concerns identified.

  • The resolve_hook_script_path method safely joins paths using Rails.root.join(), preventing path traversal attacks.
  • The File.read() is wrapped in error handling (line 220-222), gracefully handling permission issues.
  • No user input is directly passed to the file system operations - the hook value comes from shakapacker.yml config.

⚡ Performance Considerations

No performance concerns.

  • The regex pattern is simple and efficient (using word boundaries \b).
  • File reading only happens when the hook value is a script path (not a direct command).
  • The error handling ensures graceful degradation if file operations fail.

📋 Testing Validation

Excellent real-world testing:

  • ✅ Tested with Rails 8.0.4 + Shakapacker 9.4.0
  • ✅ Verified generator creates working hook
  • ✅ Confirmed detection returns true after fix
  • ✅ CI is passing (all checks green)

🎓 Best Practices Alignment

Follows project conventions from CLAUDE.md:

  • ✅ Added comprehensive test coverage
  • ✅ Updated RBS type signature
  • ✅ Clear commit message with issue reference
  • ✅ Thorough problem analysis in PR description

📝 Final Recommendation

APPROVE

This is a well-implemented fix with excellent test coverage and clear documentation. The changes are minimal, focused, and backward-compatible. The PR successfully resolves issue #2279 without introducing any regressions.

Minor suggestions above are optional enhancements - they don't block approval. The PR is ready to merge as-is.


Great work on the thorough investigation and fix! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

precompile_hook detection always returns false due to regex mismatch

2 participants