Skip to content

Conversation

@justin808
Copy link
Member

@justin808 justin808 commented Nov 16, 2025

Summary

This PR addresses code review feedback from the initial PR #1788 and subsequent detailed analysis.

Critical Issues Fixed

1. ✅ Added Missing Rspack Support

Problem: Rspack dependencies were accidentally lost during the refactor to shared module
Solution:

  • Added RSPACK_DEPENDENCIES and RSPACK_DEV_DEPENDENCIES constants
  • Created add_rspack_dependencies method in shared module
  • Modified add_dev_dependencies to use Rspack-specific dev deps when --rspack flag is set
  • Conditional installation in add_js_dependencies checks for options.rspack?

Impact: Users installing with --rspack flag now get proper Rspack packages (@rspack/core, rspack-manifest-plugin, @rspack/cli, etc.)

2. ✅ Fixed TypeScript Dependency Consistency

Problem: TypeScript dependency handling was inconsistent with shared module pattern
Solution:

  • Added TYPESCRIPT_DEPENDENCIES constant to shared module
  • Created add_typescript_dependencies method following same pattern as other dependencies
  • Updated install_generator.rb to delegate to shared method
  • Removed manual instance variable setting and inconsistent error handling

Impact: Consistent error handling and pattern across all dependency types (React, CSS, Dev, Rspack, TypeScript)

3. ✅ Documented Unconditional Install Behavior

Problem: Unclear why install_js_dependencies is called unconditionally
Solution: Added comprehensive documentation explaining the design decision
Rationale:

  • package_json gem's install is idempotent - only installs what's actually needed from package.json
  • Prevents edge cases where package.json was modified but dependencies weren't installed
  • Safer and simpler than conditional logic that could miss installation cases

4. ✅ Enhanced Module Documentation

Updates:

  • Instance Variables section: Clarified that module initializes variables using unless defined? pattern
  • Optional Methods section: Documents options.rspack? and options.typescript? support
  • Installation Behavior section: Explains why unconditional install is safe and correct
  • Usage section: Clear contract for classes including the module

Impact: Future maintainers understand the module's behavior and requirements

Initial Code Review Issues Addressed

  1. ✅ Instance Variable Initialization Pattern

    • Changed from ||= to unless defined? pattern for clarity
    • Added documentation explaining initialization by module
  2. ✅ Error Messages Made More Specific

    • All raise statements include which packages failed
    • Added context about shakapacker dependency
    • Example: "Failed to add React dependencies (react, react-dom, ...) via package_json gem. This indicates shakapacker dependency may not be properly installed."
  3. ✅ Documented add_js_dependency Method

    • Added YARD-style documentation
    • Clarified it's for single package with version (react-on-rails@VERSION)
    • Explained add_js_dependencies_batch is for batch operations
  4. ✅ Fixed RuboCop Violations

    • Removed redundant begin block
    • All files pass with zero offenses

Testing

  • ✅ All generator tests pass (6 examples, 0 failures)
  • bundle exec rubocop passes with zero offenses
  • ✅ Git hooks (pre-commit, pre-push) all pass
  • ✅ Rspack and TypeScript support verified in code

Files Changed

  • lib/generators/react_on_rails/js_dependency_manager.rb: Added Rspack & TypeScript support, enhanced documentation
  • lib/generators/react_on_rails/install_generator.rb: Simplified TypeScript method to delegate to shared module
  • lib/generators/react_on_rails/base_generator.rb: Method rename for clarity
  • spec/react_on_rails/generators/message_deduplication_spec.rb: Updated tests

Test plan

  • Run bundle exec rspec spec/react_on_rails/generators/message_deduplication_spec.rb
  • Run bundle exec rubocop
  • Verify git hooks pass
  • Verify Rspack constants and methods are present
  • Verify TypeScript constants and methods are present

🤖 Generated with Claude Code


This change is Reviewable

Summary by CodeRabbit

  • Configuration

    • Default JS transpiler changed to SWC and bundler selector made explicit.
  • Improvements

    • JavaScript dependency management centralized for more consistent installs.
    • Dev tooling simplified (new dev script entrypoint).
  • Styling / Lint

    • Replaced scss-lint with Stylelint, added config and lint script; CI now runs SCSS linting.
  • Tests

    • Added tests to prevent duplicate post-install messages and redundant install actions.
  • Version

    • Package/library version bumped to 16.2.0-beta.5.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

Walkthrough

Centralizes JavaScript dependency management into a new JsDependencyManager and updates generators to delegate to it; renames a gitignore-related method; switches Shakapacker defaults to SWC; replaces scss-lint with stylelint (configs, CI, rake, dev deps); adds tests and bumps package/library versions.

Changes

Cohort / File(s) Summary
Generator core & delegation
lib/generators/react_on_rails/base_generator.rb, lib/generators/react_on_rails/install_generator.rb
Require/include JsDependencyManager; delegate JS dependency setup/install to it; remove in-generator JS install helpers; rename update_gitignore_for_generated_bundlesupdate_gitignore_for_auto_registration.
Centralized dependency manager
lib/generators/react_on_rails/js_dependency_manager.rb
New module that declares dependency lists (React, CSS, Dev, Rspack, TypeScript) and implements setup/collect/install lifecycle using package_json with conditional handling for rspack and typescript.
Shakapacker template
lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
Replace webpack_loader with javascript_transpiler: "swc" and add assets_bundler selector; update defaults/comments.
Linting swap: scss-lint → stylelint
.stylelintrc.json, .scss-lint.yml (removed), Gemfile.development_dependencies, package.json, .github/workflows/lint-js-and-ruby.yml, rakelib/lint.rake, rakelib/docker.rake, spec/dummy/bin/scss-lint (removed)
Remove scss-lint config and gem; add stylelint config and devDependencies; add lint:scss script and CI step; update rake tasks and docker task descriptions; remove scss-lint binstub.
Tests & dev bin wrappers
spec/react_on_rails/generators/message_deduplication_spec.rb, spec/dummy/bin/dev, react_on_rails_pro/spec/dummy/bin/dev
Add message-deduplication and dependency-manager inclusion tests; add Ruby wrapper dev scripts delegating to template dev script.
Knip & ignores
knip.ts
Expand workspace ignore patterns and ignoreDependencies to exclude additional client paths and transitive JS deps.
Version bumps & package updates
lib/react_on_rails/version.rb, react_on_rails_pro/lib/react_on_rails_pro/version.rb, package.json, packages/react-on-rails/package.json, packages/react-on-rails-pro/package.json, react_on_rails_pro/package.json
Bump library and package versions to 16.2.0.beta.5 / 16.2.0-beta.5; update pro package dependency.

Sequence Diagram(s)

sequenceDiagram
    participant Gen as Generator (Base/Install)
    participant JsDM as JsDependencyManager
    participant Pkg as package_json gem

    Note over Gen,JsDM: Generator delegates JS dependency work
    Gen->>JsDM: setup_js_dependencies(options)
    JsDM->>JsDM: assemble dependency lists (REACT, CSS, DEV, RSPACK?, TYPESCRIPT?)
    JsDM->>Pkg: add/ensure packages + install_js_dependencies()
    Pkg-->>JsDM: install result (success/failure)
    JsDM-->>Gen: status / user guidance
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • Conditional assembly of dependencies for options.rspack? and options.typescript? in JsDependencyManager.
    • package_json usage and error/user messaging in install flow.
    • Confirm no leftover duplicated JS-install logic in generators and that renamed gitignore method is referenced correctly.
    • Linting swap impacts (CI, rake, dev deps) and the removed .scss-lint.yml behavior.

Possibly related issues

Possibly related PRs

Suggested reviewers

  • ihabadham
  • Judahmeek
  • alexeyr-ci

Poem

🐇 I hopped through files, tidy and keen,
I gathered JS friends behind a new screen.
SWC hums as bundles take flight,
Stylelint polishes SCSS just right.
Happy thumps — dependencies all seen!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the primary changes: fixing duplicate messages in the install generator and addressing code review issues from PR #1788.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/pr-1788-rebased

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 Nov 16, 2025

Code Review - PR #2030

Summary

This PR successfully addresses the code review feedback from #1788 by refactoring JavaScript dependency management into a shared module and improving error handling. The changes demonstrate solid software engineering practices with good test coverage.


✅ Strengths

1. Excellent Code Reuse via Module Extraction

The new JsDependencyManager module eliminates ~280 lines of duplicated code between base_generator.rb and install_generator.rb. This is a textbook example of DRY principles:

  • Constants for dependency groups (REACT_DEPENDENCIES, CSS_DEPENDENCIES, DEV_DEPENDENCIES) make it easy to maintain and update package lists
  • Both generators now include the module and get consistent behavior
  • lib/generators/react_on_rails/js_dependency_manager.rb:27-50

2. Improved Error Messages with Context

Error messages now include:

  • Specific packages that failed - helps debugging significantly
  • Root cause context - indicates shakapacker installation issues
  • Example at lib/generators/react_on_rails/js_dependency_manager.rb:78-79

This is a major improvement over generic error messages.

3. Comprehensive Test Coverage

The new message_deduplication_spec.rb tests:

  • Message deduplication (preventing duplicate success messages)
  • NPM install execution paths
  • Module inclusion and method organization
  • Both Redux and non-Redux installation paths

Particularly good: spec/react_on_rails/generators/message_deduplication_spec.rb:104-132 verifies the module is properly included and methods aren't duplicated.

4. Clean Instance Variable Initialization

The unless defined? pattern at lib/generators/react_on_rails/js_dependency_manager.rb:57 is clearer than ||= for this use case and includes helpful documentation.

5. Consistent TypeScript Dependency Handling

The refactoring in install_generator.rb (lib/generators/react_on_rails/install_generator.rb:374-384) now uses the same pattern as other dependencies, eliminating the inconsistent manual instance variable setting.


🔍 Observations & Minor Suggestions

1. Potential Redundant Instance Variable Setting

In js_dependency_manager.rb, @added_dependencies_to_package_json is set to true in every successful add_*_dependencies method:

  • add_react_on_rails_package (line 75)
  • add_react_dependencies (line 87)
  • add_css_dependencies (line 99)
  • add_dev_dependencies (line 111)

Observation: This works correctly but sets the same variable 4 times. Consider setting it once in setup_js_dependencies after all additions succeed. However, the current approach is defensive and explicit, which is valid.

2. Error Handling Strategy: Raise vs Warning

The module now raises exceptions when dependency installation fails (js_dependency_manager.rb:78, 90, 102, 114), while install_js_dependencies uses warnings (js_dependency_manager.rb:165-174).

Question for consideration: Should the behavior be consistent? The comment says "This should not happen" which suggests these are exceptional conditions worth raising. This seems reasonable given shakapacker is a hard dependency.

3. YARD Documentation Quality

The module has excellent high-level documentation (lib/generators/react_on_rails/js_dependency_manager.rb:7-26) and method-level YARD docs (lines 119-127, 147-154). This is great for maintainability.

Minor suggestion: The module documentation could mention that methods raise exceptions on failure (though the method implementations make this clear).

4. Test Mock Specificity

In message_deduplication_spec.rb:87-88, multiple methods are mocked together:

allow(install_generator).to receive_messages(add_js_dependency: true, add_js_dependencies_batch: true,
                                                     install_js_dependencies: true)

This is clean, but consider whether you want to test each method's success/failure independently in future tests.


🔒 Security Considerations

No security concerns identified

  • String interpolation in error messages uses local constants and ReactOnRails::VERSION
  • No user input is directly interpolated
  • Exception handling is appropriate

⚡ Performance Considerations

No performance issues

  • Batch operations use add_js_dependencies_batch which delegates to add_npm_dependencies
  • Constants are frozen (REACT_DEPENDENCIES.freeze)
  • Lazy loading of package_json gem maintained in GeneratorHelper

🧪 Test Coverage Assessment

Strong test coverage with room for one addition:

Well covered:

  • Message deduplication
  • Module inclusion verification
  • NPM install execution flow
  • Redux vs non-Redux paths

💡 Potential addition (not blocking):

  • Test the actual error raising when add_js_dependency or add_js_dependencies_batch returns false
  • This would verify the exception messages contain the expected package names

📋 Code Quality & Best Practices

Adheres to React on Rails Standards:

  • ✅ RuboCop compliant (per PR description)
  • ✅ Proper module organization
  • ✅ YARD documentation
  • ✅ Frozen constants
  • ✅ Clear method responsibilities

Ruby Best Practices:

  • ✅ Single Responsibility Principle - module focuses on JS dependency management
  • ✅ DRY - eliminates duplication
  • ✅ Proper exception handling with context
  • ✅ Guard clauses (return false unless pj)

🎯 Final Assessment

This is high-quality refactoring work that addresses all the code review feedback comprehensively.

Recommendation: ✅ Approve

The PR:

  • Successfully eliminates code duplication
  • Improves error messages significantly
  • Maintains backward compatibility
  • Includes comprehensive tests
  • Follows project conventions

Minor Follow-ups (Non-blocking):

  1. Consider testing exception raising scenarios explicitly
  2. Document in module comments that methods raise on failure
  3. Verify with a manual test that the improved error messages appear correctly in real failure scenarios

Great work on this refactoring! 🎉 The codebase is much cleaner and more maintainable now.


Review performed by Claude Code - analyzed code structure, tests, error handling, and adherence to React on Rails conventions per CLAUDE.md

@claude
Copy link

claude bot commented Nov 16, 2025

Code Review for PR #2030

Overview

This PR successfully addresses the code review feedback from #1788 by extracting duplicated JS dependency management logic into a shared module and improving error handling. The refactoring is well-executed and improves code maintainability.


✅ Strengths

1. Excellent Code Organization

  • DRY Principle: Extracting JsDependencyManager module eliminates significant duplication between BaseGenerator and InstallGenerator
  • Clear Separation of Concerns: The module has a single, well-defined responsibility
  • Comprehensive Documentation: YARD-style comments clearly explain requirements and usage patterns

2. Improved Error Handling

  • Error messages now include specific package names that failed (e.g., "react, react-dom, ...")
  • Clear indication that failures suggest shakapacker installation issues
  • Consistent error handling pattern across all dependency types

3. Better Type Safety & Initialization

  • The unless defined?(@added_dependencies_to_package_json) pattern is clearer than ||=
  • Properly documents that instance variables are initialized by the module
  • TypeScript dependency installation now follows the same pattern (no more manual instance variable manipulation)

4. Excellent Test Coverage

  • message_deduplication_spec.rb thoroughly tests the new module
  • Tests verify both Redux and non-Redux installations
  • Tests confirm methods come from the shared module (not duplicated)
  • Tests verify duplicate install commands are not executed

🔍 Observations & Minor Suggestions

1. Hardcoded Constants vs Configuration

REACT_DEPENDENCIES = %w[
  react
  react-dom
  @babel/preset-react
  # ...
].freeze

Observation: These dependencies are now hardcoded constants in the module. This is fine for stable dependencies, but consider if there's ever a need to override these per-generator.

Recommendation: Current approach is good. If customization is needed later, could add optional override parameters.

2. Error Handling Philosophy

The new code raises exceptions when package_json gem fails:

raise "Failed to add React dependencies (...) via package_json gem. " \
      "This indicates shakapacker dependency may not be properly installed."

Observation: This is a breaking change from the previous warning-based approach. The old code used GeneratorMessages.add_warning and allowed the generator to continue.

Questions:

  • Is this intentional? (I suspect yes, since shakapacker is now a required dependency)
  • Should the error message suggest checking Gemfile/bundle install status?
  • Should it provide recovery instructions (e.g., "Please ensure shakapacker is in your Gemfile and run 'bundle install'")?

Recommendation: The strict approach is better if shakapacker is required. Consider enhancing the error message:

raise "Failed to add React dependencies via package_json gem.\n" \
      "This indicates shakapacker may not be properly installed.\n" \
      "Please ensure 'shakapacker' is in your Gemfile and run 'bundle install'."

3. Method Visibility

All methods in JsDependencyManager are private, which is appropriate. However, add_js_dependency and add_js_dependencies_batch have detailed YARD documentation suggesting they might be semi-public interfaces.

Recommendation: Current approach is fine. The documentation helps maintainers understand the module's internal structure.

4. Version Handling Simplification

The old code had this logic:

react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
                       ["react-on-rails@#{ReactOnRails::VERSION}"]
                     else
                       puts "Adding the latest react-on-rails NPM module..."
                       ["react-on-rails"]
                     end

The new code always uses exact version:

react_on_rails_pkg = "react-on-rails@#{ReactOnRails::VERSION}"

Question: Was the version regex check unnecessary? What if ReactOnRails::VERSION is something like "16.1.0.pre.beta"?

Recommendation: If pre-release versions exist, consider keeping the version validation. Otherwise, the simplification is good.

5. Trailing Newline

# No longer needed since package_json gem handles package manager detection
    end
  end
end

Critical: According to CLAUDE.md: "ALWAYS ensure files end with a newline character"

Action Required: Verify js_dependency_manager.rb ends with a newline. The diff shows it does, but worth double-checking before merge.


🧪 Testing Recommendations

Current Testing ✅

  • Message deduplication tests are thorough
  • Module inclusion tests verify proper inheritance

Additional Test Scenarios to Consider

  1. Error Path Testing: Test what happens when package_json gem actually fails (mock failure scenarios)
  2. Version Edge Cases: Test with pre-release version strings if they exist
  3. Integration Test: Ensure install_js_dependencies actually calls package_json.manager.install

🚨 Pre-Merge Checklist

Based on CLAUDE.md requirements:

  • Run bundle exec rubocop - Should pass (PR description confirms this)
  • All files end with newlines - Verify js_dependency_manager.rb
  • Run rake run_rspec - Verify generator tests pass
  • No formatting issues - Should be handled by git hooks

🎯 Final Verdict

Recommendation: APPROVE with minor verification

This is a solid refactoring that:

Before Merge:

  1. Verify trailing newline in js_dependency_manager.rb
  2. Consider enhancing error messages with recovery instructions
  3. Confirm bundle exec rubocop passes locally
  4. Verify all tests pass (especially new generator tests)

Post-Merge Considerations:

  • Monitor for any issues with pre-release gem versions
  • Consider documenting the dependency management strategy in developer docs

Great work on this refactoring! The extraction of JsDependencyManager significantly improves code maintainability and makes the generator logic much clearer.


🤖 Review generated with Claude Code

@claude
Copy link

claude bot commented Nov 16, 2025

Code Review - PR #2030

I've reviewed this PR addressing code review feedback from #1788. Overall, this is a high-quality refactoring that successfully addresses the original feedback while improving code organization and maintainability.

✅ Strengths

1. Excellent Code Organization

  • DRY principle applied well: Extracting duplicate JS dependency management code into a shared JsDependencyManager module eliminates ~170 lines of duplicated code between base_generator.rb and install_generator.rb
  • Single Responsibility: The new module has a clear, focused purpose
  • Comprehensive documentation: YARD-style docs and inline comments explain the module's purpose, requirements, and usage patterns

2. Improved Error Handling

  • Specific error messages: All failures now include the actual package names that failed (e.g., Failed to add React dependencies (react, react-dom, ...))
  • Better context: Error messages explain that failure indicates shakapacker may not be properly installed
  • Consistent pattern: All methods follow the same error handling approach

3. Better Instance Variable Management

  • Fixed initialization pattern: Changed from ||= to unless defined? in js_dependency_manager.rb:56
  • Clear documentation: Explains that the instance variable is initialized by the module

4. Comprehensive Test Coverage

  • Message deduplication tests: New spec file with 133 lines verifies that success messages appear exactly once
  • Method organization tests: Validates that both generators use the shared module
  • NPM install execution tests: Ensures no duplicate install commands run

5. TypeScript Dependency Consistency

  • Fixed inconsistency: install_typescript_dependencies now uses the shared pattern instead of manual instance variable manipulation
  • Proper error handling: Raises specific error instead of just warning if installation fails

🔍 Areas for Consideration

1. Module Dependency Assumption (Minor)

In js_dependency_manager.rb:56:

@added_dependencies_to_package_json = false unless defined?(@added_dependencies_to_package_json)

Observation: This assumes the instance variable might already be defined by the including class. While the comment explains this, it creates a subtle coupling.

Suggestion: Consider whether this state tracking is necessary at all, since the module documentation states "package_json gem is always available via shakapacker". If it's always available, why track whether it was used?

2. Error Handling Strategy (Minor)

The module uses raise for failures (e.g., js_dependency_manager.rb:77):

raise "Failed to add react-on-rails package via package_json gem..."

Observation: While the comment says "This should not happen", raising exceptions will halt the generator entirely. The previous implementation used warnings and allowed continuation.

Question: Is this the desired behavior? Should we:

  • Keep raise (fail-fast approach - ensures proper installation)
  • Revert to warnings (forgiving approach - let users fix manually)
  • Add a configuration option?

Recommendation: The fail-fast approach is actually better for catching misconfigurations early. However, consider adding a more helpful error message suggesting how to verify shakapacker installation.

3. Constant Definitions (Style)

The constants (REACT_DEPENDENCIES, CSS_DEPENDENCIES, DEV_DEPENDENCIES) are well-organized, but:

Observation: add_react_on_rails_package uses a string literal instead of a constant:

react_on_rails_pkg = "react-on-rails@#{ReactOnRails::VERSION}"

Suggestion: For consistency, consider if Rspack dependencies should also be constants (currently they're defined in the deleted code, so this might need to be addressed separately if Rspack support is still needed).

4. Test Coverage Gap (Minor)

The new spec file tests message deduplication and method organization excellently, but:

Observation: No integration tests verifying that the actual package installations work correctly through the new module.

Suggestion: Consider adding a test that mocks package_json.manager.add and verifies the correct packages are added with correct options (dev vs regular, exact versions, etc.).

5. Documentation Completeness

Observation: The module documentation states including classes must provide destination_root, but doesn't mention they must also include GeneratorHelper.

Suggestion: Update the "Required Methods" section to explicitly state:

# == Required Modules
# Including classes must also include GeneratorHelper module

🔒 Security Considerations

No security concerns identified. The code:

  • Uses version strings from the gem itself (ReactOnRails::VERSION)
  • Doesn't execute arbitrary shell commands
  • Properly delegates to the package_json gem for package management

⚡ Performance Considerations

Positive impact:

  • Reduced code duplication means smaller file sizes
  • Single install call instead of potentially multiple npm/yarn invocations
  • Package manager detection is handled once by package_json gem

📋 Code Quality & Best Practices

Excellent adherence to project standards:

  • ✅ RuboCop compliant (as stated in PR description)
  • ✅ Follows CLAUDE.md guidelines
  • ✅ Comprehensive test coverage
  • ✅ Clear, descriptive comments
  • ✅ Proper use of frozen string literals
  • ✅ Consistent error handling patterns

🎯 Recommendations

Before Merging:

  1. Critical: Verify that all generator tests pass, especially those testing Rspack support (since related code was removed)
  2. Important: Confirm the raise vs warn strategy aligns with the team's philosophy for generator failures
  3. Nice-to-have: Add integration test for package installation verification

Future Enhancements (not blockers):

  1. Consider refactoring Rspack dependencies if that's still needed
  2. Add more detailed error recovery instructions in error messages
  3. Consider whether @added_dependencies_to_package_json state tracking is still necessary

✅ Final Verdict

LGTM with minor suggestions. This PR successfully:

The refactoring is well-executed and represents a significant improvement to the codebase. The minor suggestions above are non-blocking and can be addressed in follow-up PRs if desired.

Great work! 🎉

@claude
Copy link

claude bot commented Nov 16, 2025

Code Review - PR #2030

Overall Assessment

Excellent refactoring work! This PR successfully addresses the code review feedback from #1788 and implements a clean, DRY solution by extracting duplicate JS dependency management logic into a shared module.


✅ Strengths

1. Clean Module Extraction

  • The JsDependencyManager module successfully eliminates ~250 lines of duplicate code
  • Proper separation of concerns with well-documented module purpose
  • Good use of Ruby module inclusion pattern

2. Improved Error Messages

  • Error messages now include specific package names that failed
  • Added helpful context about shakapacker dependency relationship
  • Clear guidance for troubleshooting

3. Comprehensive Test Coverage

  • New message_deduplication_spec.rb tests the core issue (duplicate messages)
  • Tests verify proper module inclusion and method organization
  • Good coverage of both Redux and non-Redux installation paths

4. Better Code Organization

  • Instance variable initialization pattern improved with unless defined? check
  • Consistent dependency management approach across generators
  • Removed redundant instance variable tracking logic

🔍 Issues & Concerns

1. Critical: Instance Variable Management Pattern ⚠️

The current implementation has inconsistent state management between the final version and earlier commits:

In the final js_dependency_manager.rb (lines 54-60):

def setup_js_dependencies
  # Initialize instance variable if not already defined by including class
  # This ensures safe operation when the module is first included
  @added_dependencies_to_package_json = false unless defined?(@added_dependencies_to_package_json)
  add_js_dependencies
  install_js_dependencies
end

Problem: This always calls install_js_dependencies unconditionally, but the earlier patch version showed:

install_js_dependencies if @added_dependencies_to_package_json && !@ran_direct_installs

Questions:

  • Why was the conditional check removed? This seems like it could cause duplicate installation runs
  • The @ran_direct_installs variable is no longer used - was this intentional?
  • Does this mean we're now always running package manager install, even if packages were already installed via direct npm commands?

Recommendation:

  • Add a comment explaining why the unconditional install is now safe/correct
  • Or restore the conditional logic if the change was unintentional
  • Update the module documentation to clarify the new behavior

2. Missing Rspack Support in Shared Module 🐛

Issue: install_generator.rb had add_rspack_dependencies method that's now removed but not present in the shared module.

From original code:

def add_js_dependencies
  add_react_on_rails_package
  add_react_dependencies
  add_css_dependencies
  add_rspack_dependencies if options.rspack?  # ← This is lost!
  add_dev_dependencies
end

Impact: Users installing with --rspack flag will not get Rspack dependencies installed.

Recommendation:

  • Add add_rspack_dependencies to the shared module
  • Make it conditional on options.rspack? if available
  • Or document why Rspack support was intentionally removed

3. TypeScript Dependencies Still Inconsistent ⚠️

The install_typescript_dependencies method (lines 374-385 in install_generator.rb) now uses a different pattern than other dependencies:

# Use the shared dependency management approach via GeneratorHelper
unless add_npm_dependencies(typescript_packages, dev: true)
  # This should not happen since package_json is always available via shakapacker
  raise "Failed to add TypeScript dependencies..."
end

@added_dependencies_to_package_json = true

Issues:

  • Sets @added_dependencies_to_package_json directly instead of letting the shared module handle it
  • Uses unless pattern while shared module uses if/return pattern
  • Raises exception instead of using handle_npm_failure warning pattern

Recommendation:

  • Extract TypeScript dependency handling into the shared module for consistency
  • Or clearly document why TypeScript requires different error handling (raise vs warning)

4. Incomplete Documentation 📝

While the YARD docs are good, some areas need clarification:

Module documentation (lines 6-26):

# == Required Instance Variables
# Including classes must support these instance variables:
# - @added_dependencies_to_package_json: Boolean tracking if package_json gem was used

Missing:

  • What about @ran_direct_installs? The earlier commit showed this was used but final version doesn't mention it
  • Document when/how instance variables are expected to be initialized
  • Clarify lifecycle: Is module responsible for initializing these or the including class?

Recommendation: Update documentation to match actual implementation


5. Constants vs Methods for Dependencies 💭

The module defines constants for dependencies:

REACT_DEPENDENCIES = %w[...].freeze
CSS_DEPENDENCIES = %w[...].freeze
DEV_DEPENDENCIES = %w[...].freeze

But then doesn't use them in the methods (lines 80-115). The methods still have inline arrays.

Questions:

  • Are these constants used elsewhere? If not, remove them
  • Should the methods use these constants for consistency?

Recommendation: Either use the constants in the methods or remove them if unused


6. Test Coverage Gaps 🧪

message_deduplication_spec.rb is good but missing:

  1. Rspack flag testing - No tests for --rspack option
  2. TypeScript dependency testing - No coverage for install_typescript_dependencies
  3. Error path testing - Tests mock success but don't test failure scenarios
  4. Integration testing - No test that actually runs npm install to verify the package manager detection works

Example missing test:

context "with rspack flag" do
  it "installs rspack dependencies" do
    # Test that @rspack/core and related packages are added
  end
end

Recommendation: Add test coverage for edge cases and error paths


📋 Minor Suggestions

1. Method Naming Clarity

def add_js_dependency(package, dev: false)  # Single package
def add_js_dependencies_batch(packages, dev: false)  # Multiple packages

The distinction between singular and batch is good, but consider renaming for clarity:

  • add_single_js_dependency or add_versioned_package (since it's mainly for react-on-rails@VERSION)
  • Keep add_js_dependencies_batch as-is

2. Error Handling Consistency

Some methods raise exceptions, others use warnings. Consider:

  • Document when to use raise vs warning
  • Or standardize on one approach

3. Git Ignore Method Rename

update_gitignore_for_generated_bundlesupdate_gitignore_for_auto_registration

Good rename! But ensure any documentation referencing the old name is updated.


🔒 Security Considerations

✅ No security concerns identified. The PR:

  • Doesn't modify any user input handling
  • Doesn't change authentication/authorization logic
  • Maintains existing package manager security practices

⚡ Performance Considerations

Slight improvement: Reduced code duplication means faster loading time (though negligible in practice)

⚠️ Potential concern: If the unconditional install_js_dependencies call is new, this could add installation time. Verify this doesn't cause double-installs.


📊 Test Coverage

Current: Good coverage for message deduplication and module structure

Recommended additions:

  • Test Rspack flag behavior
  • Test TypeScript dependency installation
  • Test error scenarios (network failures, missing package manager)
  • Integration test with actual package manager

✅ Checklist

Before merge, please verify:

  • Rspack support - Confirm Rspack dependencies are still installed with --rspack flag
  • Installation behavior - Verify no duplicate installations occur
  • Instance variable lifecycle - Document when @added_dependencies_to_package_json and @ran_direct_installs are used
  • Constants usage - Either use the CONSTANTS or remove them
  • Tests pass - Run bundle exec rspec spec/react_on_rails/generators/message_deduplication_spec.rb
  • RuboCop passes - Run bundle exec rubocop (mentioned as passing in PR description ✅)
  • Manual testing - Test generator with and without flags: --redux, --rspack, --typescript

🎯 Summary

Verdict: Approve with minor revisions required

This is solid refactoring work that successfully eliminates code duplication and addresses the original code review feedback. The main concerns are:

  1. Missing Rspack support - needs to be restored
  2. Clarify installation behavior - document why conditional check was removed
  3. TypeScript consistency - align with shared module pattern or document difference

Once these issues are addressed, this will be a great improvement to the codebase!


Estimated time to address: ~30-60 minutes

Great work on the refactoring! 🎉

@justin808 justin808 force-pushed the claude/pr-1788-rebased branch from d988757 to 850deed Compare November 17, 2025 05:26
@justin808
Copy link
Member Author

/run-skipped-ci

@github-actions
Copy link
Contributor

🚀 Full CI Mode Enabled

All checks are already running - nothing to do!

All CI checks are already running on this PR. Added the full-ci label - future commits will run the full CI suite.

@justin808
Copy link
Member Author

Additional Update: SWC as Default Webpack Loader

Per code review feedback, I've made additional changes to properly separate SWC from Babel and leverage Shakapacker for build tool management:

Key Changes

  1. shakapacker.yml now defaults to SWC instead of Babel

    • Changed to
    • SWC provides significantly better performance
  2. Removed Babel-specific dependencies from REACT_DEPENDENCIES:

    • ❌ Removed: , ,
    • ✅ Kept: , , (React-specific, not build tool)
    • Why: Shakapacker manages webpack loader configuration. When users choose Babel via shakapacker.yml, Shakapacker installs babel-loader and its dependencies automatically.
  3. **Removed ** from TYPESCRIPT_DEPENDENCIES:

    • SWC has built-in TypeScript support
    • Babel users can add the preset manually if they prefer Babel over SWC

Impact

  • New projects: Faster builds with SWC, cleaner dependencies
  • Existing projects: No breaking changes (keep current webpack_loader setting)
  • Flexibility: Users can still choose Babel by changing one line in shakapacker.yml

All tests continue to pass! ✅

github-actions bot and others added 12 commits November 16, 2025 20:33
Addresses code review feedback from PR #1788:

1. Created shared JsDependencyManager module to eliminate code duplication
   between base_generator.rb and install_generator.rb

2. Added comprehensive test coverage for:
   - Message deduplication (ensuring messages appear exactly once)
   - NPM install command deduplication
   - Proper module inclusion and method organization

3. Improved method organization in install_generator.rb

This refactoring follows DRY principles and makes the codebase more
maintainable by consolidating shared dependency management logic.

Co-authored-by: Justin Gordon <[email protected]>
- Fixed missing newline at end of js_dependency_manager.rb
- Removed recursive add_js_dependencies wrapper in BaseGenerator
- Fixed namespace issues in tests (ReactOnRails::Generators::InstallGenerator)
- Improved RSpec test structure with proper matchers
- Optimized package_json gem usage:
  - Added package_json_available? check
  - Better separation between single and batch dependency adds
  - Improved fallback handling for when package_json is unavailable
  - Use package_json.manager.install when available

Co-authored-by: Justin Gordon <[email protected]>
- Add missing generator class declaration for proper test initialization
- Fix package_json gem mocking to match actual implementation behavior
- Adjust system call expectations to align with fallback path execution

Co-authored-by: Justin Gordon <[email protected]>
- Fixed package_json gem integration by ensuring arrays are passed to manager.add()
- Fixed test mocking issues with webpack config file reading
- Corrected test expectations to match actual behavior
- Fixed mock setup for package_json manager and fallback scenarios
- All message_deduplication_spec tests now pass

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

Co-Authored-By: Claude <[email protected]>
- Fix RuboCop VerifiedDoubles violations by using proper test doubles
- Simplify test mocking approach to focus on intended behavior
- Remove accidental react-on-rails dependency from package.json that broke version checker tests
- Use receive_messages for cleaner multiple stub setup
- Fix test to properly verify package_json integration without over-mocking

The tests now correctly verify:
- Message deduplication works properly
- package_json gem integration works when available
- Fallback to direct npm commands works when needed

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

Co-Authored-By: Claude <[email protected]>
…e documentation

Address Justin's code review suggestions:
- Extract REACT_DEPENDENCIES, CSS_DEPENDENCIES, and DEV_DEPENDENCIES as frozen module constants
- Add comprehensive module documentation explaining required instance variables and methods
- Update all dependency methods to use the new constants for better maintainability

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

Co-Authored-By: Claude <[email protected]>
…y conversions

Address Justin's minor optimization suggestion:
- Use add_js_dependencies_batch instead of add_js_dependency for single package
- Work with arrays consistently throughout the method flow
- Eliminates unnecessary string→array→string conversions
- Maintains identical functionality with improved efficiency

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

Co-Authored-By: Claude <[email protected]>
Address CodeRabbit suggestion #1:
- Remove conditional logic that could skip final install
- Always run install_js_dependencies to ensure packages are properly installed
- Update test to reflect the improved behavior
- Prevents scenarios where no install runs when package_json methods fail

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

Co-Authored-By: Claude <[email protected]>
…e_json checks

Since react_on_rails requires shakapacker (>= 6.0) and shakapacker includes
package_json as a dependency, the package_json gem is always available.

Changes:
- Remove package_json_available? method and all fallback logic
- Simplify version detection to always use exact gem version
- Remove detect_and_run_package_manager_install (package_json handles this)
- Remove @ran_direct_installs tracking (no longer needed)
- Update tests to remove fallback scenarios
- Update documentation to reflect guaranteed package_json availability

This eliminates ~60 lines of redundant code and makes the module more
maintainable and less error-prone.

Co-authored-by: Justin Gordon <[email protected]>
This commit addresses all code review feedback:

1. Improved instance variable initialization pattern
   - Changed from @added_dependencies_to_package_json ||= false
   - To: @added_dependencies_to_package_json = false unless defined?(@added_dependencies_to_package_json)
   - Added clear documentation explaining the initialization is done by the module

2. Made error messages more specific
   - All raise statements now include which packages failed
   - Added context that failure indicates shakapacker may not be properly installed
   - Error messages now help users understand what went wrong

3. Documented add_js_dependency method usage
   - Added YARD-style documentation
   - Clarified it's used for single package with version (react-on-rails@VERSION)
   - Explained add_js_dependencies_batch is for batch operations
   - Both methods now have clear @param and @return documentation

4. Fixed TypeScript dependency installation inconsistency
   - Removed manual instance variable setting
   - Now uses consistent pattern with shared module approach
   - Raises specific error instead of just warning if installation fails
   - Matches the error handling pattern of other dependency methods

5. Fixed RuboCop violations
   - Removed redundant begin block in install_js_dependencies
   - All files now pass bundle exec rubocop with zero offenses

All tests pass successfully (6 examples, 0 failures).

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

Co-Authored-By: Claude <[email protected]>
This commit addresses critical issues identified in code review:

### 1. Added Missing Rspack Support
- **Problem**: Rspack dependencies were lost during the refactor to shared module
- **Solution**: Added RSPACK_DEPENDENCIES and RSPACK_DEV_DEPENDENCIES constants
- **Implementation**:
  - Created `add_rspack_dependencies` method in shared module
  - Modified `add_dev_dependencies` to use Rspack-specific dev deps when `options.rspack?` is true
  - Conditional installation in `add_js_dependencies` checks for `options.rspack?`
- **Impact**: Users with --rspack flag now get proper Rspack packages installed

### 2. Fixed TypeScript Dependency Consistency
- **Problem**: TypeScript dependency handling was inconsistent with shared module pattern
- **Solution**: Extracted TypeScript dependencies into shared module
- **Implementation**:
  - Added TYPESCRIPT_DEPENDENCIES constant
  - Created `add_typescript_dependencies` method following same pattern as other deps
  - Updated `install_generator.rb` to delegate to shared method
  - Removed manual instance variable setting
- **Impact**: Consistent error handling and pattern across all dependency types

### 3. Documented Unconditional Install Behavior
- **Problem**: Unclear why `install_js_dependencies` is called unconditionally
- **Solution**: Added comprehensive documentation explaining the design decision
- **Rationale**:
  - package_json gem's install is idempotent - only installs what's needed
  - Prevents edge cases where package.json modified but dependencies not installed
  - Safer and simpler than conditional logic that could miss cases
- **Impact**: Future maintainers understand why the unconditional call is correct

### 4. Enhanced Module Documentation
- **Updated Instance Variables section**: Clarified module initializes variables
- **Added Optional Methods section**: Documents options.rspack? and options.typescript?
- **Added Installation Behavior section**: Explains idempotent install behavior
- **Impact**: Clear contract for classes including the module

### 5. Constants Usage Verification
- Verified all constants (REACT_DEPENDENCIES, CSS_DEPENDENCIES, DEV_DEPENDENCIES) are properly used
- All dependency methods use their corresponding constants correctly

### Testing
- ✅ All tests pass (6 examples, 0 failures)
- ✅ bundle exec rubocop passes with zero offenses
- ✅ Git hooks (pre-commit, pre-push) verified clean

### Files Changed
- `lib/generators/react_on_rails/js_dependency_manager.rb`: Added Rspack, TypeScript support, enhanced docs
- `lib/generators/react_on_rails/install_generator.rb`: Simplified TypeScript method to delegate to shared module

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

Co-Authored-By: Claude <[email protected]>
…apacker

This commit addresses the code review comment about separating SWC from
Babel and leveraging Shakapacker for webpack/rspack configurations.

### Changes

#### 1. Updated Default Webpack Loader to SWC
**File**: `lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml`
- Changed `webpack_loader` from 'babel' to 'swc'
- Added comment recommending SWC for better performance
- Shakapacker will now use swc-loader instead of babel-loader by default

**Rationale**: SWC is significantly faster than Babel and is now mature enough
to be the recommended default for new React on Rails projects.

#### 2. Removed Babel-Specific Dependencies from REACT_DEPENDENCIES
**Removed packages**:
- `@babel/preset-react` - Shakapacker's babel-loader provides this when needed
- `babel-plugin-transform-react-remove-prop-types` - Build tool specific
- `babel-plugin-macros` - Build tool specific

**Kept packages**:
- `react` - Core React library
- `react-dom` - Core React DOM library
- `prop-types` - Runtime prop validation (React-specific, not build tool)

**Rationale**:
- Shakapacker manages webpack loader configuration (babel-loader vs swc-loader)
- Users configure their preference via `shakapacker.yml` webpack_loader setting
- SWC (now default) doesn't need Babel presets
- Babel users get babel-loader and dependencies from Shakapacker
- This avoids conflicts and duplicate installations

#### 3. Removed @babel/preset-typescript from TYPESCRIPT_DEPENDENCIES
**Removed**: `@babel/preset-typescript`

**Kept**:
- `typescript` - TypeScript compiler
- `@types/react` - React type definitions
- `@types/react-dom` - React DOM type definitions

**Rationale**:
- SWC has built-in TypeScript support (no preset needed)
- Shakapacker handles the loader configuration
- Babel users can add `@babel/preset-typescript` manually if they choose Babel

#### 4. Added Comprehensive Documentation
All dependency constants now include clear comments explaining:
- Why certain packages are excluded
- How Shakapacker manages build tool dependencies
- The relationship between webpack_loader setting and dependencies

### Impact

**For New Projects**:
- Faster build times with SWC by default
- Cleaner dependency tree (no Babel packages unless explicitly needed)
- Easier to understand which dependencies are React-specific vs build tool specific

**For Existing Projects**:
- No breaking changes - existing projects keep their current webpack_loader setting
- Projects can opt into SWC by changing `webpack_loader: 'swc'` in shakapacker.yml
- Babel users continue to work as before (Shakapacker provides babel-loader)

**For Rspack Users**:
- No changes - Rspack has its own loader mechanism
- Rspack-specific dependencies remain unchanged

### Testing
- ✅ All tests pass (6 examples, 0 failures)
- ✅ bundle exec rubocop passes with zero offenses
- ✅ Git hooks verified clean

### Files Changed
- `lib/generators/react_on_rails/js_dependency_manager.rb`: Removed Babel deps, added docs
- `lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml`: Changed default to SWC

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

Co-Authored-By: Claude <[email protected]>
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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 97d4414 and 62d06f0.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • lib/generators/react_on_rails/base_generator.rb (2 hunks)
  • lib/generators/react_on_rails/install_generator.rb (3 hunks)
  • lib/generators/react_on_rails/js_dependency_manager.rb (1 hunks)
  • lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml (1 hunks)
  • spec/react_on_rails/generators/message_deduplication_spec.rb (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 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:

  • lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
  • lib/generators/react_on_rails/install_generator.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • lib/generators/react_on_rails/base_generator.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:

  • lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
  • spec/react_on_rails/generators/message_deduplication_spec.rb
  • lib/generators/react_on_rails/install_generator.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • lib/generators/react_on_rails/base_generator.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:

  • lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
  • spec/react_on_rails/generators/message_deduplication_spec.rb
  • lib/generators/react_on_rails/install_generator.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • lib/generators/react_on_rails/base_generator.rb
📚 Learning: 2025-01-23T18:20:45.824Z
Learnt from: alexeyr-ci
Repo: shakacode/react_on_rails PR: 1687
File: spec/dummy/package.json:0-0
Timestamp: 2025-01-23T18:20:45.824Z
Learning: When adding or updating dependencies in spec/dummy/package.json, maintain version consistency with other package.json files in the codebase to avoid potential version conflicts.

Applied to files:

  • spec/react_on_rails/generators/message_deduplication_spec.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:

  • lib/generators/react_on_rails/install_generator.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • lib/generators/react_on_rails/base_generator.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:

  • lib/generators/react_on_rails/install_generator.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
📚 Learning: 2024-10-08T20:53:47.076Z
Learnt from: theforestvn88
Repo: shakacode/react_on_rails PR: 1620
File: spec/dummy/client/app/startup/HelloTurboStream.jsx:3-3
Timestamp: 2024-10-08T20:53:47.076Z
Learning: The `RailsContext` import in `spec/dummy/client/app/startup/HelloTurboStream.jsx` is used later in the project, as clarified by the user theforestvn88.

Applied to files:

  • lib/generators/react_on_rails/base_generator.rb
🧬 Code graph analysis (4)
spec/react_on_rails/generators/message_deduplication_spec.rb (2)
spec/react_on_rails/support/generator_spec_helper.rb (1)
  • run_generator_test_with_args (62-72)
lib/generators/react_on_rails/generator_messages.rb (1)
  • output (5-7)
lib/generators/react_on_rails/install_generator.rb (1)
lib/generators/react_on_rails/js_dependency_manager.rb (2)
  • setup_js_dependencies (92-104)
  • add_typescript_dependencies (166-176)
lib/generators/react_on_rails/js_dependency_manager.rb (1)
lib/generators/react_on_rails/generator_helper.rb (2)
  • package_json (7-20)
  • add_npm_dependencies (23-39)
lib/generators/react_on_rails/base_generator.rb (2)
lib/generators/react_on_rails/install_generator.rb (1)
  • include (12-435)
lib/generators/react_on_rails/react_with_redux_generator.rb (1)
  • include (9-142)
🪛 ast-grep (0.39.9)
spec/react_on_rails/generators/message_deduplication_spec.rb

[warning] 33-36: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: expect(success_count).to(
eq(1),
"Expected success message to appear exactly once, but appeared #{success_count} times"
)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html

(hardcoded-secret-rsa-passphrase-ruby)


[warning] 51-54: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: expect(success_count).to(
eq(1),
"Expected success message to appear exactly once with Redux, but appeared #{success_count} times"
)
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html

(hardcoded-secret-rsa-passphrase-ruby)

⏰ 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). (11)
  • GitHub Check: build-dummy-app-webpack-test-bundles (3.2, 20, minimum)
  • GitHub Check: build-dummy-app-webpack-test-bundles (3.4, 22, latest)
  • GitHub Check: examples (3.4, latest)
  • GitHub Check: examples (3.2, minimum)
  • GitHub Check: rspec-package-tests (3.2, minimum)
  • GitHub Check: rspec-package-tests (3.4, latest)
  • GitHub Check: pro-lint-js-and-ruby
  • GitHub Check: build
  • GitHub Check: build-dummy-app-webpack-test-bundles
  • GitHub Check: build-dummy-app-webpack-test-bundles
  • GitHub Check: claude-review

Comment on lines +206 to +218
def add_js_dependency(package, dev: false)
pj = package_json
return false unless pj

begin
# Ensure package is in array format for package_json gem
packages_array = [package]
if dev
pj.manager.add(packages_array, type: :dev)
else
pj.manager.add(packages_array)
end
true
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Pin the npm package to the gem’s exact version.

add_js_dependency adds react-on-rails@#{ReactOnRails::VERSION} without exact: true, so the package_json gem will record it with a caret range (e.g., ^12.3.0). That defeats the intent of keeping the npm package in sync with the Ruby gem and can pull in incompatible releases. GeneratorHelper’s batch path already sets exact: true; this single-package path needs the same treatment.

Apply this diff to keep the versions aligned:

-          if dev
-            pj.manager.add(packages_array, type: :dev)
-          else
-            pj.manager.add(packages_array)
+          if dev
+            pj.manager.add(packages_array, type: :dev, exact: true)
+          else
+            pj.manager.add(packages_array, exact: true)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def add_js_dependency(package, dev: false)
pj = package_json
return false unless pj
begin
# Ensure package is in array format for package_json gem
packages_array = [package]
if dev
pj.manager.add(packages_array, type: :dev)
else
pj.manager.add(packages_array)
end
true
def add_js_dependency(package, dev: false)
pj = package_json
return false unless pj
begin
# Ensure package is in array format for package_json gem
packages_array = [package]
if dev
pj.manager.add(packages_array, type: :dev, exact: true)
else
pj.manager.add(packages_array, exact: true)
end
true
🤖 Prompt for AI Agents
In lib/generators/react_on_rails/js_dependency_manager.rb around lines 206 to
218, the add_js_dependency method calls pj.manager.add without passing exact:
true, causing package_json to record caret ranges; update both pj.manager.add
calls (dev and non-dev branches) to include exact: true (e.g.,
pj.manager.add(packages_array, type: :dev, exact: true) and
pj.manager.add(packages_array, exact: true)) so the npm package is pinned to the
gem’s exact version.

justin808 and others added 5 commits November 16, 2025 21:20
- Restore version validation for pre-release versions in add_react_on_rails_package
- Clarify TypeScript dependencies comment for SWC-first approach
- Add explanatory comment about package_json availability
- Fix test mocks to match actual implementation using add_npm_dependencies
- Remove stale react-on-rails@^16.1.0 entry from yarn.lock

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

Co-Authored-By: Claude <[email protected]>
## Summary
- Replace deprecated scss-lint with modern stylelint
- Remove scss_lint gem dependency and configuration files
- Add stylelint and stylelint-config-standard-scss npm packages
- Create .stylelintrc.json configuration matching original scss-lint
rules
- Update rake tasks to use stylelint instead of scss-lint
- Add stylelint to CI workflow (lint-js-and-ruby.yml)
- Include SCSS linting in main rake lint task and autofix task
- Add yarn script 'lint:scss' for running stylelint

## Configuration Philosophy
Maintains the original minimal approach - only enables essential CSS
validation rules while disabling formatting rules, matching the original
scss-lint configuration philosophy.

## Test Plan
- [x] Stylelint runs without errors on all SCSS files
- [x] Configuration disables unwanted formatting rules
- [x] Rake tasks work correctly with new linter
- [x] CI integration functions properly

Fixes #1688

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

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg"
height="34" align="absmiddle"
alt="Reviewable"/>](https://reviewable.io/reviews/shakacode/react_on_rails/1825)
<!-- Reviewable:end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- Chores
- Migrated SCSS linting from the legacy linter to Stylelint with the
standard SCSS config.
- Added Stylelint dev dependencies, a lint:scss script and autofix
support.
- Updated lint tasks and Docker orchestration to run Stylelint alongside
other linters.
- Removed legacy SCSS linter configuration, development dependency and
binstub.
  - Added ignore patterns to scope Stylelint to relevant files.

- CI
  - Added a CI step to run SCSS linting with Stylelint.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Justin Gordon <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Justin Gordon <[email protected]>
## Summary

Replaces the `spec/dummy/bin/dev` symlink with a wrapper script that
passes `--route=/` to the base dev script.

## Problem

The `spec/dummy/bin/dev` was a symlink to the template script at
`lib/generators/react_on_rails/templates/base/base/bin/dev`, which
defaults to `DEFAULT_ROUTE = "hello_world"`. This is incorrect for the
dummy app which needs to use the root route `/`.

## Solution

Replace the symlink with a wrapper script that:
- Calls the base dev script
- Forces `--route=/` for the dummy app
- Passes through all other command-line arguments

## Test Plan

- Verified `bundle exec rubocop` passes with no offenses
- Verified `bin/dev --help` works correctly in spec/dummy
- Verified file is executable and has correct permissions

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

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg"
height="34" align="absmiddle"
alt="Reviewable"/>](https://reviewable.io/reviews/shakacode/react_on_rails/2029)
<!-- Reviewable:end -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated internal development script configuration to improve
development environment setup.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude <[email protected]>
…f webpack_loader

- Rename webpack_loader to javascript_transpiler (Shakapacker 9.3+ standard)
- Add assets_bundler configuration option
- Update comments to reflect current Shakapacker API
- Add note about automatic SWC usage with rspack

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

Co-Authored-By: Claude <[email protected]>
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

♻️ Duplicate comments (1)
lib/generators/react_on_rails/js_dependency_manager.rb (1)

216-227: Still need to pin the npm package version in add_js_dependency (duplicate of prior feedback)

add_js_dependency still calls pj.manager.add without exact: true, so react-on-rails@#{ReactOnRails::VERSION} will be recorded as a caret range (e.g. ^16.2.0), while add_npm_dependencies already pins versions exactly. That breaks the intent of keeping the npm package in lockstep with the gem version.

Align this single-package path with the batch helper:

       # Ensure package is in array format for package_json gem
       packages_array = [package]
       if dev
-        pj.manager.add(packages_array, type: :dev)
+        pj.manager.add(packages_array, type: :dev, exact: true)
       else
-        pj.manager.add(packages_array)
+        pj.manager.add(packages_array, exact: true)
       end

You can confirm how package_json records the specifier by running the generator and inspecting package.json to ensure react-on-rails is added with an exact version (no leading ^).

🧹 Nitpick comments (1)
package.json (1)

3-3: Stylelint deps and lint:scss script are correctly configured; refactoring to centralize glob patterns is optional

Verification confirms the added devDependencies and lint:scss script are set up correctly. The glob patterns match exactly between the package.json script and stylelint_command in rakelib/lint.rake. To reduce duplication and keep glob patterns centralized, you could optionally refactor the Rake task to call yarn run lint:scss instead of hardcoding the same patterns. This is a recommended improvement but not required for functionality.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 29f2b61 and a642b66.

⛔ Files ignored due to path filters (5)
  • Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/Gemfile.lock is excluded by !**/*.lock
  • react_on_rails_pro/spec/dummy/Gemfile.lock is excluded by !**/*.lock
  • spec/dummy/Gemfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (19)
  • .github/workflows/lint-js-and-ruby.yml (1 hunks)
  • .scss-lint.yml (0 hunks)
  • .stylelintrc.json (1 hunks)
  • Gemfile.development_dependencies (0 hunks)
  • knip.ts (2 hunks)
  • lib/generators/react_on_rails/js_dependency_manager.rb (1 hunks)
  • lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml (1 hunks)
  • lib/react_on_rails/version.rb (1 hunks)
  • package.json (3 hunks)
  • packages/react-on-rails-pro/package.json (2 hunks)
  • packages/react-on-rails/package.json (1 hunks)
  • rakelib/docker.rake (1 hunks)
  • rakelib/lint.rake (1 hunks)
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb (1 hunks)
  • react_on_rails_pro/package.json (1 hunks)
  • react_on_rails_pro/spec/dummy/bin/dev (1 hunks)
  • spec/dummy/bin/dev (0 hunks)
  • spec/dummy/bin/dev (1 hunks)
  • spec/dummy/bin/scss-lint (0 hunks)
💤 Files with no reviewable changes (3)
  • Gemfile.development_dependencies
  • .scss-lint.yml
  • spec/dummy/bin/scss-lint
✅ Files skipped from review due to trivial changes (2)
  • rakelib/docker.rake
  • spec/dummy/bin/dev
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: alexeyr-ci
Repo: shakacode/react_on_rails PR: 1687
File: spec/dummy/package.json:0-0
Timestamp: 2025-01-23T18:20:45.824Z
Learning: When adding or updating dependencies in spec/dummy/package.json, maintain version consistency with other package.json files in the codebase to avoid potential version conflicts.
📚 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_pro/package.json
  • react_on_rails_pro/spec/dummy/bin/dev
  • package.json
  • packages/react-on-rails-pro/package.json
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • packages/react-on-rails/package.json
  • knip.ts
  • spec/dummy/bin/dev
📚 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_pro/package.json
  • react_on_rails_pro/spec/dummy/bin/dev
  • package.json
  • packages/react-on-rails-pro/package.json
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • packages/react-on-rails/package.json
  • knip.ts
  • spec/dummy/bin/dev
📚 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_pro/package.json
  • packages/react-on-rails-pro/package.json
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.rb
  • lib/generators/react_on_rails/js_dependency_manager.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_pro/package.json
  • react_on_rails_pro/spec/dummy/bin/dev
  • package.json
  • packages/react-on-rails-pro/package.json
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • .stylelintrc.json
  • lib/react_on_rails/version.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • packages/react-on-rails/package.json
  • rakelib/lint.rake
  • knip.ts
📚 Learning: 2025-01-23T18:20:45.824Z
Learnt from: alexeyr-ci
Repo: shakacode/react_on_rails PR: 1687
File: spec/dummy/package.json:0-0
Timestamp: 2025-01-23T18:20:45.824Z
Learning: When adding or updating dependencies in spec/dummy/package.json, maintain version consistency with other package.json files in the codebase to avoid potential version conflicts.

Applied to files:

  • react_on_rails_pro/package.json
  • package.json
  • packages/react-on-rails-pro/package.json
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • packages/react-on-rails/package.json
📚 Learning: 2024-12-12T13:07:09.929Z
Learnt from: alexeyr-ci
Repo: shakacode/react_on_rails PR: 1644
File: node_package/src/ReactOnRailsRSC.ts:87-87
Timestamp: 2024-12-12T13:07:09.929Z
Learning: When handling errors in 'node_package/src/ReactOnRailsRSC.ts', include the error stack in error messages in development and test environments to aid debugging.

Applied to files:

  • react_on_rails_pro/package.json
  • packages/react-on-rails-pro/package.json
📚 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_pro/package.json
  • packages/react-on-rails-pro/package.json
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
📚 Learning: 2024-10-08T20:53:47.076Z
Learnt from: theforestvn88
Repo: shakacode/react_on_rails PR: 1620
File: spec/dummy/client/app/startup/HelloTurboStream.jsx:3-3
Timestamp: 2024-10-08T20:53:47.076Z
Learning: The `RailsContext` import in `spec/dummy/client/app/startup/HelloTurboStream.jsx` is used later in the project, as clarified by the user theforestvn88.

Applied to files:

  • react_on_rails_pro/spec/dummy/bin/dev
📚 Learning: 2025-09-25T17:44:48.481Z
Learnt from: ihabadham
Repo: shakacode/react_on_rails PR: 1825
File: package.json:74-75
Timestamp: 2025-09-25T17:44:48.481Z
Learning: stylelint-config-standard-scss automatically includes stylelint-scss as a transitive dependency through stylelint-config-recommended-scss, so there's no need to add stylelint-scss explicitly to devDependencies when using stylelint-config-standard-scss.

Applied to files:

  • package.json
  • .stylelintrc.json
  • .github/workflows/lint-js-and-ruby.yml
  • rakelib/lint.rake
📚 Learning: 2025-02-13T16:50:47.848Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: node_package/src/clientStartup.ts:18-21
Timestamp: 2025-02-13T16:50:47.848Z
Learning: In the react_on_rails module, the `reactOnRailsPageUnloaded` function in clientStartup.ts is intentionally kept private as it's only used internally as a callback for `onPageUnloaded`.

Applied to files:

  • package.json
  • packages/react-on-rails-pro/package.json
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.rb
  • packages/react-on-rails/package.json
📚 Learning: 2025-09-15T21:24:48.207Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1781
File: node_package/src/ClientSideRenderer.ts:82-95
Timestamp: 2025-09-15T21:24:48.207Z
Learning: In React on Rails, the force_load feature includes both explicit `data-force-load="true"` usage and the ability to hydrate components during the page loading state (`document.readyState === 'loading'`). Both capabilities require a Pro license, so the condition `!railsContext.rorPro && (isComponentForceLoaded || document.readyState === 'loading')` correctly gates both scenarios.

Applied to files:

  • packages/react-on-rails-pro/package.json
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.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:

  • packages/react-on-rails-pro/package.json
  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
📚 Learning: 2025-02-13T19:09:15.991Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: node_package/src/RSCWebpackLoader.ts:0-0
Timestamp: 2025-02-13T19:09:15.991Z
Learning: In React Server Components webpack loader, using `new Function('return import("react-server-dom-webpack/node-loader")')()` is necessary as a workaround to bypass TypeScript compilation issues with direct dynamic imports.

Applied to files:

  • packages/react-on-rails-pro/package.json
  • knip.ts
📚 Learning: 2025-02-13T16:50:26.861Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1644
File: node_package/src/turbolinksUtils.ts:34-36
Timestamp: 2025-02-13T16:50:26.861Z
Learning: In React on Rails, when checking for Turbolinks version 5 using `turbolinksVersion5()`, always ensure `Turbolinks` exists first by checking `turbolinksInstalled()` to prevent TypeError when accessing properties.

Applied to files:

  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.rb
  • lib/generators/react_on_rails/js_dependency_manager.rb
  • packages/react-on-rails/package.json
📚 Learning: 2025-04-09T12:56:10.756Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1696
File: node_package/src/RSCPayloadContainer.ts:0-0
Timestamp: 2025-04-09T12:56:10.756Z
Learning: In the react_on_rails codebase, RSC payloads are already stringified using `JSON.stringify()` before being processed by the `escapeScript` function, which handles escaping of special characters. The function only needs to handle specific HTML markers like comments and closing script tags.

Applied to files:

  • react_on_rails_pro/lib/react_on_rails_pro/version.rb
  • lib/react_on_rails/version.rb
🧬 Code graph analysis (1)
lib/generators/react_on_rails/js_dependency_manager.rb (1)
lib/generators/react_on_rails/generator_helper.rb (2)
  • package_json (7-20)
  • add_npm_dependencies (23-39)
🔇 Additional comments (12)
react_on_rails_pro/package.json (1)

3-3: LGTM! Version bump is consistent across the codebase.

The version update from 16.2.0-beta.4 to 16.2.0-beta.5 aligns with the coordinated version bumps across all related packages (packages/react-on-rails/package.json, packages/react-on-rails-pro/package.json, lib/react_on_rails/version.rb, and react_on_rails_pro/lib/react_on_rails_pro/version.rb).

packages/react-on-rails/package.json (1)

3-3: LGTM! Version bump is consistent.

The version update aligns with the coordinated beta release across the codebase.

react_on_rails_pro/spec/dummy/bin/dev (1)

1-5: LGTM! Clean delegation pattern.

The script correctly delegates to the centralized base dev script using exec and forwards arguments appropriately. The relative path is correct for this file's location.

packages/react-on-rails-pro/package.json (1)

3-3: LGTM! Version and dependency updates are synchronized.

Both the package version and the react-on-rails dependency are correctly updated to 16.2.0-beta.5, maintaining consistency across the monorepo.

Also applies to: 59-59

spec/dummy/bin/dev (1)

1-5: LGTM! Consistent delegation pattern.

The script correctly delegates to the base dev script with the appropriate relative path for this location and forwards arguments properly.

react_on_rails_pro/lib/react_on_rails_pro/version.rb (1)

4-4: LGTM! Ruby version constant updated consistently.

The VERSION constant is correctly bumped to match the package.json version updates across the codebase.

lib/react_on_rails/version.rb (1)

4-4: LGTM! Ruby version constant updated consistently.

The VERSION constant matches the coordinated version bump across all packages.

knip.ts (2)

129-134: LGTM! Appropriate ignore patterns for dynamically loaded code.

These ignore patterns correctly exclude React on Rails components that are registered and loaded dynamically at runtime, which Knip cannot trace through static analysis.


165-176: LGTM! Valid dependencies for production builds.

The added dependencies are all legitimate runtime or transitive dependencies that Knip's static analysis doesn't detect:

  • Build tooling: @babel/runtime, mini-css-extract-plugin, css-loader, sass, sass-loader
  • Runtime libraries: create-react-class, react-helmet, @types/react-helmet, react-redux, react-router-dom

These align with the PR's centralized dependency management and the dynamic nature of React on Rails component registration.

.stylelintrc.json (1)

1-45: SCSS lint configuration looks reasonable and aligned with the new tooling

Extending the SCSS preset and relaxing the pattern rules/ignoreFiles to match existing code is consistent and should keep noise low while still enforcing basics; no changes needed from my side.

lib/generators/react_on_rails/js_dependency_manager.rb (1)

40-89: Dependency sets and SWC/TypeScript separation look consistent with Shakapacker’s role

The React/CSS/dev/Rspack/TypeScript dependency groups, plus the comments about SWC as the default transpiler and omitting Babel presets/@babel/preset-typescript, line up well with shakapacker.yml being the source of truth for loader/transpiler choice. The conditional use of RSPACK_DEV_DEPENDENCIES when options.rspack? is set and dev-only TypeScript deps via add_typescript_dependencies also look correct.

If you’d like, verify the generated app’s package.json for both webpack and rspack + TypeScript combinations to ensure the expected packages appear in the right (dev vs prod) sections.

Also applies to: 140-205

.github/workflows/lint-js-and-ruby.yml (1)

137-138: CI SCSS lint step is correctly wired and placed

The yarn run lint:scss command is properly defined in package.json, uses the correct stylelint and stylelint-config-standard-scss dependencies, and the file glob patterns reference existing directories. No configuration issues found.

require_relative "task_helpers"

namespace :lint do
namespace :lint do # rubocop:disable Metrics/BlockLength
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Rake stylelint integration works; consider reusing the Yarn script and updating descriptions

The new scss task and autofix hooks are functionally solid. Two small maintainability ideas:

  • To avoid duplicated glob patterns between Rake and package.json, you could make stylelint_command simply run yarn run lint:scss and stylelint_fix_command run yarn run lint:scss --fix, letting the script own the file list.
  • The top-level autofix task description still only mentions eslint/prettier/rubocop; consider updating it to mention SCSS/stylelint now that stylelint_fix_command runs as well.

You can verify behavior after such a change with:

Also applies to: 13-16, 23-25, 32-45


🏁 Script executed:

#!/bin/bash
bundle exec rake lint:scss
bundle exec rake autofix

Length of output: 89


🏁 Script executed:

#!/bin/bash
# Examine the lint.rake file to see the current implementation
cat rakelib/lint.rake

Length of output: 1418


🏁 Script executed:

#!/bin/bash
# Check if package.json exists and look for lint:scss script
cat package.json | grep -A 20 '"scripts"'

Length of output: 939


🏁 Script executed:

#!/bin/bash
# Search for any yarn/npm scripts related to stylelint
rg -i 'stylelint|lint:scss' package.json

Length of output: 187


🏁 Script executed:

#!/bin/bash
# Look for the glob patterns used in rake file
rg -n 'glob|@' rakelib/lint.rake

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check the exact content around lines 5, 13-16, 23-25, 32-45
sed -n '1,50p' rakelib/lint.rake

Length of output: 1303


🏁 Script executed:

#!/bin/bash
# Look for any documentation or comments about autofix
rg -n 'autofix|description' rakelib/lint.rake -C2

Length of output: 309


🏁 Script executed:

#!/bin/bash
# Check if there's a Gemfile to understand rake setup
cat Gemfile | grep -i rake

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for all task descriptions to see if autofix is mentioned
rg -n 'task|desc' rakelib/lint.rake

Length of output: 588


🏁 Script executed:

#!/bin/bash
# Find the complete autofix implementation
ast-grep --pattern 'task :autofix'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for stylelint_command and stylelint_fix_command definitions
rg -n 'stylelint_command|stylelint_fix_command' rakelib/lint.rake

Length of output: 189


Update autofix description to include stylelint, and optionally refactor to reuse the Yarn script

The review comment is valid. Two concrete issues found:

  1. Line 51 — Incomplete description: The global autofix task description omits stylelint/scss, though the task itself calls stylelint_fix_command on line 32. Update to: "Auto-fix all linting violations (eslint --fix, prettier --write, rubocop -A, stylelint --fix)".

  2. Lines 39–40 — Glob pattern duplication: The glob patterns in stylelint_command are identical to the lint:scss script in package.json. Consider refactoring stylelint_command to call yarn run lint:scss and stylelint_fix_command to call yarn run lint:scss --fix, letting package.json own the file list.

🤖 Prompt for AI Agents
In rakelib/lint.rake around lines 5 and 39–51: update the global autofix task
description on line 51 to read "Auto-fix all linting violations (eslint --fix,
prettier --write, rubocop -A, stylelint --fix)" to accurately include stylelint,
and refactor the stylelint_command and stylelint_fix_command (lines ~39–40 and
~32) to invoke the package.json script instead of duplicating globs—replace the
direct stylelint invocations with calls to "yarn run lint:scss" and "yarn run
lint:scss --fix" respectively so the file list is maintained in package.json.

@justin808
Copy link
Member Author

Closing this PR in favor of #2051 which has a clean branch without merge conflicts.

The new PR contains the same JS dependency manager refactoring changes, just on a fresh branch created from the latest master.

@justin808 justin808 closed this Nov 18, 2025
justin808 added a commit that referenced this pull request Nov 19, 2025
## Summary

This PR refactors JavaScript dependency management in React on Rails
generators by extracting duplicated code into a shared
`JsDependencyManager` module.

## Changes

- **Eliminates ~270 lines of duplicated code** between `BaseGenerator`
and `InstallGenerator`
- **Centralizes dependency definitions** in frozen constants with clear
documentation
- **Removes Babel dependencies** that are now managed by Shakapacker
- **Changes default transpiler to SWC** in generated shakapacker.yml for
better performance
- **Adds comprehensive test coverage** for the new module
- **Simplifies dependency installation flow** using package_json gem

## Key Improvements

### Code Organization
- All JS dependencies are now defined as frozen constants
(REACT_DEPENDENCIES, CSS_DEPENDENCIES, etc.)
- Clear separation of concerns with well-documented module
- Consistent error handling across all generators

### Dependency Management
- Leverages package_json gem (always available via Shakapacker) for
reliable cross-platform package management
- Removes Babel-related packages that Shakapacker now handles
automatically
- Adds support for Rspack and TypeScript dependencies

### Default Configuration
- ⚠️ **Breaking Change**: Default `webpack_loader` changed from
`'babel'` to `'swc'` in generated shakapacker.yml
- SWC provides better performance and has built-in TypeScript support
- Users who need Babel can still configure it manually

## Testing

New test file
`spec/react_on_rails/generators/message_deduplication_spec.rb` verifies:
- No duplicate post-install messages
- Proper module inclusion in both generators
- Correct dependency installation flow

## Migration Notes

For new installations, this change is transparent. Existing projects are
not affected as this only impacts the generator output for new setups.

---

Supersedes and closes #2030 (that PR had merge conflict issues, so
starting fresh with a clean branch)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Centralized JavaScript dependency management across generators for
more consistent installation and simplified generator behavior.

* **Configuration**
* Installer config adds javascript_transpiler and assets_bundler
options; previous webpack-specific key removed.

* **Tests**
* New specs for post-install messages, message deduplication, and JS
dependency flows to validate installation messaging and dependency
handling.

* **Changelog**
* Generator no longer auto-installs Babel presets; SWC is the default
transpiler and Babel must be added manually.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude <[email protected]>
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.

3 participants