-
-
Notifications
You must be signed in to change notification settings - Fork 638
Move React/Shakapacker version compatibility to generator smoke tests #2125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Caution Review failedAn error occurred during the review process. Please try again later. WalkthroughThe PR implements minimum-version compatibility testing for React 18.0.0 and Shakapacker 8.2.0 in separate generator example apps, keeping Changes
Sequence Diagram(s)sequenceDiagram
participant CI as CI Workflow
participant Latest as Latest Examples
participant Minimum as Minimum Examples
CI->>Latest: Run shakapacker_examples_latest
Latest->>Latest: Load examples with minimum_versions=false
Latest->>Latest: Run RSpec with bundled deps
Latest-->>CI: ✓ Tests pass (React 19, Shakapacker latest)
CI->>Minimum: Run shakapacker_examples_minimum
Minimum->>Minimum: Load examples with minimum_versions=true
Minimum->>Minimum: apply_minimum_versions() in generated app
Minimum->>Minimum: Pin React 18.0.0, Shakapacker 8.2.0
Minimum->>Minimum: Run RSpec with unbundled deps
Minimum-->>CI: ✓ Tests pass (React 18, Shakapacker 8.2.0)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code Review - PR #2125: Move React/Shakapacker version compatibility to generator smoke tests✅ Overall AssessmentThis is a well-structured refactoring that improves the testing strategy by separating version compatibility testing from integration tests. The approach is sound and aligns with the original issue #2123 objectives. 🎯 Strengths1. Clear Separation of Concerns
2. Cleaner CI Configuration
3. Better Real-World Representation
4. Code Quality
|
Code Review - PR #2125OverviewThis PR successfully refactors React/Shakapacker version compatibility testing from spec/dummy to generator smoke tests. The approach is clean and improves the separation of concerns. Overall, this is well-structured with good benefits. ✅ Strengths
|
Code Review - PR #2125I've reviewed the changes for moving React/Shakapacker version compatibility testing to generator smoke tests. Overall, this is a well-structured refactoring that improves the separation of concerns. Here's my detailed feedback: ✅ Strengths
🔍 Observations & Suggestions1. Testing CoverageThe PR description mentions:
Suggestion: Before merging, verify the CI workflow runs as expected. Consider testing locally with: # Simulate the CI environment
cd react_on_rails
bundle exec rake run_rspec:shakapacker_examples_latest
bundle exec rake run_rspec:shakapacker_examples_minimum2. Potential Edge Case in
|
Code Review - PR #2125SummaryThis PR successfully moves React/Shakapacker version compatibility testing from spec/dummy to generator smoke tests. The overall approach is sound and aligns well with the project's testing strategy. ✅ Strengths
🔍 Issues & Concerns1. CRITICAL: Missing attr_reader and minimum_versions? methodIn attr_reader :packer_type, :name, :generator_options, :minimum_versionsBut the current file only has: attr_reader :packer_type, :name, :generator_optionsThe
Required fix: attr_reader :packer_type, :name, :generator_options, :minimum_versions
def initialize(packer_type: nil, name: nil, generator_options: nil, minimum_versions: false)
@packer_type = packer_type
@name = name
@generator_options = generator_options
@minimum_versions = minimum_versions
self.class.all[packer_type.to_sym] << self
end
def minimum_versions?
@minimum_versions
end2. Missing run_rspec.rake changesThe PR diff shows new rake tasks should be added to
These changes are not in the current file. Without these:
Required fix: Add the rake tasks as shown in the PR diff. 3. Missing shakapacker_examples.rake changesThe PR diff shows a new
This code is not present in the current file. Required fix: Add the 4. Missing examples_config.yml entriesThe current # Missing from current file:
- name: basic-minimum
generator_options: ''
minimum_versions: true
- name: basic-server-rendering-minimum
generator_options: --example-server-rendering
minimum_versions: trueWithout these entries, no minimum version examples will be generated. 🐛 Potential Bugs5. Predicate method naming inconsistencyIn def latest_examples
ExampleType.all[:shakapacker_examples].reject(&:minimum_versions)
end
def minimum_examples
ExampleType.all[:shakapacker_examples].select(&:minimum_versions)
endThis calls
The symbol-to-proc syntax 6. JSON formatting in apply_minimum_versionsThe PR adds: File.write(package_json_path, "\#{JSON.pretty_generate(package_json)}\n")Good: This preserves consistent formatting with a trailing newline (as required by CLAUDE.md). 📝 Code Quality7. Constants placement is goodThe minimum version constants are well-placed: MINIMUM_REACT_VERSION = "18.0.0"
MINIMUM_SHAKAPACKER_VERSION = "8.2.0"These make it easy to update supported versions in the future. 8. Script/convert simplificationThe removal of React/Shakapacker logic from ⚡ Performance ConsiderationsNo performance concerns. The changes are primarily organizational and don't introduce performance overhead. 🔒 Security ConcernsNo security issues identified. The changes involve:
All are low-risk from a security perspective. 🧪 Test CoverageMissing verification:According to the PR description test plan:
The last item is unchecked, but it's the most critical one! Before merging, you should:
🎯 RecommendationsMust fix before merge:
Nice to have:
📋 Checklist for AuthorBefore marking as ready to merge:
💡 Overall AssessmentArchitecture: Excellent - The separation of concerns is much cleaner. Implementation: Incomplete - Several critical code changes are missing. This appears to be an issue with the PR branch not containing all the changes shown in the diff, or the diff was generated from a different state than what's currently in the branch. Recommendation: Request changes - The PR cannot be merged until all the missing code is added and tested locally. Great work on the design! Just need to ensure all the implementation is present. 🚀 |
Code Review - PR #2125Great work on separating version compatibility testing from spec/dummy! This is a cleaner architecture. Here's my detailed review: ✅ Strengths
🔍 Issues & Suggestions1. Missing
|
Code Review - PR #2125Overall Assessment: This is a well-structured refactoring that improves the separation of concerns between spec/dummy integration tests and generator smoke tests. The approach is cleaner and more maintainable. ✅ ✅ Strengths
🔍 Issues & Concerns1. Potential Race Condition in Rake Task (CRITICAL)Location: def latest_examples
ExampleType.all[:shakapacker_examples].reject(&:minimum_versions)
end
def minimum_examples
ExampleType.all[:shakapacker_examples].select(&:minimum_versions)
endProblem: These helper methods are defined at the top level of the Recommendation: Move the filtering logic into the task bodies or use lambdas: desc "Runs Rspec for latest version example apps only"
task shakapacker_examples_latest: "shakapacker_examples:gen_all" do
latest_examples = ExampleType.all[:shakapacker_examples].reject(&:minimum_versions)
latest_examples.each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
endOr ensure 2. Silent Failure Risk in
|
Code Review - PR #2125SummaryThis PR successfully moves React and Shakapacker version compatibility testing from spec/dummy to generator smoke tests. The approach is sound and aligns well with the suggested improvements from PR #2114. ✅ Strengths1. Clear Separation of ConcernsThe PR correctly separates:
This makes the testing strategy much clearer and easier to maintain. 2. Good Architectural Design
3. Simplified CI Logic
4. Proper Version Updates
🔍 Observations & Questions1. Task Invocation Pattern (Minor)In task shakapacker_examples: "shakapacker_examples:gen_all" do
ExampleType.all[:shakapacker_examples].each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
endThis runs ALL examples (both latest and minimum). Is this intentional? The new tasks Recommendation: Consider whether
2. Dependency Generation OrderIn sh_in_dir(example_type.dir, generator_commands)
# Apply minimum versions for compatibility testing examples
apply_minimum_versions(example_type.dir) if example_type.minimum_versions
sh_in_dir(example_type.dir, "npm install")The 3. Error Handling in JSON ParsingThe rescue JSON::ParserError => e
puts " ERROR: Failed to parse package.json in #{dir}: #{e.message}"
raise
endGood defensive programming! ✅ 4. Workflow Step NamesThe workflow step names were updated from:
To:
This is a good clarification! ✅ 🔒 Security & Performance
📋 Test CoverageBased on the PR description, the following are marked as complete:
Recommendation: Once CI passes, verify that:
🎯 Overall AssessmentLGTM with minor clarification needed on the This is a well-structured PR that:
RecommendationOnce CI passes and the question about 🤖 Generated with Claude Code |
Code Review - PR #2125✅ Overall AssessmentThis is a well-designed refactoring that improves the test architecture by separating concerns: spec/dummy now tests latest versions, while generators test the compatibility matrix. All CI checks are passing. Strengths1. Excellent Separation of Concerns ✨
2. Clean Implementation
3. Improved CI Organization
4. Good Documentation
Issues & Recommendations
|
Code Review for PR #2125SummaryThis PR successfully refactors version compatibility testing from spec/dummy to dedicated generator smoke test examples. The approach is clean and follows the project's architecture well. ✅ Strengths
🔍 Issues Found1. CRITICAL: Missing Implementation in
|
Review Comments AddressedThank you for the thorough reviews! All the issues mentioned have been addressed in the commits on this branch: ✅ All Critical Issues Resolved
Files Ready for Review
All RuboCop violations have been fixed and the code follows project conventions. |
Code Review: Move React/Shakapacker version compatibility to generator smoke testsOverall Assessment✅ Strong refactoring - This PR successfully separates concerns by moving version compatibility testing from spec/dummy to generator smoke tests. The approach is cleaner and more maintainable. Code Quality & Best Practices✅ Excellent Structure
✅ Helper Methodsdef latest_examples
ExampleType.all[:shakapacker_examples].reject(&:minimum_versions?)
end
def minimum_examples
ExampleType.all[:shakapacker_examples].select(&:minimum_versions?)
endThese filtering methods (lines 94-100 in run_rspec.rake) are clean and readable. 💡 Minor Suggestion - Method LocationThe helper methods
Potential Issues
|
There was a problem hiding this 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 (1)
package.json (1)
31-32: Update@types/reactand@types/react-domto v19 to match React 19 runtime.TypeScript types must be updated when upgrading to React 19. Install @types/react@^19.0.0 and @types/react-dom@^19.0.0. React 19 includes significant TypeScript type changes, with removed types and cleanups that require matching type definitions.
Mismatched versions (v18 types with v19 runtime) prevent builds and cause errors like "It looks like you're trying to use TypeScript but do not have the required package(s) installed." Update lines 31-32 in
package.jsonand align with the correct versions already used inspec/dummy/package.json.
🧹 Nitpick comments (2)
script/convert (1)
15-21: Fallback path logic only handles Gemfile, not package.json.The fallback from
/react_on_rails/Gemfileto/Gemfile(line 19) doesn't apply to the package.json paths used throughout this script. If backward compatibility with the old repository layout is needed for package.json files, consider generalizing the pattern:- old_path = path.sub(%r{/react_on_rails/Gemfile}, "/Gemfile") + # Try removing react_on_rails/ prefix for old layout compatibility + old_path = path.sub(%r{/react_on_rails/}, "/")Alternatively, if the Gemfile fallback is no longer needed, the entire block could be removed to simplify the code.
react_on_rails/rakelib/run_rspec.rake (1)
93-100: Consider moving helper methods earlier in the namespace for better organization.The helper methods work correctly, using
rejectandselectwith theminimum_versions?predicate to filter examples. However, for better readability, consider moving these helpers to the top of the namespace block (after line 12) before they're used.namespace :run_rspec do include ReactOnRails::TaskHelpers + + # Helper methods for filtering examples + def latest_examples + ExampleType.all[:shakapacker_examples].reject(&:minimum_versions?) + end + + def minimum_examples + ExampleType.all[:shakapacker_examples].select(&:minimum_versions?) + end # Loads data from examples_config.yml and instantiates corresponding ExampleType objects examples_config_file = File.expand_path("examples_config.yml", __dir__)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
react_on_rails/spec/dummy/yarn.lockis excluded by!**/yarn.lock,!**/*.lockyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (9)
.github/workflows/examples.yml(2 hunks).github/workflows/integration-tests.yml(2 hunks)package.json(1 hunks)react_on_rails/rakelib/example_type.rb(1 hunks)react_on_rails/rakelib/examples_config.yml(1 hunks)react_on_rails/rakelib/run_rspec.rake(1 hunks)react_on_rails/rakelib/shakapacker_examples.rake(2 hunks)react_on_rails/spec/dummy/package.json(1 hunks)script/convert(2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
**/*: CRITICAL: Ensure all files end with a newline character
When making changes to directory structure or file paths, run comprehensive grep searches to find all affected files before committing:grep -r 'old/path' . --exclude-dir=node_modules --exclude-dir=.git
Files:
package.jsonreact_on_rails/spec/dummy/package.jsonreact_on_rails/rakelib/examples_config.ymlreact_on_rails/rakelib/shakapacker_examples.rakereact_on_rails/rakelib/example_type.rbreact_on_rails/rakelib/run_rspec.rakescript/convert
**/*.{js,jsx,ts,tsx,json,yaml,yml,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
NEVER manually format code - let Prettier and RuboCop handle ALL formatting automatically via
rake autofix
Files:
package.jsonreact_on_rails/spec/dummy/package.jsonreact_on_rails/rakelib/examples_config.yml
package.json
📄 CodeRabbit inference engine (CLAUDE.md)
Never run
npmcommands - only use equivalent Yarn Classic commands
Files:
package.json
.github/workflows/*.yml
📄 CodeRabbit inference engine (CLAUDE.md)
When modifying CI workflows, test all changes locally first via manual execution of equivalent commands before pushing - CI iteration is expensive (10-30 min/cycle)
Files:
.github/workflows/integration-tests.yml.github/workflows/examples.yml
**/*.rb
📄 CodeRabbit inference engine (CLAUDE.md)
CRITICAL: Always run
bundle exec rubocopand fix ALL violations before every commit/push
Files:
react_on_rails/rakelib/example_type.rb
🧠 Learnings (18)
📓 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-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to react_on_rails_pro/**/*.{js,jsx,ts,tsx,json,yaml,yml,css,scss} : The react_on_rails_pro directory has its own Prettier and ESLint configuration - CI lints both directories separately
Applied to files:
package.jsonreact_on_rails/spec/dummy/package.jsonreact_on_rails/rakelib/examples_config.ymlreact_on_rails/rakelib/shakapacker_examples.rakescript/convert
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to packages/react-on-rails/src/**/*.{ts,tsx} : TypeScript files in the npm package must be compiled to JavaScript in `packages/react-on-rails/lib/` via `yarn run build`
Applied to files:
package.json.github/workflows/integration-tests.ymlreact_on_rails/spec/dummy/package.jsonreact_on_rails/rakelib/examples_config.ymlreact_on_rails/rakelib/shakapacker_examples.rakereact_on_rails/rakelib/example_type.rbreact_on_rails/rakelib/run_rspec.rakescript/convert
📚 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:
package.jsonreact_on_rails/spec/dummy/package.jsonreact_on_rails/rakelib/examples_config.ymlreact_on_rails/rakelib/example_type.rbscript/convert
📚 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:
package.jsonreact_on_rails/spec/dummy/package.jsonreact_on_rails/rakelib/examples_config.ymlreact_on_rails/rakelib/shakapacker_examples.rakereact_on_rails/rakelib/example_type.rbscript/convert
📚 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:
package.jsonreact_on_rails/spec/dummy/package.jsonreact_on_rails/rakelib/examples_config.ymlreact_on_rails/rakelib/shakapacker_examples.rakescript/convert
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to spec/react_on_rails/**/*.rb : Ruby unit tests should be located in `spec/react_on_rails/` and tested via `rake run_rspec:gem`
Applied to files:
package.jsonreact_on_rails/spec/dummy/package.jsonreact_on_rails/rakelib/examples_config.ymlreact_on_rails/rakelib/run_rspec.rakescript/convert
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Use `yalc` for local development when testing React on Rails with external applications - this allows local package linking without publishing to npm
Applied to files:
package.jsonreact_on_rails/spec/dummy/package.json
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: CRITICAL: For infrastructure/config changes affecting directory structure, build configs, or CI workflows, perform comprehensive local testing before pushing including: grep for affected files, test build pipeline, run relevant specs, and run full lint check
Applied to files:
.github/workflows/integration-tests.ymlreact_on_rails/rakelib/examples_config.yml.github/workflows/examples.ymlscript/convert
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to .github/workflows/*.yml : When modifying CI workflows, test all changes locally first via manual execution of equivalent commands before pushing - CI iteration is expensive (10-30 min/cycle)
Applied to files:
.github/workflows/integration-tests.yml.github/workflows/examples.yml
📚 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/spec/dummy/package.jsonreact_on_rails/rakelib/shakapacker_examples.rakescript/convert
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to lib/react_on_rails/**/*.rb : When creating new Ruby files in `lib/react_on_rails/`, create corresponding RBS signature file in `sig/react_on_rails/` and add to Steepfile for type checking
Applied to files:
react_on_rails/rakelib/examples_config.ymlreact_on_rails/rakelib/shakapacker_examples.rakereact_on_rails/rakelib/example_type.rbscript/convert
📚 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/rakelib/examples_config.ymlscript/convert
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to lib/generators/react_on_rails/**/*.rb : Rails generators run in host app context and should not assume specific project structure (e.g., `app/javascript/` may not exist) - use `Rails.root` for path resolution
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rakescript/convert
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to **/*.{js,jsx,ts,tsx,json,yaml,yml,css,scss} : NEVER manually format code - let Prettier and RuboCop handle ALL formatting automatically via `rake autofix`
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rakescript/convert
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: React on Rails is a Rails Engine - automatically loads all `.rake` files from `lib/tasks/` directory without explicit loading via `rake_tasks` block to avoid duplicate task execution
Applied to files:
react_on_rails/rakelib/run_rspec.rake
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to lib/tasks/*.rake : Rake tasks in lib/tasks/ are automatically loaded by Rails::Engine - verify tasks don't cause duplicate execution during `rake assets:precompile`
Applied to files:
react_on_rails/rakelib/run_rspec.rake
📚 Learning: 2025-11-25T04:54:35.286Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T04:54:35.286Z
Learning: Applies to spec/dummy/**/*.rb : Integration tests in the dummy app should be located in `spec/dummy/` and tested via `rake run_rspec:dummy`
Applied to files:
react_on_rails/rakelib/run_rspec.rake
⏰ 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). (7)
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: examples (3.4, latest)
- 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: build
- GitHub Check: claude-review
🔇 Additional comments (11)
react_on_rails/rakelib/example_type.rb (1)
16-31: LGTM!Clean implementation following Ruby conventions:
- Constants are appropriately scoped within the class
- Predicate method
minimum_versions?follows Ruby idioms- Default parameter
minimum_versions: falsemaintains backward compatibilityscript/convert (1)
40-51: LGTM!Appropriately skips RSC-related tests when running on React 18, as RSC requires React 19. The
exit 0no-op fortest:rscis a clean approach..github/workflows/integration-tests.yml (2)
135-137: LGTM!Step name accurately reflects the updated purpose of
script/convert(Node.js tooling compatibility rather than Shakapacker v6 support).
214-216: Consistent rename with the other workflow step.react_on_rails/rakelib/shakapacker_examples.rake (3)
11-11: LGTM!The
require "json"statement is necessary for the newapply_minimum_versionsmethod that parses and writes package.json files.
82-83: LGTM!The conditional invocation of
apply_minimum_versionscorrectly applies minimum version constraints only to examples marked withminimum_versions: true.
19-48: All dependencies verified and confirmed in place.The verification confirms:
minimum_versions?predicate is properly defined inExampleType(line 23 in example_type.rb)- Constants
MINIMUM_REACT_VERSION("18.0.0") andMINIMUM_SHAKAPACKER_VERSION("8.2.0") are defined (lines 17-18 in example_type.rb)- The
apply_minimum_versionsmethod correctly uses these constants to update package.json filesThe method logic is sound with appropriate error handling and safe navigation checks.
.github/workflows/examples.yml (2)
133-133: LGTM!The step name update accurately reflects the script's broader purpose of handling Node.js tooling compatibility.
175-180: Conditional CI workflow changes verified and correct.The conditional steps properly split testing based on
matrix.dependency-level. Verification confirms:
- Both rake tasks exist in
react_on_rails/rakelib/run_rspec.rake(lines 103, 108)- Matrix configuration properly defines
dependency-levelvalues as 'latest' and 'minimum' (line 81)- Conditional syntax correctly matches matrix values
- Environment setup responds appropriately to dependency-level (BUNDLE_FROZEN, line 105)
react_on_rails/rakelib/examples_config.yml (1)
10-16: LGTM!The new minimum-version test configurations are well-structured and clearly documented. The
minimum_versions: trueflag properly integrates with the new testing infrastructure to verify compatibility with React 18.0.0 and Shakapacker 8.2.0.react_on_rails/rakelib/run_rspec.rake (1)
102-110: LGTM!The new rake tasks properly separate latest and minimum version testing. The task structure is consistent with existing patterns, correctly setting up dependencies on generation tasks and invoking RSpec for the appropriate example subsets.
Code ReviewThis is a well-structured PR that successfully moves React/Shakapacker version compatibility testing from spec/dummy to generator smoke tests. The approach is clean and maintainable. Here's my detailed feedback: ✅ Strengths
🔍 Potential Issues1. Critical: Missing RuboCop validationPer CLAUDE.md requirements, you MUST run def apply_minimum_versions(dir) # rubocop:disable Metrics/CyclomaticComplexityThis suggests the method may have complexity issues. Consider:
2. Error handling incompletenessIn File.write(package_json_path, "\#{JSON.pretty_generate(package_json)}\n")This should have error handling for write failures: begin
File.write(package_json_path, "\#{JSON.pretty_generate(package_json)}\n")
puts " Updated package.json with minimum versions:"
# ...
rescue Errno::EACCES, Errno::ENOENT => e
puts " ERROR: Failed to write package.json: \#{e.message}"
raise
end3. Missing test coverage validationPer CLAUDE.md's "CRITICAL - LOCAL TESTING REQUIREMENTS", before claiming tests are fixed:
The test plan shows checkboxes for rake task verification but not for actual test execution. 4. Potential race condition in CIIn - name: Main CI - Latest version examples
if: matrix.dependency-level == 'latest'
run: cd react_on_rails && bundle exec rake run_rspec:shakapacker_examples_latest
- name: Main CI - Minimum version examples
if: matrix.dependency-level == 'minimum'
run: cd react_on_rails && bundle exec rake run_rspec:shakapacker_examples_minimumBoth steps run unconditionally based on matrix values. This is correct, but consider adding a validation step to ensure the examples were generated with the correct versions before running tests. 💡 Suggestions for Improvement1. Add version verificationConsider adding a verification step in the rake task: def verify_minimum_versions(dir)
package_json = JSON.parse(File.read(File.join(dir, "package.json")))
react_version = package_json.dig("dependencies", "react")
shakapacker_version = package_json.dig("devDependencies", "shakapacker") ||
package_json.dig("dependencies", "shakapacker")
unless react_version == MINIMUM_REACT_VERSION && shakapacker_version == MINIMUM_SHAKAPACKER_VERSION
raise "Version mismatch in \#{dir}: React=\#{react_version}, Shakapacker=\#{shakapacker_version}"
end
endCall this after 2. Document the script/convert changesThe script/convert file removes a lot of code. Consider adding a comment or git commit message explaining that React/Shakapacker conversion is now handled by generator examples, not by script/convert. 3. Constants visibilityThe constants
|
Addressing Review Comment #3573928031Thank you for the detailed review! I've addressed the concerns and also made critical React 19 compatibility updates to the spec/dummy app. ✅ Review Concerns Addressed1. Clarification: spec/dummy in minimum CIGood catch! You're right to ask about this. The spec/dummy integration tests should only run with latest versions (React 19, Shakapacker 9.4.0). The minimum CI workflow only runs the generator example tasks ( 2. JSON Parsing Error HandlingThe begin
package_json = JSON.parse(File.read(package_json_path))
rescue JSON::ParserError => e
puts " ERROR: Failed to parse package.json in \#{dir}: \#{e.message}"
raise
endFail-fast behavior is correct for CI - we want to know immediately if generated examples have malformed package.json. 3. Documentation AddedAdded comment in # Minimum version compatibility tests - tests React 18 and Shakapacker 8.2.0
- name: basic-minimum
generator_options: ''
minimum_versions: true🚀 React 19 Compatibility UpdatesI've also updated the spec/dummy app to be fully compatible with React 19, addressing peer dependency issues: Dependencies Updated in
|
| Package | Old Version | New Version | Reason |
|---|---|---|---|
react-redux |
^8.0.2 | ^9.2.0 | React 19 support |
redux |
^4.0.1 | ^5.0.1 | Required by react-redux 9.x |
redux-thunk |
^2.2.0 | ^3.1.0 | Required by redux 5.x |
react-helmet |
^6.1.0 | Replaced with @dr.pogodin/react-helmet@^3.0.4 |
Thread-safe React 19 fork |
Code Changes:
-
redux-thunk import changes: Updated from default export to named export:
import middleware from 'redux-thunk'→import { thunk } from 'redux-thunk'- Files updated:
SharedReduxStore.jsx,ReduxApp.server.jsx,ReduxApp.client.jsx,app-react16/ReduxApp.client.jsx
-
react-helmet migration: Updated to
@dr.pogodin/react-helmetwhich is the React 19 compatible fork:- Uses
HelmetProviderwithcontextprop for SSR (thread-safe) - Updated
ReactHelmetApp.server.jsxandReactHelmetAppBroken.server.jsxwith new SSR pattern - Updated
ReactHelmet.jsxcomponent
- Uses
Verification:
- ✅
yarn installcompletes without peer dependency warnings (only unrelated babel-eslint warning) - ✅
yarn run build:testcompletes successfully - ✅ RuboCop passes with no offenses
Source
The react-helmet migration follows the official Dr. Pogodin React Helmet documentation for server-side rendering with context-based data capture.
Code Review - PR #2125Thank you for this well-structured refactoring! This PR successfully moves React/Shakapacker version compatibility testing from spec/dummy to generator smoke tests. ✅ StrengthsArchitecture & Design
Implementation Quality
🔍 Suggestions & Questions1. RuboCop Disable - Is It Necessary?def apply_minimum_versions(dir) # rubocop:disable Metrics/CyclomaticComplexityThis method appears relatively simple (early return, JSON parse, 2-3 conditionals). Have you verified this disable is actually needed? Try removing it and running RuboCop. 2. JSON FormattingFile.write(package_json_path, "\#{JSON.pretty_generate(package_json)}\n")Good that you're adding the trailing newline! Note that this will reformat the entire package.json (key ordering, spacing). Consider documenting this behavior in a comment if it's intentional. 3. Error Handling EnhancementConsider handling rescue JSON::ParserError => e
puts " ERROR: Invalid JSON in \#{package_json_path}: \#{e.message}"
raise
rescue Errno::ENOENT
puts " ERROR: package.json not found at \#{package_json_path}"
raise4. CI Workflow Edge CaseWhat if 5. Test CoverageAre there tests verifying:
6. DocumentationThe comment in 🧪 Testing Recommendations# Verify rake tasks exist
bundle exec rake -T | grep shakapacker_examples
# Test latest examples
bundle exec rake shakapacker_examples:gen_basic
cat gen-examples/basic/package.json | grep '"react"' # Should be ^19.0.0
# Test minimum examples
bundle exec rake shakapacker_examples:gen_basic-minimum
cat gen-examples/basic-minimum/package.json | grep '"react"' # Should be 18.0.0
# Verify filtering
bundle exec rake run_rspec:shakapacker_examples_latest
bundle exec rake run_rspec:shakapacker_examples_minimum🏁 VerdictOverall: ✅ Approve This is a well-executed refactoring. The architectural approach is sound, implementation is clean, and CI is passing. The suggestions above are minor improvements, not blockers. Great work! 🚀 This approach is much more maintainable than modifying spec/dummy on the fly. Review generated by Claude Code following CLAUDE.md conventions |
Code Review - PR #2125OverviewThis PR successfully moves React and Shakapacker version compatibility testing from the dummy app to dedicated generator smoke tests. The approach is well-architected and aligns with best practices for testing compatibility matrices. ✅ Strengths1. Clear Separation of Concerns
2. Excellent Code Quality
3. CI Integration
4. Helper Methods Are Well Structured def latest_examples
ExampleType.all[:shakapacker_examples].reject(&:minimum_versions?)
end
def minimum_examples
ExampleType.all[:shakapacker_examples].select(&:minimum_versions?)
endThese are readable and leverage Ruby's functional collection methods appropriately. 🔍 Areas for Consideration1. Missing Cleanup in The Current state: # Lines 30-31 - Should these be removed?
gsub_file_content("../react_on_rails/Gemfile.development_dependencies", /gem "shakapacker", "[^"]*"/, 'gem "shakapacker", "8.2.0"')
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"shakapacker": "[^"]*",/, '"shakapacker": "8.2.0",')
# Lines 45-49 - Should these be removed?
gsub_file_content("../package.json", /"react": "[^"]*",/, '"react": "18.0.0",')
gsub_file_content("../package.json", /"react-dom": "[^"]*",/, '"react-dom": "18.0.0",')
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"react": "[^"]*",/, '"react": "18.0.0",')
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"react-dom": "[^"]*",/, '"react-dom": "18.0.0",')Expected: Based on the PR description, 2. Potential Complexity in The method has reasonable complexity (RuboCop disabled with def apply_minimum_versions(dir)
# ...
if package_json["dependencies"]
package_json["dependencies"]["react"] = ExampleType::MINIMUM_REACT_VERSION
package_json["dependencies"]["react-dom"] = ExampleType::MINIMUM_REACT_VERSION
end
if package_json["devDependencies"]&.key?("shakapacker")
package_json["devDependencies"]["shakapacker"] = ExampleType::MINIMUM_SHAKAPACKER_VERSION
elsif package_json["dependencies"]&.key?("shakapacker")
package_json["dependencies"]["shakapacker"] = ExampleType::MINIMUM_SHAKAPACKER_VERSION
end
# ...
endSuggestions:
3. Test Coverage Gaps The test plan in the PR description shows:
Question: Will you be monitoring the CI run to ensure the minimum version examples actually run and pass? This is critical validation that the approach works end-to-end. 4. Documentation Consider adding:
🛡️ Security & PerformanceSecurity: ✅ No security concerns. The JSON parsing includes error handling. Performance: ✅ The filtering operations are performed on small arrays (handful of example types), so performance impact is negligible. 🧪 Testing RecommendationsBefore merging, verify:
📋 Minor Suggestions
🎯 RecommendationApprove with minor revisions This is a solid architectural improvement that makes the codebase more maintainable. The only blocking concern is confirming that All other suggestions are optional refinements. The core logic is sound, well-tested, and follows Ruby best practices. Great work on this refactoring! 🚀 Related: Closes #2123 |
Code ReviewOverall Assessment ✅This is a well-structured PR that successfully moves React/Shakapacker version compatibility testing from spec/dummy to the generator smoke tests. The approach is sound and the implementation is clean. CI is passing successfully. Strengths 💪
Code Quality Issues 🔍1. Missing Implementation in
|
Code Review - PR #2125: Move React/Shakapacker version compatibility to generator smoke testsOverviewThis PR successfully refactors version compatibility testing from spec/dummy to generator smoke tests. The approach is clean and well-architected. Strengths1. Clean Architecture
2. Smart Implementation
3. Simplified Conversion Script
Issues and RecommendationsCRITICAL: Missing Test CoverageProblem: No tests verify the new rake tasks work correctly. Recommendation: Add tests to verify latest_examples and minimum_examples filtering. Why critical: The PR checklist shows "Verify rake tasks are created correctly" but this should be automated, not manual. MEDIUM: CI Workflow TestingIssue: From examples.yml lines 175-179 - conditional execution based on dependency-level Recommendation per CLAUDE.md:
MEDIUM: Potential Race ConditionIssue in shakapacker_examples.rake:56-58 - Modifies package.json AFTER generation but BEFORE npm install Recommendation: Add a comment explaining the ordering to prevent future refactoring issues LOW: Missing RuboCop VerificationFrom CLAUDE.md: ALWAYS run bundle exec rubocop before commit Recommendation: Run locally before merge Security and PerformanceSecurity: No concerns
Performance: Acceptable
Testing ChecklistPer CLAUDE.md "15-Minute Rule": spend 15 minutes testing locally before pushing Before merging, verify:
Recommendations SummaryBefore Merge (Required)
Future Improvements (Optional)
ConclusionOverall: Strong PR with good architecture. Main concern is lack of automated tests for new rake tasks and missing local verification before CI runs. Recommendation: APPROVE with conditions
Great work on the refactoring! The separation of concerns is much cleaner now. |
Code Review: PR #2125Great work on this refactor! This is a well-thought-out improvement that simplifies the testing strategy. Here's my detailed feedback: ✅ Strengths
🔍 Potential Issues & Suggestions1. Missing
|
There was a problem hiding this 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
♻️ Duplicate comments (1)
react_on_rails/spec/dummy/package.json (1)
21-28: LGTM — React 19 ecosystem dependencies updated correctly.All dependencies now support React 19:
- react-redux upgraded to ^9.2.0 (adds React 19 peer dependency support)
- @dr.pogodin/react-helmet ^3.0.4 replaces react-helmet (React 19 compatible)
- redux ^5.0.1 and redux-thunk ^3.1.0 are current stable versions
This addresses the compatibility concerns raised in the previous review.
🧹 Nitpick comments (1)
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx (1)
31-31: Use optional chaining for safer property access.The current fallback only guards against
helmetbeing undefined. Ifhelmetexists buthelmet.titleis undefined,helmet.title.toString()would throw a TypeError.Apply this diff for more defensive access:
- title: helmet ? helmet.title.toString() : '', + title: helmet?.title?.toString() || '',This ensures the code gracefully handles cases where either
helmetorhelmet.titlemight be undefined.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
react_on_rails/spec/dummy/Gemfile.lockis excluded by!**/*.lockreact_on_rails/spec/dummy/yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (10)
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx(2 hunks)react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx(1 hunks)react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx(1 hunks)react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx(2 hunks)react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx(1 hunks)react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx(2 hunks)react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx(2 hunks)react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx(2 hunks)react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx(2 hunks)react_on_rails/spec/dummy/package.json(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
ALWAYS ensure files end with a newline character before committing/pushing
Files:
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsxreact_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsxreact_on_rails/spec/dummy/package.jsonreact_on_rails/spec/dummy/client/app/components/ReactHelmet.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to spec/dummy/e2e/playwright/**/*.spec.js : Use Rails helpers (`appFactories`, `appEval`) in Playwright tests instead of UI-based setup to leverage factory_bot and arbitrary Ruby code execution
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.
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.
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package
Applied to files:
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsxreact_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsxreact_on_rails/spec/dummy/package.jsonreact_on_rails/spec/dummy/client/app/components/ReactHelmet.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
📚 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/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsxreact_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsxreact_on_rails/spec/dummy/client/app/components/ReactHelmet.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
📚 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/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsxreact_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsxreact_on_rails/spec/dummy/package.jsonreact_on_rails/spec/dummy/client/app/components/ReactHelmet.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
📚 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/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsxreact_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsxreact_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsxreact_on_rails/spec/dummy/package.jsonreact_on_rails/spec/dummy/client/app/components/ReactHelmet.jsxreact_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
📚 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:
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
📚 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:
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsxreact_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsxreact_on_rails/spec/dummy/package.jsonreact_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
📚 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/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
📚 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:
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
📚 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/spec/dummy/client/app/startup/ReactHelmetApp.client.jsxreact_on_rails/spec/dummy/package.json
📚 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/spec/dummy/package.json
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: The `react_on_rails_pro/` directory has its own Prettier/ESLint configuration and must be linted separately
Applied to files:
react_on_rails/spec/dummy/package.json
🧬 Code graph analysis (8)
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx (1)
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx (1)
props(10-14)
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx (3)
react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx (3)
store(37-37)combinedReducer(32-32)combinedProps(33-33)react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx (3)
store(31-31)combinedReducer(26-26)combinedProps(27-27)react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx (1)
combinedReducer(13-13)
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx (1)
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx (5)
helmetContext(21-21)helmetContext(27-27)componentHtml(22-26)props(20-34)renderedHtml(29-32)
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx (1)
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx (1)
props(10-14)
react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx (2)
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx (3)
store(32-32)combinedReducer(27-27)combinedProps(28-28)react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx (3)
store(31-31)combinedReducer(26-26)combinedProps(27-27)
react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx (3)
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx (1)
combinedReducer(27-27)react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx (1)
combinedReducer(32-32)react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx (1)
combinedReducer(26-26)
react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx (3)
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx (3)
store(32-32)combinedReducer(27-27)combinedProps(28-28)react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx (3)
store(37-37)combinedReducer(32-32)combinedProps(33-33)react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx (1)
combinedReducer(13-13)
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx (2)
packages/react-on-rails/src/ReactDOMServer.cts (1)
renderToString(4-4)react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx (1)
ReactHelmet(8-16)
⏰ 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: build
- GitHub Check: examples (3.4, latest)
- GitHub Check: examples (3.2, minimum)
- GitHub Check: build-dummy-app-webpack-test-bundles (3.2, 20, minimum)
- GitHub Check: build-dummy-app-webpack-test-bundles (3.4, 22, latest)
🔇 Additional comments (11)
react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx (1)
8-8: LGTM — redux-thunk 3.x migration is correct.The switch from default import to named
{ thunk }export aligns with redux-thunk 3.x API. The middleware usage at line 37 is updated consistently.Also applies to: 37-37
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx (1)
8-8: LGTM — Consistent redux-thunk 3.x migration in React 16 variant.The named
{ thunk }import and middleware usage align with the main app/ variant and redux-thunk 3.x API.Also applies to: 32-32
react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx (1)
9-9: LGTM — Server-side redux-thunk migration is correct.The named import and curried middleware application pattern are both valid for redux-thunk 3.x and consistent with the client-side changes.
Also applies to: 31-31
react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx (1)
2-2: LGTM — Helmet migration with clear documentation.The switch to
@dr.pogodin/react-helmetis correct for React 19 compatibility. The added comments clearly document the HelmetProvider requirement for both client and server rendering.Also applies to: 5-7
react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx (1)
2-2: LGTM — Shared store migration is consistent.The redux-thunk 3.x named export and middleware usage are correct and align with other Redux store configurations in the codebase.
Also applies to: 15-15
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx (1)
3-3: LGTM — Client-side HelmetProvider integration is correct.The HelmetProvider wrapper is required by
@dr.pogodin/react-helmetfor both client and server rendering. The implementation and documentation are correct.Also applies to: 9-14
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx (1)
4-4: LGTM — Server-side helmet rendering migrated correctly.The context-based HelmetProvider pattern is the proper approach for
@dr.pogodin/react-helmetSSR. This replaces the oldHelmet.renderStatic()global approach with thread-safe per-request context extraction.Also applies to: 19-39
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx (2)
3-4: LGTM: React 19-compatible helmet library migration.The migration from
react-helmetto@dr.pogodin/react-helmetis correct. This fork provides React 19 compatibility as documented in the PR objectives.
9-14: LGTM: HelmetProvider wrapper correctly applied.The HelmetProvider wrapper is correctly implemented for client-side rendering, consistent with the pattern in ReactHelmetApp.client.jsx. The explanatory comment on line 9 is helpful.
react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx (2)
6-6: LGTM: Server-side helmet library migration.The import of
HelmetProviderfrom@dr.pogodin/react-helmetis correct for React 19 compatibility.
21-27: LGTM: Correct server-side HelmetProvider pattern.The helmetContext pattern correctly implements the @dr.pogodin/react-helmet server-side rendering approach. The context object is populated during rendering and then extracted for use in the returned HTML structure.
There was a problem hiding this 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/rakelib/shakapacker_examples.rake (1)
19-73: Good implementation with JSON error handling; consider extracting webpack-assets-manifest version to a constant.The method correctly handles JSON parsing errors (re-raising with context for CI), updates both package.json and Gemfile, and provides clear output. The logic for checking both
depsanddev_depsis thorough.However, the webpack-assets-manifest version
"^5.0.6"is hardcoded on lines 40 and 44, while other versions use named constants (MINIMUM_REACT_VERSION,MINIMUM_SHAKAPACKER_VERSION). For consistency and easier maintenance, consider extracting this to a constant likeMINIMUM_WEBPACK_ASSETS_MANIFEST_VERSIONinExampleType.Example:
# In example_type.rb MINIMUM_WEBPACK_ASSETS_MANIFEST_VERSION = "^5.0.6"Then update lines 40 and 44:
- deps["webpack-assets-manifest"] = "^5.0.6" if deps.key?("webpack-assets-manifest") + deps["webpack-assets-manifest"] = ExampleType::MINIMUM_WEBPACK_ASSETS_MANIFEST_VERSION if deps.key?("webpack-assets-manifest")- dev_deps["webpack-assets-manifest"] = "^5.0.6" if dev_deps&.key?("webpack-assets-manifest") + dev_deps["webpack-assets-manifest"] = ExampleType::MINIMUM_WEBPACK_ASSETS_MANIFEST_VERSION if dev_deps&.key?("webpack-assets-manifest")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
react_on_rails/rakelib/shakapacker_examples.rake(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rb,rake}
📄 CodeRabbit inference engine (CLAUDE.md)
ALWAYS run
bundle exec rubocopand fix ALL violations before every commit/push
Files:
react_on_rails/rakelib/shakapacker_examples.rake
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
ALWAYS ensure files end with a newline character before committing/pushing
Files:
react_on_rails/rakelib/shakapacker_examples.rake
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package
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-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rake
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to lib/react_on_rails/*.rb : Create RBS signature files for new Ruby files in `lib/react_on_rails/` by adding corresponding `.rbs` file in `sig/react_on_rails/`, adding to Steepfile, and validating before committing
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rake
📚 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/rakelib/shakapacker_examples.rake
📚 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/rakelib/shakapacker_examples.rake
📚 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/rakelib/shakapacker_examples.rake
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to **/*.{rb,rake} : ALWAYS run `bundle exec rubocop` and fix ALL violations before every commit/push
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rake
⏰ 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: examples (3.4, latest)
- GitHub Check: examples (3.2, minimum)
- GitHub Check: build
- GitHub Check: build-dummy-app-webpack-test-bundles (3.2, 20, minimum)
🔇 Additional comments (2)
react_on_rails/rakelib/shakapacker_examples.rake (2)
11-11: LGTM: JSON library required for new functionality.The addition of
require "json"is necessary to support JSON parsing and generation in the newapply_minimum_versionsmethod.
107-112: LGTM: Clean integration of minimum version pinning.The conditional application of
apply_minimum_versionsis correctly placed after generator commands and before npm install. Re-runningbundle_install_inafter Gemfile modification ensures dependencies are properly updated. The comment clearly explains the rationale.
CI Status Update✅ Fixed
🔧 In Progress: Generator tests (minimum version)The minimum version generator tests are encountering a Bundler isolation issue where the generated example app is loading Shakapacker from the parent This is happening because:
Potential solutions:
The Integration Tests pass which validates the core React 19 compatibility changes. The Generator test issue is a CI environment isolation problem, not a code issue. |
There was a problem hiding this 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/rakelib/shakapacker_examples.rake (1)
40-40: Consider extracting webpack-assets-manifest version as a constant.The hardcoded
"^5.0.6"appears twice and is coupled toMINIMUM_SHAKAPACKER_VERSION. Extracting it asMINIMUM_WEBPACK_ASSETS_MANIFEST_VERSIONinExampleTypewould improve maintainability and consistency with the other minimum version constants.Example:
# In example_type.rb MINIMUM_WEBPACK_ASSETS_MANIFEST_VERSION = "^5.0.6" # In this file, lines 40 and 44: deps["webpack-assets-manifest"] = ExampleType::MINIMUM_WEBPACK_ASSETS_MANIFEST_VERSION if deps.key?("webpack-assets-manifest")Also applies to: 44-44
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
react_on_rails/rakelib/shakapacker_examples.rake(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rb,rake}
📄 CodeRabbit inference engine (CLAUDE.md)
ALWAYS run
bundle exec rubocopand fix ALL violations before every commit/push
Files:
react_on_rails/rakelib/shakapacker_examples.rake
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
ALWAYS ensure files end with a newline character before committing/pushing
Files:
react_on_rails/rakelib/shakapacker_examples.rake
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package
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.
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.
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rake
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to lib/react_on_rails/*.rb : Create RBS signature files for new Ruby files in `lib/react_on_rails/` by adding corresponding `.rbs` file in `sig/react_on_rails/`, adding to Steepfile, and validating before committing
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rake
📚 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/rakelib/shakapacker_examples.rake
📚 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/rakelib/shakapacker_examples.rake
📚 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/rakelib/shakapacker_examples.rake
📚 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/rakelib/shakapacker_examples.rake
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to **/*.{rb,rake} : ALWAYS run `bundle exec rubocop` and fix ALL violations before every commit/push
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rake
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: Applies to spec/dummy/e2e/playwright/app_commands/**/*.rb : Add custom Playwright app commands in `e2e/playwright/app_commands/` directory as Ruby files using CypressOnRails SmartFactoryWrapper pattern
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rake
📚 Learning: 2025-11-25T08:05:17.778Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.778Z
Learning: The `react_on_rails_pro/` directory has its own Prettier/ESLint configuration and must be linted separately
Applied to files:
react_on_rails/rakelib/shakapacker_examples.rake
📚 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/rakelib/shakapacker_examples.rake
🔇 Additional comments (4)
react_on_rails/rakelib/shakapacker_examples.rake (4)
11-11: LGTM – JSON library addition.The JSON library require is necessary for the package.json manipulation in
apply_minimum_versions.
19-73: Well-implemented minimum version updates with proper error handling.The method correctly:
- Handles JSON parse errors by logging context and re-raising to fail fast in CI
- Updates React, Shakapacker, and webpack-assets-manifest versions in package.json
- Pins Shakapacker in Gemfile using regex replacement (appropriate for generated apps with standard gem declarations)
- Adds trailing newline when writing package.json
107-112: LGTM – Correct integration of minimum version updates.The logic correctly applies minimum versions when the flag is set and re-runs
bundle_install_inafter modifying the Gemfile. The placement after generator commands and before npm install is appropriate.
116-120: Excellent fix for the Bundler isolation issue.Setting
BUNDLE_GEMFILEensures the rake task uses the generated app's Gemfile and bundle, preventing version mismatches where the parent workspace's gems (e.g., Shakapacker 9.4.0) could be loaded instead of the generated app's pinned versions (e.g., Shakapacker 8.2.0). This directly resolves the CI failure described in the PR objectives.
PR Split NoticeThis PR has been split into two smaller, focused PRs: PR 1: React 19 Compatibility ✅ (Ready for merge)PR #2127 - Updates spec/dummy for React 19 compatibility
PR 2: Minimum Version Testing Infrastructure (This PR)This PR will be rebased/updated to contain only the minimum version testing infrastructure changes once PR #2127 is merged. Current blockers:
Recommendation: Merge PR #2127 first, then continue work on this PR for the minimum version testing. |
Code Review: PR #2125Overall AssessmentThis is a well-architected refactoring with significant scope. The PR successfully moves version compatibility testing from spec/dummy to generator smoke tests while also migrating from Yarn to pnpm. Critical Issues1. PR Scope Too Large 2. Missing Type Definitions for React 19 Code Quality - Excellent Design✅ Clean separation of concerns with ExampleType class Areas for Improvement
Testing Requirements (CRITICAL)Per CLAUDE.md and testing-build-scripts.md, MUST test locally before merge:
PR description shows incomplete testing. Do not merge until ALL CI passes. Must Fix Before Merge
Should Consider
Final Recommendation✅ Approve with required changes - This is solid engineering work with clear benefits (better separation of concerns, maintainable CI). Main risk is combined scope making diagnosis harder if issues arise. Fix the React 19 type definitions and verify complete CI pass before merging. Review follows CLAUDE.md, testing-build-scripts.md, avoiding-ci-failure-cycles.md, and pr-splitting-strategy.md |
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
CONTRIBUTING.md (1)
239-247: Update script/convert docs to match its new roleThis section still describes
script/convertas switching the development environment between Shakapacker v6 and v8, but the script now only tweaks Node/tooling compatibility and Pro test behavior (React/Shakapacker version coverage moved to generator smoke tests). That can confuse contributors who expect it to toggle Shakapacker versions.Consider either:
- Rewording this section to describe the current
script/convertpurpose, and/or- Pointing to the generator smoke-test examples (minimum vs latest) as the place where Shakapacker/React version compatibility is exercised.
react_on_rails/rakelib/release.rake (1)
210-215: Verify Pro dummy app path when updating Gemfile.lock
pro_dummy_app_diris built fromgem_root, notpro_gem_root:pro_dummy_app_dir = File.join(gem_root, "react_on_rails_pro", "spec", "dummy") unbundled_sh_in_dir(pro_dummy_app_dir, "bundle install#{bundle_quiet_flag}") if Dir.exist?(pro_dummy_app_dir)Given the monorepo now has
react_on_rails/andreact_on_rails_pro/as top‑level siblings, this may miss the actual Pro dummy app (react_on_rails_pro/spec/dummy), leaving its Gemfile.lock stale during releases.Consider basing this path on
pro_gem_rootinstead:- pro_dummy_app_dir = File.join(gem_root, "react_on_rails_pro", "spec", "dummy") + pro_dummy_app_dir = File.join(pro_gem_root, "spec", "dummy")and keep the
Dir.exist?guard.react_on_rails_pro/spec/dummy/package.json (1)
50-62: Based on my verification, the original review comment correctly identifies the React version inconsistency but the Redux compatibility concern is unfounded. Let me provide the final rewritten comment:
Inconsistent React version declarations between root and dummy packages.
Version inconsistency detected:
- Root
package.jsondeclares"react": "^19.0.0"(allows minor/patch updates)- This file declares
"react": "19.0.0"(exact version)Based on learnings, version consistency should be maintained across package.json files to avoid potential conflicts.
Apply this consistency fix:
- "react": "19.0.0", - "react-dom": "19.0.0", + "react": "^19.0.0", + "react-dom": "^19.0.0",Note: redux-thunk 3.1.0 is compatible with Redux 5.0.1 and React 19, so no compatibility changes are needed there.
🧹 Nitpick comments (4)
package-scripts.yml (1)
18-18: pnpm-based TypeScript check looks correctUsing
pnpm --filter <workspace> run type-checkfor each of the three packages is consistent with the new pnpm workspace setup and keeps checks scoped per package.react_on_rails_pro/spec/execjs-compatible-dummy/package.json (1)
2-2: ExecJS dummy wired into pnpm/yalc flowDeclaring
packageManager: [email protected]and usingpnpm run link-sourceplusyalc add --link react-on-railsmakes this dummy app consistent with the rest of the pnpm-based workflow and keeps it sourcing the local package.Also applies to: 42-43
script/convert (1)
4-26: Script scope matches new “minimum toolchain” role; consider simplifying path fallbackThe header comment and current replacements correctly narrow
script/convertto:
- Dropping Node‑incompatible dev deps from the root
package.json, and- Adjusting the Pro
test:non-rscscript to skip RSC/streaming tests under minimum React/Node.That matches the intent to move React/Shakapacker version compatibility into generator smoke tests.
The
gsub_file_contenthelper still contains a Gemfile‑specific fallback:old_path = path.sub(%r{/react_on_rails/Gemfile}, "/Gemfile")but the script now only operates on
../package.jsonand../packages/.../package.json, so this fallback is effectively dead code and slightly contradicts the “old vs new structure” comment.Optional: either remove the Gemfile‑specific fallback, or generalize it (or the comment) to match the current usage. Behavior today is correct either way.
CLAUDE.md (1)
96-113: Consider updating legacy yarn-based checklist to pnpm for consistencyThe “Mandatory Local Testing Checklist” still shows:
rm -rf node_modules && yarn install --frozen-lockfile yarn run build yarn run yalc:publish ... yarn run lintwhile the rest of this file now standardizes on pnpm and explicitly says to avoid
npmcommands.For consistency with current tooling (and to avoid mixed signals to AI agents), consider updating this snippet to the pnpm equivalents (and, if desired, mentioning yarn only as an alternative for external consumers, not for this repo’s workflows).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (6)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlreact_on_rails/spec/dummy/yarn.lockis excluded by!**/yarn.lock,!**/*.lockreact_on_rails_pro/spec/dummy/yarn.lockis excluded by!**/yarn.lock,!**/*.lockreact_on_rails_pro/spec/execjs-compatible-dummy/yarn.lockis excluded by!**/yarn.lock,!**/*.lockreact_on_rails_pro/yarn.lockis excluded by!**/yarn.lock,!**/*.lockyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (63)
.claude/commands/update-changelog.md(0 hunks).claude/docs/analysis/MONOREPO_MIGRATION_ANALYSIS.md(0 hunks).claude/docs/analysis/PHASE_5_COMPLETION_NOTES.md(0 hunks).claude/docs/analysis/claude-md-improvements.md(0 hunks).claude/docs/analysis/github-issue-1765-status-update.md(0 hunks).claude/docs/analysis/github-issue-1765-update.md(0 hunks).claude/docs/avoiding-ci-failure-cycles.md(0 hunks).claude/docs/pr-splitting-strategy.md(0 hunks).claude/docs/testing-build-scripts.md(7 hunks).github/workflows/examples.yml(3 hunks).github/workflows/gem-tests.yml(0 hunks).github/workflows/integration-tests.yml(5 hunks).github/workflows/lint-js-and-ruby.yml(2 hunks).github/workflows/package-js-tests.yml(1 hunks).github/workflows/playwright.yml(2 hunks).github/workflows/pro-integration-tests.yml(13 hunks).github/workflows/pro-lint.yml(4 hunks).github/workflows/pro-test-package-and-gem.yml(5 hunks).gitignore(1 hunks).npmrc(1 hunks).prettierignore(1 hunks)CHANGELOG.md(1 hunks)CLAUDE.md(8 hunks)CODING_AGENTS.md(0 hunks)CONTRIBUTING.md(16 hunks)TODO.md(0 hunks)bin/lefthook/eslint-lint(2 hunks)bin/lefthook/prettier-format(2 hunks)docs/CI_OPTIMIZATION.md(0 hunks)docs/DIRECTORY_LICENSING.md(0 hunks)docs/LICENSING_FAQ.md(0 hunks)docs/MONOREPO_MERGER_PLAN.md(0 hunks)docs/building-features/i18n.md(0 hunks)docs/building-features/streaming-server-rendering.md(0 hunks)docs/contributor-info/releasing.md(0 hunks)docs/guides/testing-configuration.md(0 hunks)docs/migrating/migrating-from-react-rails.md(0 hunks)docs/planning/docs-improvement/01-problem-analysis.md(0 hunks)docs/planning/docs-improvement/02-pr-1813-comparison.md(0 hunks)docs/planning/docs-improvement/04-ia-redesign-plan.md(0 hunks)docs/planning/docs-improvement/ia-redesign-live.md(0 hunks)docs/upgrading/release-notes/16.0.0.md(0 hunks)docs/upgrading/upgrading-react-on-rails.md(0 hunks)knip.ts(3 hunks)package-scripts.yml(1 hunks)package.json(3 hunks)packages/react-on-rails-pro-node-renderer/package.json(3 hunks)packages/react-on-rails-pro/package.json(2 hunks)packages/react-on-rails-pro/scripts/check-react-version.cjs(1 hunks)packages/react-on-rails-pro/tests/jest.setup.js(1 hunks)packages/react-on-rails/package.json(1 hunks)pnpm-workspace.yaml(1 hunks)react_on_rails/rakelib/dummy_apps.rake(1 hunks)react_on_rails/rakelib/lint.rake(3 hunks)react_on_rails/rakelib/node_package.rake(1 hunks)react_on_rails/rakelib/release.rake(1 hunks)react_on_rails/rakelib/run_rspec.rake(2 hunks)react_on_rails/rakelib/shakapacker_examples.rake(2 hunks)react_on_rails/spec/dummy/package.json(3 hunks)react_on_rails_pro/spec/dummy/client/app/components/LazyApolloGraphQL.tsx(1 hunks)react_on_rails_pro/spec/dummy/package.json(2 hunks)react_on_rails_pro/spec/execjs-compatible-dummy/package.json(2 hunks)script/convert(2 hunks)
💤 Files with no reviewable changes (26)
- .github/workflows/gem-tests.yml
- docs/guides/testing-configuration.md
- .claude/docs/avoiding-ci-failure-cycles.md
- docs/building-features/streaming-server-rendering.md
- .claude/docs/analysis/claude-md-improvements.md
- .claude/docs/analysis/PHASE_5_COMPLETION_NOTES.md
- docs/CI_OPTIMIZATION.md
- CODING_AGENTS.md
- docs/planning/docs-improvement/01-problem-analysis.md
- docs/upgrading/upgrading-react-on-rails.md
- docs/LICENSING_FAQ.md
- docs/building-features/i18n.md
- docs/planning/docs-improvement/04-ia-redesign-plan.md
- docs/planning/docs-improvement/ia-redesign-live.md
- docs/planning/docs-improvement/02-pr-1813-comparison.md
- docs/contributor-info/releasing.md
- docs/MONOREPO_MERGER_PLAN.md
- docs/DIRECTORY_LICENSING.md
- .claude/docs/analysis/github-issue-1765-status-update.md
- .claude/commands/update-changelog.md
- TODO.md
- .claude/docs/pr-splitting-strategy.md
- docs/migrating/migrating-from-react-rails.md
- .claude/docs/analysis/github-issue-1765-update.md
- docs/upgrading/release-notes/16.0.0.md
- .claude/docs/analysis/MONOREPO_MIGRATION_ANALYSIS.md
✅ Files skipped from review due to trivial changes (2)
- .npmrc
- .prettierignore
🚧 Files skipped from review as they are similar to previous changes (1)
- react_on_rails/rakelib/run_rspec.rake
🧰 Additional context used
📓 Path-based instructions (2)
**/*
📄 CodeRabbit inference engine (CLAUDE.md)
ALWAYS ensure files end with a newline character before committing/pushing
Files:
react_on_rails_pro/spec/dummy/client/app/components/LazyApolloGraphQL.tsxbin/lefthook/eslint-lintCONTRIBUTING.mdpackages/react-on-rails/package.jsonpackages/react-on-rails-pro-node-renderer/package.jsonpackage-scripts.ymlbin/lefthook/prettier-formatreact_on_rails_pro/spec/execjs-compatible-dummy/package.jsonpackages/react-on-rails-pro/scripts/check-react-version.cjsreact_on_rails/rakelib/dummy_apps.rakereact_on_rails/rakelib/lint.rakereact_on_rails/rakelib/node_package.rakepnpm-workspace.yamlreact_on_rails/rakelib/shakapacker_examples.rakeCLAUDE.mdpackages/react-on-rails-pro/package.jsonknip.tsreact_on_rails_pro/spec/dummy/package.jsonscript/convertCHANGELOG.mdreact_on_rails/rakelib/release.rakereact_on_rails/spec/dummy/package.jsonpackages/react-on-rails-pro/tests/jest.setup.jspackage.json
**/*.{rb,rake}
📄 CodeRabbit inference engine (CLAUDE.md)
ALWAYS run
bundle exec rubocopand fix ALL violations before every commit/push
Files:
react_on_rails/rakelib/dummy_apps.rakereact_on_rails/rakelib/lint.rakereact_on_rails/rakelib/node_package.rakereact_on_rails/rakelib/shakapacker_examples.rakereact_on_rails/rakelib/release.rake
🧠 Learnings (34)
📓 Common learnings
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package
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.
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-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package
Applied to files:
react_on_rails_pro/spec/dummy/client/app/components/LazyApolloGraphQL.tsxbin/lefthook/eslint-lintCONTRIBUTING.md.gitignorepackages/react-on-rails/package.jsonpackages/react-on-rails-pro-node-renderer/package.jsonpackage-scripts.ymlbin/lefthook/prettier-formatreact_on_rails_pro/spec/execjs-compatible-dummy/package.jsonpackages/react-on-rails-pro/scripts/check-react-version.cjsreact_on_rails/rakelib/dummy_apps.rake.claude/docs/testing-build-scripts.mdreact_on_rails/rakelib/lint.rakereact_on_rails/rakelib/node_package.rakereact_on_rails/rakelib/shakapacker_examples.rakeCLAUDE.mdpackages/react-on-rails-pro/package.jsonknip.ts.github/workflows/lint-js-and-ruby.ymlreact_on_rails_pro/spec/dummy/package.json.github/workflows/examples.ymlscript/convertCHANGELOG.mdreact_on_rails/rakelib/release.rake.github/workflows/pro-integration-tests.ymlreact_on_rails/spec/dummy/package.jsonpackages/react-on-rails-pro/tests/jest.setup.jspackage.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/spec/dummy/client/app/components/LazyApolloGraphQL.tsxCONTRIBUTING.mdpackages/react-on-rails-pro-node-renderer/package.jsonpackages/react-on-rails-pro/scripts/check-react-version.cjsCLAUDE.mdpackages/react-on-rails-pro/package.jsonknip.ts
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: The `react_on_rails_pro/` directory has its own Prettier/ESLint configuration and must be linted separately
Applied to files:
bin/lefthook/eslint-lintCONTRIBUTING.md.gitignorepackages/react-on-rails/package.jsonpackages/react-on-rails-pro-node-renderer/package.jsonpackage-scripts.yml.github/workflows/pro-test-package-and-gem.ymlbin/lefthook/prettier-formatreact_on_rails_pro/spec/execjs-compatible-dummy/package.jsonpackages/react-on-rails-pro/scripts/check-react-version.cjsreact_on_rails/rakelib/dummy_apps.rake.claude/docs/testing-build-scripts.mdreact_on_rails/rakelib/lint.rake.github/workflows/integration-tests.ymlreact_on_rails/rakelib/shakapacker_examples.rakeCLAUDE.md.github/workflows/pro-lint.ymlpackages/react-on-rails-pro/package.jsonknip.ts.github/workflows/lint-js-and-ruby.ymlreact_on_rails_pro/spec/dummy/package.json.github/workflows/examples.ymlscript/convertCHANGELOG.mdreact_on_rails/rakelib/release.rake.github/workflows/pro-integration-tests.ymlreact_on_rails/spec/dummy/package.jsonpackages/react-on-rails-pro/tests/jest.setup.jspackage.json
📚 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:
bin/lefthook/eslint-lintCONTRIBUTING.md.gitignorepackages/react-on-rails/package.jsonpackages/react-on-rails-pro-node-renderer/package.jsonpackage-scripts.ymlreact_on_rails_pro/spec/execjs-compatible-dummy/package.jsonpackages/react-on-rails-pro/scripts/check-react-version.cjsreact_on_rails/rakelib/dummy_apps.rake.claude/docs/testing-build-scripts.mdreact_on_rails/rakelib/lint.rakereact_on_rails/rakelib/node_package.rake.github/workflows/integration-tests.ymlreact_on_rails/rakelib/shakapacker_examples.rake.github/workflows/pro-lint.ymlpackages/react-on-rails-pro/package.jsonknip.ts.github/workflows/lint-js-and-ruby.ymlreact_on_rails_pro/spec/dummy/package.jsonscript/convertCHANGELOG.mdreact_on_rails/rakelib/release.rakereact_on_rails/spec/dummy/package.jsonpackages/react-on-rails-pro/tests/jest.setup.jspackage.json
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Do NOT manually format code during conflict resolution; always use `rake autofix` or `pnpm run format` for automated formatting
Applied to files:
bin/lefthook/eslint-lintCONTRIBUTING.mdbin/lefthook/prettier-formatreact_on_rails_pro/spec/execjs-compatible-dummy/package.json.claude/docs/testing-build-scripts.mdreact_on_rails/rakelib/lint.rakereact_on_rails/rakelib/node_package.rakeCLAUDE.mdreact_on_rails/rakelib/release.rake
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: NEVER use `npm` commands; only use equivalent `pnpm` commands for JavaScript package management
Applied to files:
bin/lefthook/eslint-lintCONTRIBUTING.mdpackages/react-on-rails/package.jsonpackages/react-on-rails-pro-node-renderer/package.json.github/workflows/pro-test-package-and-gem.ymlreact_on_rails_pro/spec/execjs-compatible-dummy/package.json.github/workflows/package-js-tests.yml.claude/docs/testing-build-scripts.mdreact_on_rails/rakelib/lint.rakereact_on_rails/rakelib/node_package.rake.github/workflows/integration-tests.ymlCLAUDE.md.github/workflows/pro-lint.ymlpackages/react-on-rails-pro/package.json.github/workflows/lint-js-and-ruby.ymlreact_on_rails_pro/spec/dummy/package.json.github/workflows/examples.ymlreact_on_rails/rakelib/release.rakereact_on_rails/spec/dummy/package.json
📚 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:
bin/lefthook/eslint-lintCONTRIBUTING.md.github/workflows/pro-lint.ymlCHANGELOG.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to lib/react_on_rails/*.rb : Create RBS signature files for new Ruby files in `lib/react_on_rails/` by adding corresponding `.rbs` file in `sig/react_on_rails/`, adding to Steepfile, and validating before committing
Applied to files:
bin/lefthook/eslint-lintCONTRIBUTING.md.gitignorebin/lefthook/prettier-formatpackages/react-on-rails-pro/scripts/check-react-version.cjs.github/workflows/integration-tests.ymlreact_on_rails/rakelib/shakapacker_examples.rakeCLAUDE.mdpackages/react-on-rails-pro/package.jsonknip.ts.github/workflows/lint-js-and-ruby.ymlscript/convertCHANGELOG.mdreact_on_rails/rakelib/release.rake
📚 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:
bin/lefthook/eslint-lintpackages/react-on-rails-pro/scripts/check-react-version.cjspackages/react-on-rails-pro/package.jsonscript/convertCHANGELOG.md
📚 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:
CONTRIBUTING.mdpackages/react-on-rails/package.json.github/workflows/pro-test-package-and-gem.ymlreact_on_rails_pro/spec/execjs-compatible-dummy/package.jsonreact_on_rails/rakelib/dummy_apps.rake.claude/docs/testing-build-scripts.md.github/workflows/integration-tests.ymlreact_on_rails/rakelib/shakapacker_examples.rakeCLAUDE.md.github/workflows/pro-lint.ymlpackages/react-on-rails-pro/package.jsonreact_on_rails_pro/spec/dummy/package.jsonscript/convertCHANGELOG.md.github/workflows/pro-integration-tests.ymlreact_on_rails/spec/dummy/package.jsonpackage.json
📚 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:
CONTRIBUTING.md.gitignorepackages/react-on-rails/package.jsonpackages/react-on-rails-pro-node-renderer/package.jsonreact_on_rails_pro/spec/execjs-compatible-dummy/package.jsonpackages/react-on-rails-pro/scripts/check-react-version.cjsreact_on_rails/rakelib/dummy_apps.rakereact_on_rails/rakelib/node_package.rake.github/workflows/integration-tests.ymlreact_on_rails/rakelib/shakapacker_examples.rakeCLAUDE.mdpackages/react-on-rails-pro/package.jsonknip.ts.github/workflows/lint-js-and-ruby.ymlreact_on_rails_pro/spec/dummy/package.jsonscript/convertCHANGELOG.mdreact_on_rails/rakelib/release.rakereact_on_rails/spec/dummy/package.jsonpackage.json
📚 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:
CONTRIBUTING.md.gitignorepackages/react-on-rails-pro-node-renderer/package.jsonreact_on_rails_pro/spec/execjs-compatible-dummy/package.jsonpackages/react-on-rails-pro/scripts/check-react-version.cjsreact_on_rails/rakelib/dummy_apps.rakereact_on_rails/rakelib/lint.rakereact_on_rails/rakelib/shakapacker_examples.rakepackages/react-on-rails-pro/package.jsonknip.ts.github/workflows/lint-js-and-ruby.ymlreact_on_rails_pro/spec/dummy/package.jsonscript/convertCHANGELOG.mdreact_on_rails/rakelib/release.rakereact_on_rails/spec/dummy/package.jsonpackages/react-on-rails-pro/tests/jest.setup.jspackage.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:
CONTRIBUTING.mdpackages/react-on-rails-pro/scripts/check-react-version.cjsCHANGELOG.mdreact_on_rails/rakelib/release.rake
📚 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:
CONTRIBUTING.mdpackages/react-on-rails-pro/package.jsonCHANGELOG.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to spec/dummy/e2e/playwright/**/*.spec.js : Use Rails helpers (`appFactories`, `appEval`) in Playwright tests instead of UI-based setup to leverage factory_bot and arbitrary Ruby code execution
Applied to files:
CONTRIBUTING.md.github/workflows/pro-test-package-and-gem.yml.github/workflows/playwright.ymlreact_on_rails/rakelib/dummy_apps.rake.github/workflows/integration-tests.ymlCLAUDE.md.github/workflows/pro-lint.ymlreact_on_rails_pro/spec/dummy/package.json.github/workflows/pro-integration-tests.ymlpackages/react-on-rails-pro/tests/jest.setup.js
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to spec/dummy/e2e/playwright/app_commands/**/*.rb : Add custom Playwright app commands in `e2e/playwright/app_commands/` directory as Ruby files using CypressOnRails SmartFactoryWrapper pattern
Applied to files:
CONTRIBUTING.md.github/workflows/playwright.ymlreact_on_rails/rakelib/dummy_apps.rakereact_on_rails/rakelib/lint.rake.github/workflows/integration-tests.ymlreact_on_rails/rakelib/shakapacker_examples.rakeCLAUDE.md.github/workflows/pro-lint.yml.github/workflows/pro-integration-tests.yml
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to spec/dummy/e2e/playwright/**/*.spec.js : Generate test data in Playwright tests using `appFactories` function with factory_bot syntax (e.g., `appFactories([['create', 'user', { name: 'Test User' }]])`) rather than manual database manipulation
Applied to files:
CONTRIBUTING.md.github/workflows/pro-test-package-and-gem.ymlreact_on_rails/rakelib/dummy_apps.rake.github/workflows/integration-tests.ymlCLAUDE.md.github/workflows/pro-lint.yml.github/workflows/pro-integration-tests.ymlpackages/react-on-rails-pro/tests/jest.setup.js
📚 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:
CONTRIBUTING.mdpackages/react-on-rails-pro/tests/jest.setup.js
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to **/*.{rb,rake} : ALWAYS run `bundle exec rubocop` and fix ALL violations before every commit/push
Applied to files:
CONTRIBUTING.md.gitignore.claude/docs/testing-build-scripts.mdreact_on_rails/rakelib/lint.rakereact_on_rails/rakelib/shakapacker_examples.rakeCLAUDE.md.github/workflows/pro-lint.yml.github/workflows/lint-js-and-ruby.yml
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: ALWAYS let Prettier and RuboCop handle ALL formatting - never manually format
Applied to files:
CONTRIBUTING.mdbin/lefthook/prettier-formatreact_on_rails/rakelib/lint.rakeCLAUDE.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Exclude `/coverage`, `/tmp`, `/gen-examples`, `/packages/react-on-rails/lib`, `/node_modules`, `/spec/dummy/node_modules`, `/spec/dummy/tmp`, `/spec/dummy/app/assets/webpack`, `/spec/dummy/log`, `/spec/dummy/e2e/playwright-report`, `/spec/dummy/test-results` from IDE indexing
Applied to files:
CONTRIBUTING.md.gitignorepackages/react-on-rails-pro-node-renderer/package.json.claude/docs/testing-build-scripts.mdpnpm-workspace.yaml.github/workflows/integration-tests.ymlCLAUDE.md.github/workflows/pro-lint.ymlpackages/react-on-rails-pro/package.jsonknip.ts.github/workflows/lint-js-and-ruby.ymlreact_on_rails_pro/spec/dummy/package.jsonscript/convertpackage.json
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Resolve merge conflicts by: resolving logical conflicts first, verifying file paths with grep, testing affected scripts, auto-fixing formatting with `rake autofix`, and testing critical scripts if build configs changed
Applied to files:
CONTRIBUTING.md.claude/docs/testing-build-scripts.mdreact_on_rails/rakelib/lint.rakeCLAUDE.md.github/workflows/lint-js-and-ruby.ymlscript/convert
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to sig/react_on_rails/**/*.rbs : In RBS type signature files, define type signatures that correspond to Ruby files in `lib/react_on_rails/`
Applied to files:
.gitignoreknip.ts
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to /CHANGELOG_PRO.md : Update `/CHANGELOG_PRO.md` for Pro-only features, fixes, and changes affecting Pro packages
Applied to files:
.github/workflows/pro-test-package-and-gem.yml.github/workflows/pro-lint.ymlscript/convertCHANGELOG.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to spec/dummy/e2e/playwright/**/*.spec.js : In Playwright E2E tests, use `app('clean')` in `beforeEach` blocks to ensure clean database state between tests
Applied to files:
.github/workflows/playwright.ymlCLAUDE.md.github/workflows/pro-integration-tests.yml
📚 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 is handled in deeper level calls of the React on Rails Pro codebase, so it doesn't need to be validated again in the `rsc_payload_react_component` helper method.
Applied to files:
packages/react-on-rails-pro/scripts/check-react-version.cjsCHANGELOG.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: For infrastructure/config changes affecting directory structure, file paths, build configurations, or CI workflows, conduct comprehensive local testing before pushing (the '15-Minute Rule')
Applied to files:
.claude/docs/testing-build-scripts.mdCLAUDE.md.github/workflows/examples.yml
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: NEVER push without running full lint check first
Applied to files:
.claude/docs/testing-build-scripts.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to /CHANGELOG*.md : Use changelog format: `[PR 1818](https://github.com/shakacode/react_on_rails/pull/1818) by [username](https://github.com/username)` (no hash in PR number)
Applied to files:
CLAUDE.mdCHANGELOG.md
📚 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:
CLAUDE.mdpackages/react-on-rails-pro/package.jsonknip.tsreact_on_rails/spec/dummy/package.jsonpackages/react-on-rails-pro/tests/jest.setup.js
📚 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:
packages/react-on-rails-pro/package.jsonknip.tsCHANGELOG.md
📚 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:
script/convert
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Do NOT add changelog entries for linting, formatting, refactoring, tests, or documentation fixes
Applied to files:
CHANGELOG.md
🪛 LanguageTool
CONTRIBUTING.md
[uncategorized] ~22-~22: “React” is a proper noun and needs to be capitalized.
Context: ...sites Note for users: End users of react_on_rails can continue using their prefe...
(A_GOOGLE)
[uncategorized] ~22-~22: “React” is a proper noun and needs to be capitalized.
Context: ...low are for contributors working on the react_on_rails codebase itself. - [Yalc](htt...
(A_GOOGLE)
[style] ~310-~310: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...figs, then you need to restart Foreman. If you change the JS code for react-on-rai...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🪛 markdownlint-cli2 (0.18.1)
.claude/docs/testing-build-scripts.md
114-114: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🔇 Additional comments (56)
knip.ts (3)
41-45: LGTM!The new ignoreDependencies entries are well-documented and correctly identify tooling that Knip cannot auto-detect (nps via YAML config, validation tools used in scripts).
179-182: LGTM!The updated comments more accurately describe how these dependencies are used (webpack for runtime polyfills, CSS extraction for MiniCssExtractPlugin).
201-201: No action required—the file correctly ends with a trailing newline.The
knip.tsfile already complies with the coding guideline requirement to end with a newline character. No changes are needed.packages/react-on-rails-pro/tests/jest.setup.js (4)
1-4: LGTM—static imports improve ES module compliance.The migration from runtime
require()calls to staticimportstatements at the top of the file follows ES module conventions and improves clarity.
74-74: File ends with newline — no issue.The file
packages/react-on-rails-pro/tests/jest.setup.jsalready ends with a newline character, meeting the coding guideline requirement. No action needed.
34-34: Node.js version compatibility is satisfied; Readable.toWeb() is supported in the project's minimum supported Node.js version.The project's minimum supported Node.js version is 20 (per CI matrix in
package-js-tests.yml), which exceeds the 17.0.0 requirement forReadable.toWeb(). The.nvmrcspecifies 22.12.0 and CI workflows test against Node.js 22 and 20. No version compatibility issues exist.
24-39: Perfect. Now I have all the information I need. Let me verify one final detail about the jest mock hoisting in ESM:
<function_calls>
jest.mock hoisting ES modules @jest/globals setupFiles conditional
</function_calls>Based on my comprehensive verification, I can now provide the rewritten review comment:
The jest.mock in jest.setup.js is correctly placed and functioning as intended; no changes needed.
The jest.mock at lines 24-39 is in a setupFiles configuration file that runs during jest initialization (before any tests), not during test execution. While jest.mock is typically at the top level, calling it within a conditional at module load time in a setup file is a valid pattern in ESM with @jest/globals.
Evidence:
jest.config.jsconfiguressetupFiles: ['<rootDir>/tests/jest.setup.js'], meaning this file runs synchronously during jest initialization- The test
utils.test.jssuccessfully verifies the mock works: it assertsexpect(body).toBeInstanceOf(ReadableStream), confirming the fetch response body is correctly converted from Node's Readable stream to Web ReadableStream- The
testEnvironment: 'jsdom'in the base config ensureswindowis defined when needed, making the conditional check valid- No test failures are reported in CI
The conditional
if (typeof window !== 'undefined')is appropriate here for environment detection at module load time, and the mock is properly registered before any imports that depend on it..gitignore (1)
1-2: Root Gemfile.lock ignore is consistent with monorepo layoutIgnoring
/Gemfile.lockat the root while documenting that the real lock lives underreact_on_rails/keeps the VCS state clean and avoids confusion between locks.pnpm-workspace.yaml (1)
1-2: Workspace scope definition is saneDeclaring
packages/*as the workspace root matches the typical monorepo layout here and should work well with the pnpm filters used elsewhere.react_on_rails_pro/spec/dummy/client/app/components/LazyApolloGraphQL.tsx (1)
80-82: Structured error rendering is reasonableSwitching to
JSON.stringify(updateError)should surface more detail than.toString()in this dummy component and is fine for debugging-oriented UI.packages/react-on-rails/package.json (1)
8-15: Build and type-check scripts align with pnpm toolingUsing
pnpm run clean && tscfor build, a dedicatedtype-checkscript withtsc --noEmit, andpnpm run buildinprepublishOnlyfits the pnpm migration and keeps package scripts straightforward.react_on_rails/rakelib/node_package.rake (1)
10-10: Node package build task correctly migrated to pnpmUpdating the task to
sh "pnpm run build && pnpm yalc:publish"removes the last yarn dependency and matches the pnpm-only tooling direction.react_on_rails/rakelib/lint.rake (1)
20-21: Lint tasks correctly switched to pnpmUpdating eslint, prettier, and stylelint invocations to
pnpm run …aligns the Ruby rake lint tasks with the pnpm-based JS tooling and keeps all linting routed through the workspace scripts.Also applies to: 30-31, 40-40
CONTRIBUTING.md (1)
22-38: PNPM contributor guidance and setup commands look consistentThe new note clearly distinguishes end‑user package manager freedom from pnpm‑only contributor workflows, and the updated setup command (
bundle && pnpm install && rake …) matches the rest of the repo’s pnpm migration. No issues here.Also applies to: 31-34
packages/react-on-rails-pro/scripts/check-react-version.cjs (1)
1-19: React-version gate for RSC tests is correctThe script correctly treats React
<19as “skip RSC tests” (exit 0) and React≥19as “run RSC tests” (exit 1 so the surrounding|| jest …chain executes). This aligns with the test:rsc auto‑detection behavior described elsewhere.CHANGELOG.md (1)
34-35: PNPM migration changelog entry is well‑formedThe new Unreleased “Package Manager Migration to pnpm (Contributors Only)” entry follows the project’s changelog format and accurately scopes the change to contributors. Looks good.
react_on_rails/rakelib/release.rake (1)
259-278: PNPM-based NPM publishing flow looks correctSwitching to
pnpm publishfor:
packages/react-on-railspackages/react-on-rails-proreact_on_rails_pro(node renderer, with--no-git-checks)reuses the
npm_publish_args(registry + OTP when hitting npmjs.org) and keeps Verdaccio support. This matches the repository’s pnpm-only policy and the new unified release behavior.CLAUDE.md (1)
135-158: PNPM-centric development guidance is consistent and clearThe updated Essential Commands, linting/formatting, build, and changelog sections consistently use
pnpmand explicitly forbidnpmfor repo work, which matches the project’s tooling direction. The commands (pnpm install,pnpm run test,pnpm run lint,pnpm run format.listDifferent,pnpm run build,pnpm run type-check) look coherent with the rest of the monorepo.Also applies to: 279-317
.github/workflows/examples.yml (1)
119-188: Examples workflow correctly migrates to PNPM and splits latest/minimum example setsThe workflow now:
- Sets up pnpm with a cached store and prints its version.
- Installs Node deps via
pnpm install(frozen forlatest, non‑frozen forminimum) and usespnpm yalc:publishpluspnpm add -g yalcfor the local package flow.- Runs
script/convertonly for theminimumdependency level, which matches the script’s new “minimum toolchain” responsibility.- Routes example specs through the new tasks:
run_rspec:shakapacker_examples_latestfor latest deps,run_rspec:shakapacker_examples_minimumfor minimum deps.This is consistent with the CI story described in the PR and the rest of the pnpm migration.
Also applies to: 151-158
.claude/docs/testing-build-scripts.md (1)
7-59: Build-script testing guidance now matches PNPM-based workflowsThe updated doc:
- Emphasizes clean
pnpm install --frozen-lockfile,pnpm run build,pnpm run prepack, andpnpm run yalc:publishas mandatory checks after changing package.json or build configs.- Calls out workspace-specific behavior and the need to use
workspace:*with pnpm, plus verification viapnpm -r listand a fresh install.- Grounded real-world examples (path issues, workspace protocol migration) in PNPM terms.
This aligns well with the current tooling and should help prevent future silent build/publish regressions.
Also applies to: 41-59, 113-159
bin/lefthook/prettier-format (1)
26-26: LGTM! Correct pnpm migration.The migration from
yarn run prettiertopnpm exec prettieris correct and consistent with the broader pnpm adoption across the codebase.Also applies to: 41-41
bin/lefthook/eslint-lint (1)
34-34: LGTM! Correct pnpm migration.The migration from
yarn run eslinttopnpm exec eslintis correct and maintains proper separation of root and Pro directory linting.Also applies to: 51-51
packages/react-on-rails-pro-node-renderer/package.json (2)
50-50: LGTM! Correct workspace dependency syntax.The change to
"react-on-rails": "workspace:*"is the correct pnpm syntax for monorepo workspace dependencies, replacing Yarn's plain"*"syntax.
73-82: LGTM! Scripts properly migrated to pnpm.All script commands have been correctly updated to use
pnpm runinstead of yarn equivalents. The removal of the resolutions block is also correct, as pnpm uses overrides (defined in the root package.json).react_on_rails/rakelib/dummy_apps.rake (1)
8-12: LGTM! Correct pnpm migration in Rake task.The task has been properly renamed and the command updated. Note that the
--mutex networkflag was correctly removed as pnpm has built-in lock file management.Per coding guidelines, ensure this file has been checked with RuboCop:
#!/bin/bash bundle exec rubocop react_on_rails/rakelib/dummy_apps.rake.github/workflows/pro-lint.yml (2)
158-162: LGTM! Correct use of --ignore-workspace flag.The
--ignore-workspaceflag is correctly used for dummy app installations to prevent pnpm from treating them as part of the parent workspace. This ensures proper dependency isolation for test scenarios.
100-115: pnpm-lock.yaml exists and is properly committed—no action needed.The verification confirms
pnpm-lock.yamlis present in the repository root, tracked in git, and the cache key configuration at line 111 of the workflow will function correctly. The lock file exists and is committed, so the cache mechanism will work as intended..github/workflows/pro-test-package-and-gem.yml (3)
102-115: Verify pnpm-lock.yaml exists for cache keys.Both jobs in this workflow use
pnpm-lock.yamlfor cache keys. Ensure this file is committed to the repository for proper caching.Same verification as pro-lint.yml applies - see comment on that file.
Also applies to: 207-220
135-140: LGTM! Correct pnpm installation with frozen lockfile.The use of
pnpm install --frozen-lockfileensures deterministic, reproducible installs in CI. The--ignore-workspaceflag for dummy apps correctly isolates their dependencies.Also applies to: 249-250
253-254: LGTM! Proper use of pnpm filter for monorepo workspace.The
pnpm --filtercommand correctly targets the specific package in the monorepo workspace for testing.package.json (1)
58-59: Update @types/react and @types/react-dom to React 19 versions; function component propTypes in spec/dummy will be silently ignored.The upgrade to React 19 has been partially applied. While the main dependencies are updated, there are two compatibility concerns:
TypeScript Types Mismatch: @types/react and @types/react-dom are still pinned to v18 (lines 31-32), not v19. These should be updated to
^19.0.0to match React and ensure proper type checking.Function Component propTypes: Multiple function components in spec/dummy use propTypes (HelloWorldProps.jsx, HelloWorldHooks.jsx, RailsContext.jsx, HelloWorldContainer.jsx, etc.), which React 19 silently ignores. In React 19, propTypes checks are removed entirely. Class component propTypes (static propTypes) work fine, but function component propTypes will no longer provide runtime validation.
Actions needed:
- Update @types/react and @types/react-dom to ^19.0.0
- Consider removing propTypes from function components in spec/dummy or migrating to the standalone prop-types package with runtime validation
- The production code appropriately uses TypeScript instead of propTypes
.github/workflows/package-js-tests.yml (2)
101-112: LGTM! pnpm setup and caching is correctly configured.The pnpm setup follows the recommended pattern: action setup, store path retrieval, and cache configuration with
pnpm-lock.yamlhash key. This is consistent with the pnpm migration across other workflow files.
123-130: LGTM! pnpm commands correctly replace Yarn equivalents.The conditional
--frozen-lockfilelogic correctly allows lockfile updates for Node 20 (minimum version testing via conversion script) while enforcing frozen lockfile for Node 22 (latest). Global yalc installation via pnpm aligns with the project's package management standards..github/workflows/lint-js-and-ruby.yml (3)
101-112: LGTM! pnpm setup follows the established pattern.The pnpm setup and caching configuration is consistent with other workflow files in this PR.
136-139: Good use of--ignore-workspacefor dummy app isolation.The
--ignore-workspaceflag correctly prevents pnpm from treating the dummy app as part of the parent workspace, which is essential since it has its own dependencies and uses yalc links. The explanatory comment is helpful.
167-185: LGTM! Linting commands correctly migrated to pnpm.All linting tools are correctly invoked via
pnpm execorpnpm runas appropriate. Thepnpm startcommand for format.listDifferent correctly uses the nps (package-scripts) runner..github/workflows/playwright.yml (2)
56-69: LGTM! pnpm setup and caching correctly configured.The pnpm setup follows the established pattern used consistently across the PR's workflow files.
71-100: LGTM! Playwright workflow correctly migrated to pnpm.All dependency installation and test execution commands are correctly using pnpm equivalents. The
--ignore-workspaceflag for the dummy app andpnpm execfor Playwright browser installation are appropriate.react_on_rails/rakelib/shakapacker_examples.rake (2)
21-73: Well-structured minimum version application with proper error handling.The
apply_minimum_versionsmethod correctly:
- Handles JSON parsing errors with informative output and re-raises to fail CI fast
- Updates both
dependenciesanddevDependenciesfor React, Shakapacker, and webpack-assets-manifest- Updates Gemfile with exact Shakapacker version pin
- Provides clear output of the applied versions
The RuboCop disables for complexity metrics are acceptable given this is a configuration-focused method.
117-127: Good solution for Bundler isolation in minimum-version examples.The
BUNDLE_GEMFILEandBUNDLE_FROZEN=falseenvironment variables correctly address the CI issue mentioned in PR comments where generated apps were loading the wrong Shakapacker version from the parent workspace's vendor/bundle. This ensures the generated app uses its own Gemfile with the pinned minimum Shakapacker version..github/workflows/pro-integration-tests.yml (5)
101-115: LGTM! pnpm setup consistent across Pro integration workflow.The pnpm setup pattern is correctly replicated across all three jobs in this workflow (build-dummy-app-webpack-test-bundles, rspec-dummy-app-node-renderer, dummy-app-node-renderer-e2e-tests).
138-141: Good use of--ignore-workspacewith clear documentation.The comment explaining why
--ignore-workspaceis needed for the Pro dummy app is helpful for maintainability.
351-356: LGTM! Artifact naming correctly reflects pnpm migration.The debug log artifact is appropriately renamed from yarn to pnpm context.
501-513: Note the 5x timeout increase for E2E tests.The Rails server wait timeout is 300s here (E2E tests job) vs 60s in the rspec-dummy-app-node-renderer job (line 301). This difference is likely intentional since E2E tests may have heavier initialization, but verify this is the expected behavior.
515-519: LGTM! Playwright commands correctly migrated to pnpm.The Playwright installation and E2E test execution correctly use pnpm commands.
.github/workflows/integration-tests.yml (5)
122-133: PNPM setup is correctly configured and duplicated appropriately.The PNPM setup steps (pnpm/action-setup, store path retrieval, cache configuration) are properly duplicated across both jobs. This is standard practice in GitHub Actions since jobs run independently. The cache key glob pattern
**/pnpm-lock.yamlcorrectly targets the monorepo root lockfile.Also applies to: 211-222
147-149: Conditional frozen-lockfile logic supports both reproducible and compatibility testing.The conditional
${{ matrix.dependency-level == 'latest' && '--frozen-lockfile' || '--no-frozen-lockfile' }}correctly:
- Uses
--frozen-lockfilefor latest runs to ensure reproducible builds- Uses
--no-frozen-lockfilefor minimum runs (older Node/Ruby) to test compatibilityThe
--ignore-workspaceflag for dummy app installs (lines 154–157, 260–263) is correct, as the dummy app has its own dependency scope and should not inherit workspace constraints.Also applies to: 252-255, 260-263
143-145: Conversion script scope aligns with PR objectives.The conversion script is correctly run only when
dependency-level == 'minimum'(for older Ruby/Node compatibility). Per PR objectives, the script now handles only Node.js tooling compatibility and no longer modifies React/Shakapacker versions. The spec/dummy app maintains React 19 and Shakapacker 9.4.0 regardless of matrix level, which is correct.Also applies to: 232-234
80-85: Matrix setup correctly tests latest and minimum Ruby/Node versions.The
setup-integration-matrixjob correctly generates two matrix configurations:
- Latest: Ruby 3.4, Node 22 (for fast PR feedback)
- Minimum: Ruby 3.2, Node 20 (full CI, master, or workflow_dispatch only)
This aligns with the PR objectives: spec/dummy always uses React 19/Shakapacker 9.4.0, but the matrix ensures compatibility across supported Ruby/Node versions.
328-329: Verify file ends with a newline character.The artifact name correctly changed from
yarn-debug.logtopnpm-debug.log. However, ensure the file ends with a newline after the closing braces on line 329, per coding guidelines.react_on_rails/spec/dummy/package.json (3)
21-28: React 19 dependencies are correctly updated.The upgrade from React 18 to ^19.0.0 includes critical dependency updates:
- react-helmet replaced with @dr.pogodin/react-helmet@^3.0.4 (React 19 compatible)
- react-redux upgraded to ^9.2.0 (adds React 19 peer dependency support)
- redux upgraded to ^5.0.1 and redux-thunk to ^3.1.0
Per past review comments, these changes were already implemented and verified in commits db1c0fd to dbc7a32. No further action needed.
69-86: PNPM scripts correctly migrated from Yarn.All build, test, and utility scripts properly use
pnpm runcommands:
- preinstall, link-source, lint, format delegate via pnpm
- test:js invokes jest directly (pnpm automatically includes node_modules/.bin in PATH)
- build commands correctly chain pnpm and bin/shakapacker
The packageManager field (line 89) ensures the team enforces [email protected] usage.
1-89: Verify trailing newline at end of file.Ensure this file ends with a newline character after the closing brace, per coding guidelines.
packages/react-on-rails-pro/package.json (3)
58-58: Workspace dependency resolution is correctly configured.The change from
"react-on-rails": "*"to"react-on-rails": "workspace:*"correctly uses PNPM's workspace protocol. This ensures the pro package depends on the local react-on-rails package in the monorepo, matching the PNPM workspace setup referenced in pnpm-workspace.yaml.
7-15: PNPM scripts and TypeScript compilation are correctly configured.All scripts properly delegate to pnpm and tsc:
- build and build-watch clean and compile with tsc
- test chains test:non-rsc and test:rsc via pnpm
- test:rsc conditionally runs jest with NODE_CONDITIONS=react-server (gates RSC tests)
- prepublishOnly ensures build runs before publishing
1-82: Verify trailing newline at end of file.Ensure this file ends with a newline character after the closing brace, per coding guidelines.
| // Export disableHttp2 for test utilities | ||
| 'src/worker.ts!', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Script executed:
# First, locate and examine the knip.ts file
fd -t f "knip.ts" --exec cat -n {} \; | head -100
# Then check for the package.json in react-on-rails-pro-node-renderer
fd -t f "package.json" | grep -i "react-on-rails-pro-node-renderer" | head -5Repository: shakacode/react_on_rails
<shell_result>
Repository: shakacode/react_on_rails
Exit code: 0
stdout:
1 import type { KnipConfig } from 'knip';
2
3 const config: KnipConfig = {
4 // ! at the end means files are used in production
5 workspaces: {
6 // Root workspace - manages the monorepo and global tooling
7 '.': {
8 entry: ['eslint.config.ts', 'jest.config.base.js'],
9 project: ['*.{js,mjs,ts}'],
10 ignoreBinaries: [
11 // Has to be installed globally
12 'yalc',
13 // Pro package binaries used in Pro workflows
14 'playwright',
15 'e2e-test',
16 ],
17 ignore: ['react_on_rails_pro/**', 'react_on_rails/vendor/**'],
18 ignoreDependencies: [
19 // Required for TypeScript compilation, but we don't depend on Turbolinks itself.
20 '@types/turbolinks',
21 // The Knip ESLint plugin fails to detect these are transitively required by a config,
22 // though we don't actually use its rules anywhere.
23 '@babel/eslint-parser',
24 '@babel/preset-react',
25 'eslint-config-shakacode',
26 'eslint-plugin-jsx-a11y',
27 'eslint-plugin-react',
28 'eslint-plugin-react-hooks',
29 // These are used as transitive dependencies and missing from package.json
30 '@eslint/eslintrc',
31 '@eslint/js',
32 // used by Jest
33 'jsdom',
34 'jest-junit',
35 // This is an optional peer dependency because users without RSC don't need it
36 // but Knip doesn't like such dependencies to be referenced directly in code
37 'react-on-rails-rsc',
38 // SWC transpiler dependencies used by Shakapacker in dummy apps
39 '@swc/core',
40 'swc-loader',
41 // Used via nps (package-scripts.yml) which knip doesn't fully analyze
42 'nps',
43 // Used for package validation but not directly imported
44 '@arethetypeswrong/cli',
45 'publint',
46 ],
47 },
48
49 // React on Rails core package workspace
50 'packages/react-on-rails': {
51 entry: [
52 'src/ReactOnRails.full.ts!',
53 'src/ReactOnRails.client.ts!',
54 'src/base/full.rsc.ts!',
55 'src/context.ts!',
56 ],
57 project: ['src/**/*.[jt]s{x,}!', 'tests/**/*.[jt]s{x,}', '!lib/**'],
58 ignore: [
59 // Jest setup and test utilities - not detected by Jest plugin in workspace setup
60 'tests/jest.setup.js',
61 // Build output directories that should be ignored
62 'lib/**',
63 ],
64 },
65
66 // React on Rails Pro Node Renderer package workspace
67 'packages/react-on-rails-pro-node-renderer': {
68 entry: [
69 'src/ReactOnRailsProNodeRenderer.ts!',
70 'src/default-node-renderer.ts!',
71 'src/integrations/*.ts!',
72 // Export disableHttp2 for test utilities
73 'src/worker.ts!',
74 ],
75 project: ['src/**/*.[jt]s{x,}!', 'tests/**/*.[jt]s{x,}', '!lib/**'],
76 ignore: [
77 // Build output directories that should be ignored
78 'lib/**',
79 // Test fixtures
80 'tests/fixtures/**',
81 // Test helper utilities
82 'tests/helper.ts',
83 'tests/httpRequestUtils.ts',
84 ],
85 ignoreDependencies: [
86 // Optional dependencies used in integrations
87 '@honeybadger-io/js',
88 '@sentry/*',
89 // Jest reporter used in CI
90 'jest-junit',
91 ],
92 },
93
94 // React on Rails Pro package workspace
95 'packages/react-on-rails-pro': {
96 entry: [
97 'src/ReactOnRails.node.ts!',
98 'src/ReactOnRails.full.ts!',
99 'src/ReactOnRails.client.ts!',
100 'src/ReactOnRailsRSC.ts!',
packages/react-on-rails-pro-node-renderer/package.json
</shell_result>
Script executed:
# Check the package.json to see what's exported
cat packages/react-on-rails-pro-node-renderer/package.json | jq '.exports'
# Read worker.ts to see what disableHttp2 is
cat packages/react-on-rails-pro-node-renderer/src/worker.tsRepository: shakacode/react_on_rails
<shell_result>
Repository: shakacode/react_on_rails
Exit code: 0
stdout:
{
".": {
"types": "./lib/ReactOnRailsProNodeRenderer.d.ts",
"default": "./lib/ReactOnRailsProNodeRenderer.js"
},
"./integrations/*": {
"types": "./lib/integrations/*.d.ts",
"default": "./lib/integrations/*.js"
},
"./package.json": "./package.json"
}
/**
* Entry point for worker process that handles requests.
* @module worker
*/
import path from 'path';
import cluster from 'cluster';
import { mkdir } from 'fs/promises';
import fastify from 'fastify';
import fastifyFormbody from '@fastify/formbody';
import fastifyMultipart from '@fastify/multipart';
import log, { sharedLoggerOptions } from './shared/log.js';
import packageJson from './shared/packageJson.js';
import { buildConfig, Config, getConfig } from './shared/configBuilder.js';
import fileExistsAsync from './shared/fileExistsAsync.js';
import type { FastifyInstance, FastifyReply, FastifyRequest } from './worker/types.js';
import checkProtocolVersion from './worker/checkProtocolVersionHandler.js';
import authenticate from './worker/authHandler.js';
import { handleRenderRequest, type ProvidedNewBundle } from './worker/handleRenderRequest.js';
import handleGracefulShutdown from './worker/handleGracefulShutdown.js';
import {
errorResponseResult,
formatExceptionMessage,
copyUploadedAssets,
ResponseResult,
workerIdLabel,
saveMultipartFile,
Asset,
getAssetPath,
getBundleDirectory,
deleteUploadedAssets,
} from './shared/utils.js';
import * as errorReporter from './shared/errorReporter.js';
import { lock, unlock } from './shared/locks.js';
import { startSsrRequestOptions, trace } from './shared/tracing.js';
// Uncomment the below for testing timeouts:
// import { delay } from './shared/utils.js';
//
// function getRandomInt(max) {
// return Math.floor(Math.random() * Math.floor(max));
// }
declare module '@fastify/multipart' {
interface MultipartFile {
// We save all uploaded files and store this value
value: Asset;
}
}
export type FastifyConfigFunction = (app: FastifyInstance) => void;
const fastifyConfigFunctions: FastifyConfigFunction[] = [];
/**
* Configures Fastify instance before starting the server.
* @param configFunction The configuring function. Normally it will be something like `(app) => { app.register(...); }`
* or `(app) => { app.addHook(...); }` to report data from Fastify to an external service.
* Note that we call `await app.ready()` in our code, so you don't need to `await` the results.
*/
export function configureFastify(configFunction: FastifyConfigFunction) {
fastifyConfigFunctions.push(configFunction);
}
function setHeaders(headers: ResponseResult['headers'], res: FastifyReply) {
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- fixing it with `void` just violates no-void
Object.entries(headers).forEach(([key, header]) => res.header(key, header));
}
const setResponse = async (result: ResponseResult, res: FastifyReply) => {
const { status, data, headers, stream } = result;
if (status !== 200 && status !== 410) {
log.info({ msg: 'Sending non-200, non-410 data back', data });
}
setHeaders(headers, res);
res.status(status);
if (stream) {
await res.send(stream);
} else {
res.send(data);
}
};
const isAsset = (value: unknown): value is Asset => (value as { type?: string }).type === 'asset';
function assertAsset(value: unknown, key: string): asserts value is Asset {
if (!isAsset(value)) {
throw new Error(`React On Rails Error: Expected an asset for key: ${key}`);
}
}
// Remove after this issue is resolved: https://github.com/fastify/light-my-request/issues/315
let useHttp2 = true;
// Call before any test using `app.inject()`
export const disableHttp2 = () => {
useHttp2 = false;
};
type WithBodyArrayField<T, K extends string> = T & { [P in K | `${K}[]`]?: string | string[] };
const extractBodyArrayField = <Key extends string>(
body: WithBodyArrayField<Record<string, unknown>, Key>,
key: Key,
): string[] | undefined => {
const value = body[key] ?? body[`${key}[]`];
if (Array.isArray(value)) {
return value;
}
if (typeof value === 'string' && value.length > 0) {
return [value];
}
return undefined;
};
export default function run(config: Partial<Config>) {
// Store config in app state. From now it can be loaded by any module using
// getConfig():
buildConfig(config);
const { serverBundleCachePath, logHttpLevel, port, fastifyServerOptions, workersCount } = getConfig();
const app = fastify({
http2: useHttp2 as true,
bodyLimit: 104857600, // 100 MB
logger:
logHttpLevel !== 'silent' ? { name: 'RORP HTTP', level: logHttpLevel, ...sharedLoggerOptions } : false,
...fastifyServerOptions,
});
handleGracefulShutdown(app);
// We shouldn't have unhandled errors here, but just in case
app.addHook('onError', (req, res, err, done) => {
// Not errorReporter.error so that integrations can decide how to log the errors.
app.log.error({ msg: 'Unhandled Fastify error', err, req, res });
done();
});
// 10 MB limit for code including props
const fieldSizeLimit = 1024 * 1024 * 10;
// Supports application/x-www-form-urlencoded
void app.register(fastifyFormbody);
// Supports multipart/form-data
void app.register(fastifyMultipart, {
attachFieldsToBody: 'keyValues',
limits: {
fieldSize: fieldSizeLimit,
// For bundles and assets
fileSize: Infinity,
},
onFile: async (part) => {
const destinationPath = path.join(serverBundleCachePath, 'uploads', part.filename);
// TODO: inline here
await saveMultipartFile(part, destinationPath);
// eslint-disable-next-line no-param-reassign
part.value = {
filename: part.filename,
savedFilePath: destinationPath,
type: 'asset',
};
},
});
const isProtocolVersionMatch = async (req: FastifyRequest, res: FastifyReply) => {
// Check protocol version
const protocolVersionCheckingResult = checkProtocolVersion(req);
if (typeof protocolVersionCheckingResult === 'object') {
await setResponse(protocolVersionCheckingResult, res);
return false;
}
return true;
};
const isAuthenticated = async (req: FastifyRequest, res: FastifyReply) => {
// Authenticate Ruby client
const authResult = authenticate(req);
if (typeof authResult === 'object') {
await setResponse(authResult, res);
return false;
}
return true;
};
const requestPrechecks = async (req: FastifyRequest, res: FastifyReply) => {
if (!(await isProtocolVersionMatch(req, res))) {
return false;
}
if (!(await isAuthenticated(req, res))) {
return false;
}
return true;
};
// See https://github.com/shakacode/react_on_rails_pro/issues/119 for why
// the digest is part of the request URL. Yes, it's not used here, but the
// server logs might show it to distinguish different requests.
app.post<{
Body: WithBodyArrayField<
{
renderingRequest: string;
},
'dependencyBundleTimestamps'
>;
// Can't infer from the route like Express can
Params: { bundleTimestamp: string; renderRequestDigest: string };
}>('/bundles/:bundleTimestamp/render/:renderRequestDigest', async (req, res) => {
if (!(await requestPrechecks(req, res))) {
return;
}
// DO NOT REMOVE (REQUIRED FOR TIMEOUT TESTING)
// if(TESTING_TIMEOUTS && getRandomInt(2) === 1) {
// console.log(
// 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ');
// console.log(`Sleeping, to test timeouts`);
// console.log(
// 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ');
//
// await delay(100000);
// }
const { renderingRequest } = req.body;
const { bundleTimestamp } = req.params;
const providedNewBundles: ProvidedNewBundle[] = [];
const assetsToCopy: Asset[] = [];
Object.entries(req.body).forEach(([key, value]) => {
if (key === 'bundle') {
assertAsset(value, key);
providedNewBundles.push({ timestamp: bundleTimestamp, bundle: value });
} else if (key.startsWith('bundle_')) {
assertAsset(value, key);
providedNewBundles.push({ timestamp: key.replace('bundle_', ''), bundle: value });
} else if (isAsset(value)) {
assetsToCopy.push(value);
}
});
try {
const dependencyBundleTimestamps = extractBodyArrayField(req.body, 'dependencyBundleTimestamps');
await trace(async (context) => {
try {
const result = await handleRenderRequest({
renderingRequest,
bundleTimestamp,
dependencyBundleTimestamps,
providedNewBundles,
assetsToCopy,
});
await setResponse(result, res);
} catch (err) {
const exceptionMessage = formatExceptionMessage(
renderingRequest,
err,
'UNHANDLED error in handleRenderRequest',
);
errorReporter.message(exceptionMessage, context);
await setResponse(errorResponseResult(exceptionMessage), res);
}
}, startSsrRequestOptions({ renderingRequest }));
} catch (theErr) {
const exceptionMessage = formatExceptionMessage(renderingRequest, theErr);
errorReporter.message(`Unhandled top level error: ${exceptionMessage}`);
await setResponse(errorResponseResult(exceptionMessage), res);
}
});
// There can be additional files that might be required at the runtime.
// Since the remote renderer doesn't contain any assets, they must be uploaded manually.
app.post<{
Body: WithBodyArrayField<Record<string, Asset>, 'targetBundles'>;
}>('/upload-assets', async (req, res) => {
if (!(await requestPrechecks(req, res))) {
return;
}
let lockAcquired = false;
let lockfileName: string | undefined;
const assets: Asset[] = Object.values(req.body).filter(isAsset);
// Handle targetBundles as either a string or an array
const targetBundles = extractBodyArrayField(req.body, 'targetBundles');
if (!targetBundles || targetBundles.length === 0) {
const errorMsg = 'No targetBundles provided. As of protocol version 2.0.0, targetBundles is required.';
log.error(errorMsg);
await setResponse(errorResponseResult(errorMsg), res);
return;
}
const assetsDescription = JSON.stringify(assets.map((asset) => asset.filename));
const taskDescription = `Uploading files ${assetsDescription} to bundle directories: ${targetBundles.join(', ')}`;
try {
const { lockfileName: name, wasLockAcquired, errorMessage } = await lock('transferring-assets');
lockfileName = name;
lockAcquired = wasLockAcquired;
if (!wasLockAcquired) {
const msg = formatExceptionMessage(
taskDescription,
errorMessage,
`Failed to acquire lock ${lockfileName}. Worker: ${workerIdLabel()}.`,
);
await setResponse(errorResponseResult(msg), res);
} else {
log.info(taskDescription);
try {
// Prepare all directories first
const directoryPromises = targetBundles.map(async (bundleTimestamp) => {
const bundleDirectory = getBundleDirectory(bundleTimestamp);
// Check if bundle directory exists, create if not
if (!(await fileExistsAsync(bundleDirectory))) {
log.info(`Creating bundle directory: ${bundleDirectory}`);
await mkdir(bundleDirectory, { recursive: true });
}
return bundleDirectory;
});
const bundleDirectories = await Promise.all(directoryPromises);
// Copy assets to each bundle directory
const assetCopyPromises = bundleDirectories.map(async (bundleDirectory) => {
await copyUploadedAssets(assets, bundleDirectory);
log.info(`Copied assets to bundle directory: ${bundleDirectory}`);
});
await Promise.all(assetCopyPromises);
// Delete assets from uploads directory
await deleteUploadedAssets(assets);
await setResponse(
{
status: 200,
headers: {},
},
res,
);
} catch (err) {
const msg = 'ERROR when trying to copy assets';
const message = `${msg}. ${err}. Task: ${taskDescription}`;
log.error({
msg,
err,
task: taskDescription,
});
await setResponse(errorResponseResult(message), res);
}
}
} finally {
if (lockAcquired) {
try {
if (lockfileName) {
await unlock(lockfileName);
}
} catch (error) {
log.warn({
msg: `Error unlocking ${lockfileName} from worker ${workerIdLabel()}`,
err: error,
task: taskDescription,
});
}
}
}
});
// Checks if file exist
app.post<{
Querystring: { filename: string };
Body: WithBodyArrayField<Record<string, unknown>, 'targetBundles'>;
}>('/asset-exists', async (req, res) => {
if (!(await isAuthenticated(req, res))) {
return;
}
const { filename } = req.query;
if (!filename) {
const message = `ERROR: filename param not provided to GET /asset-exists`;
log.info(message);
await setResponse(errorResponseResult(message), res);
return;
}
// Handle targetBundles as either a string or an array
const targetBundles = extractBodyArrayField(req.body, 'targetBundles');
if (!targetBundles || targetBundles.length === 0) {
const errorMsg = 'No targetBundles provided. As of protocol version 2.0.0, targetBundles is required.';
log.error(errorMsg);
await setResponse(errorResponseResult(errorMsg), res);
return;
}
// Check if the asset exists in each of the target bundles
const results = await Promise.all(
targetBundles.map(async (bundleHash) => {
const assetPath = getAssetPath(bundleHash, filename);
const exists = await fileExistsAsync(assetPath);
if (exists) {
log.info(`/asset-exists Uploaded asset DOES exist in bundle ${bundleHash}: ${assetPath}`);
} else {
log.info(`/asset-exists Uploaded asset DOES NOT exist in bundle ${bundleHash}: ${assetPath}`);
}
return { bundleHash, exists };
}),
);
// Asset exists if it exists in all target bundles
const allExist = results.every((result) => result.exists);
await setResponse({ status: 200, data: { exists: allExist, results }, headers: {} }, res);
});
app.get('/info', (_req, res) => {
res.send({
node_version: process.version,
renderer_version: packageJson.version,
});
});
// In tests we will run worker in master thread, so we need to ensure server
// will not listen:
// we are extracting worker from cluster to avoid false TS error
const { worker } = cluster;
if (workersCount === 0 || cluster.isWorker) {
app.listen({ port }, () => {
const workerName = worker ? `worker #${worker.id}` : 'master (single-process)';
log.info(`Node renderer ${workerName} listening on port ${port}!`);
});
}
fastifyConfigFunctions.forEach((configFunction) => {
configFunction(app);
});
return app;
}
</shell_result>
Script executed:
# Search for disableHttp2 usage in the codebase
rg -n "disableHttp2" --type ts --type tsx -C 2Repository: shakacode/react_on_rails
<shell_result>
Repository: shakacode/react_on_rails
Exit code: 2
stderr:
unrecognized file type: tsx
</shell_result>
Script executed:
# Search for disableHttp2 usage in the codebase (correct file types)
rg -n "disableHttp2" --type ts -C 2Repository: shakacode/react_on_rails
<shell_result>
Repository: shakacode/react_on_rails
Exit code: 0
stdout:
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts-5-// eslint-disable-next-line import/no-relative-packages
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts-6-import packageJson from '../package.json';
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts:7:import worker, { disableHttp2 } from '../src/worker';
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts-8-import {
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts-9- BUNDLE_TIMESTAMP,
--
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts-30-const railsEnv = 'test';
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts-31-
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts:32:disableHttp2();
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts-33-
packages/react-on-rails-pro-node-renderer/tests/worker.test.ts-34-describe('worker', () => {
--
packages/react-on-rails-pro-node-renderer/src/worker.ts-94-
packages/react-on-rails-pro-node-renderer/src/worker.ts-95-// Call before any test using `app.inject()`
packages/react-on-rails-pro-node-renderer/src/worker.ts:96:export const disableHttp2 = () => {
packages/react-on-rails-pro-node-renderer/src/worker.ts-97- useHttp2 = false;
packages/react-on-rails-pro-node-renderer/src/worker.ts-98-};
--
knip.ts-70- 'src/default-node-renderer.ts!',
knip.ts-71- 'src/integrations/*.ts!',
knip.ts:72: // Export disableHttp2 for test utilities
knip.ts-73- 'src/worker.ts!',
knip.ts-74- ],
</shell_result>
Remove the ! production marker from src/worker.ts.
The disableHttp2 export is test-only (called at module level in tests/worker.test.ts to configure Fastify for testing via app.inject()), not a production entry point. The file itself is not exported in package.json, so it should not be marked with ! (production marker). Either remove the ! suffix to treat it as a dev/test-only entry, or remove the entry entirely and let Knip detect it via test imports.
🤖 Prompt for AI Agents
In knip.ts around lines 72 to 73, the production marker '!' is incorrectly
applied to 'src/worker.ts!' making a test-only file appear as a production
entry; remove the trailing '!' from that entry (change 'src/worker.ts!' to
'src/worker.ts') or delete the entry entirely so Knip treats it as a
dev/test-only file discovered via test imports.
| bundle_install_in(example_type.dir) | ||
| end | ||
|
|
||
| sh_in_dir(example_type.dir, "npm install") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use pnpm install instead of npm install.
Based on learnings, this repository should NEVER use npm commands; only pnpm equivalents should be used for JavaScript package management.
- sh_in_dir(example_type.dir, "npm install")
+ sh_in_dir(example_type.dir, "pnpm install")📝 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.
| sh_in_dir(example_type.dir, "npm install") | |
| sh_in_dir(example_type.dir, "pnpm install") |
🤖 Prompt for AI Agents
In react_on_rails/rakelib/shakapacker_examples.rake around line 114, replace the
call that runs "npm install" with the pnpm equivalent; update the sh_in_dir
invocation to execute "pnpm install" so the project uses pnpm for package
installation consistently across scripts. Ensure the command string is exactly
"pnpm install" and leave any surrounding helpers/arguments unchanged.
This moves React and Shakapacker version compatibility testing from spec/dummy to the generator smoke tests, as suggested in PR #2114 review. Changes: - Update spec/dummy to always use latest React 19 and Shakapacker 9.4.0 - Add minimum version example apps (basic-minimum, basic-server-rendering-minimum) that use React 18.0.0 and Shakapacker 8.2.0 - Add ExampleType.minimum_versions flag to support version-specific examples - Add rake tasks for filtered testing: - run_rspec:shakapacker_examples_latest (for latest versions only) - run_rspec:shakapacker_examples_minimum (for minimum versions only) - Simplify script/convert to only handle Node.js tooling compatibility (removed React/Shakapacker version modifications) - Update CI workflows to run appropriate examples per dependency level Benefits: - Clearer separation: spec/dummy tests latest, generators test compatibility - Simpler CI configuration for integration tests - Better reflects real-world usage patterns Closes #2123 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Improves error handling by catching and logging JSON parse errors when reading package.json during minimum version configuration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Add a predicate method with ? suffix for boolean checks, following Ruby convention. Update run_rspec.rake to use the predicate method with &:minimum_versions? instead of &:minimum_versions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Upgrade react-redux from ^8.0.2 to ^9.2.0 for React 19 support
- Upgrade redux from ^4.0.1 to ^5.0.1 (required by react-redux 9.x)
- Upgrade redux-thunk from ^2.2.0 to ^3.1.0 (required by redux 5.x)
- Replace react-helmet@^6.1.0 with @dr.pogodin/react-helmet@^3.0.4
(thread-safe React 19 compatible fork)
Code changes:
- Update redux-thunk imports to use named export: { thunk }
- Update react-helmet SSR to use HelmetProvider with context prop
- Remove @types/react-helmet (new package has built-in types)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Add HelmetProvider wrapper to client-side entry points for ReactHelmet components. The @dr.pogodin/react-helmet package requires HelmetProvider to wrap all Helmet components, on both server and client sides. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…lity Shakapacker 8.2.0 requires webpack-assets-manifest ^5.x, but the generator creates apps with ^6.x. The apply_minimum_versions function now also downgrades webpack-assets-manifest to be compatible with Shakapacker 8.2.0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The minimum version testing was failing because: 1. Gemfile had 'shakapacker >= 8.2.0' which installs latest (9.4.0) 2. package.json was downgraded to shakapacker 8.2.0 3. The version mismatch caused Shakapacker to error on rake tasks Solution: - apply_minimum_versions now also updates Gemfile to pin shakapacker to the exact minimum version (8.2.0) - Re-run bundle install after updating Gemfile to install the pinned version - This ensures both gem and npm package are at the same version 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Use BUNDLE_GEMFILE to explicitly point to the generated app's Gemfile when running rake tasks. This prevents bundler from using gems from a parent workspace's vendor/bundle, which could have different versions. This fixes the Shakapacker version mismatch error in CI where the generated app had shakapacker 8.2.0 installed but Rails was loading shakapacker 9.4.0 from the parent react_on_rails vendor/bundle. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The BUNDLE_GEMFILE env var was causing issues for latest version examples because bundler was detecting Gemfile/lockfile mismatches in frozen mode. Changes: - Only set BUNDLE_GEMFILE and BUNDLE_FROZEN=false for minimum version examples - Latest examples continue using standard bundle exec This ensures: - Latest examples work normally without bundler isolation issues - Minimum examples are properly isolated from parent workspace gems 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
The lockfile was generated with React 18.0.0 but package.json specifies ^19.0.0. This caused CI failures with --frozen-lockfile. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Use unbundled_sh_in_dir to properly isolate the bundler environment when running generate_packs in generated example apps. The previous approach with BUNDLE_GEMFILE env var didn't work because bundler still used cached gem paths from the parent rake context. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Add unbundled option to run_tests_in to use unbundled_sh_in_dir for minimum version example tests. This ensures the example app's Gemfile and gem versions are used (e.g., Shakapacker 8.2.0) instead of the parent workspace's bundle context (which has Shakapacker 9.4.0). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
chromedriver-helper was deprecated in March 2019 and is incompatible with modern selenium-webdriver (4.x). The gem tries to set Selenium::WebDriver::Chrome.driver_path which no longer exists. Modern selenium-webdriver uses webdriver-manager internally for driver management. GitHub Actions and most CI environments have Chrome and ChromeDriver pre-installed, so no driver helper gem is needed. This fixes the minimum version example tests which were failing with: "undefined method `driver_path=' for Selenium::WebDriver::Chrome:Module" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
c6c3f68 to
0a4d47e
Compare
Summary
This PR moves React and Shakapacker version compatibility testing from spec/dummy to the generator smoke tests, as suggested in PR #2114 review.
Key changes:
basic-minimum,basic-server-rendering-minimum) that test React 18.0.0 and Shakapacker 8.2.0script/convertto only handle Node.js tooling compatibility (removed React/Shakapacker version modifications)run_rspec:shakapacker_examples_latest(basic, redux, etc.)run_rspec:shakapacker_examples_minimum(basic-minimum, etc.)Benefits
Test plan
run_rspec:shakapacker_examples_latestincludes only non-minimum examplesrun_rspec:shakapacker_examples_minimumincludes only minimum examplesCloses #2123
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.