Skip to content

Conversation

@justin808
Copy link
Member

@justin808 justin808 commented Nov 26, 2025

Summary

Updates spec/dummy dependencies to be compatible with React 19:

Dependency Updates

Package Old Version New Version Reason
react 18.0.0 ^19.0.0 Latest React
react-dom 18.0.0 ^19.0.0 Latest React
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

  1. redux-thunk imports - Updated from default export to named export:

    • import middleware from 'redux-thunk'import { thunk } from 'redux-thunk'
    • Files: SharedReduxStore.jsx, ReduxApp.server.jsx, ReduxApp.client.jsx
  2. react-helmet migration - Updated to @dr.pogodin/react-helmet:

    • Uses HelmetProvider wrapper (required for both client and server)
    • Server-side uses context prop for thread-safe data capture
    • Files: ReactHelmet.jsx, ReactHelmetApp.server.jsx, ReactHelmetAppBroken.server.jsx, client entry points

Test Plan

  • Integration Tests pass (tests React rendering with new dependencies)
  • Lint passes
  • Manual test: Run spec/dummy app and verify React components render

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Upgraded React framework to version 19 with accompanying major version updates to Redux, state management middleware, and related ecosystem dependencies to maintain full compatibility and improve overall application stability
    • Migrated to an enhanced helmet library that provides better support for dynamic page metadata and improved rendering capabilities in both client and server environments

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

justin808 and others added 2 commits November 25, 2025 14:19
- 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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Walkthrough

Updates redux-thunk imports from default to named imports across multiple files. Replaces react-helmet with @dr.pogodin/react-helmet, wrapping components with HelmetProvider for both client and server rendering. Updates package.json to React 19, redux 5.x, redux-thunk 3.x, and react-redux 9.2.0.

Changes

Cohort / File(s) Summary
Redux Thunk Migration
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx, react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx, react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx, react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
Replaced default import of thunkMiddleware from redux-thunk with named import thunk. Updated applyMiddleware() calls to use thunk instead of thunkMiddleware.
React Helmet Migration — Client
react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx, react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx, react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
Changed import from react-helmet to @dr.pogodin/react-helmet. Wrapped default exports with HelmetProvider component.
React Helmet Migration — Server
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx, react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
Replaced Helmet.renderStatic() with HelmetProvider and per-request helmetContext. Renders component within HelmetProvider, extracts helmet data via helmetContext, and derives renderedHtml.title from helmet data.
Dependency Updates
react_on_rails/spec/dummy/package.json
Updated React 18.x → 19.x, redux-thunk (default import) → 3.x (named import), redux → 5.x, react-redux → 9.2.0. Replaced react-helmet with @dr.pogodin/react-helmet. Removed @types/react-helmet from devDependencies.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Redux Thunk changes: Consistent pattern applied across 4 files; straightforward import/usage swap with no logic changes
  • React Helmet client changes: Consistent HelmetProvider wrapping pattern across 3 files; minimal logic modification
  • Server-side Helmet rendering: Most complex area—review helmetContext extraction logic in ReactHelmetApp.server.jsx and ReactHelmetAppBroken.server.jsx to ensure correct per-request helmet data capture
  • Package.json: Verify dependency version compatibility and that no peer dependency conflicts exist with React 19 and redux 5.x

Possibly related PRs

Suggested labels

review-needed, full-ci

Suggested reviewers

  • Judahmeek
  • AbanoubGhadban
  • alexeyr-ci2

Poem

🐰 Thunks reimported, helmets now nested,
Redux refreshed, React's newest tested!
From eighteen to nineteen we proudly hop,
Dependencies danced to the version upgrade top! 🎉

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the pull request: updating the spec/dummy application for React 19 compatibility. It directly reflects the core purpose of the changes across multiple files and dependencies.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jg/react19-compat

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

❤️ Share

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

@claude
Copy link

claude bot commented Nov 26, 2025

Code Review: React 19 Compatibility Update

I've reviewed this PR and overall it looks solid. The changes correctly update the spec/dummy app to React 19 and handle the necessary dependency migrations. Here's my detailed feedback:


What's Good

1. Dependency Updates Are Correct

  • React 18 → 19: ✅ Uses caret range (^19.0.0) allowing patch updates
  • react-redux 8 → 9: ✅ Required for React 19 support
  • redux 4 → 5: ✅ Required by react-redux 9.x
  • redux-thunk 2 → 3: ✅ Required by redux 5.x
  • react-helmet migration: ✅ Correctly switches to maintained fork

2. Code Changes Are Thorough

  • All redux-thunk imports correctly updated from default to named export
  • HelmetProvider correctly added to all client-side entry points
  • Server-side rendering correctly uses context object for thread-safety
  • Good defensive coding with helmet ? helmet.title.toString() : ''

3. Documentation Added

  • Helpful comments explaining HelmetProvider requirements
  • Clear explanation of thread-safe server-side rendering pattern

⚠️ Potential Issues

1. Inconsistency: ReactHelmetApp.server.jsx Structure Change

In react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx, the component structure was significantly changed:

Before (expected based on component name):

const componentHtml = renderToString(<ReactHelmet {...props} />);

After:

const componentHtml = renderToString(
  <HelmetProvider context={helmetContext}>
    <div>
      <Helmet>
        <title>Custom page title</title>
      </Helmet>
      Props: {JSON.stringify(props)}
      <HelloWorld {...props} />
    </div>
  </HelmetProvider>,
);

Issue: This duplicates the ReactHelmet component logic inline instead of using the component. This creates:

  • Code duplication (ReactHelmet already has the same structure)
  • Potential maintenance burden (two places to update)
  • Inconsistency with ReactHelmetAppBroken.server.jsx which correctly wraps <ReactHelmet />

Recommendation: Should be:

const componentHtml = renderToString(
  <HelmetProvider context={helmetContext}>
    <ReactHelmet {...props} />
  </HelmetProvider>,
);

2. Pro Package Parity Issue

The Pro dummy app (react_on_rails_pro/spec/dummy/package.json) still uses:

  • react-helmet: ^6.0.0-beta.2 (old package, should migrate to @dr.pogodin/react-helmet)
  • shakapacker: 9.3.0 (open source is now on 9.4.0)

Questions:

  • Should Pro also be updated to use @dr.pogodin/react-helmet for consistency?
  • Should Pro also bump shakapacker to 9.4.0?
  • Are there Pro-specific react-helmet usages that need similar updates?

Impact: Medium - Could cause confusion or test failures in Pro package


🔍 Testing Concerns

1. Integration Tests

The PR description shows unchecked test plan items:

  • Integration Tests pass
  • Lint passes
  • Manual test: Run spec/dummy app

Critical per CLAUDE.md:

NEVER claim a test is "fixed" without running it locally first

Recommendation: Before merging, confirm:

# Run integration tests locally
cd react_on_rails/spec/dummy
bundle exec rspec spec/system/integration_spec.rb

# Verify react-helmet rendering works
grep -A 10 'react-helmet' spec/system/integration_spec.rb

2. Redux Store Tests

Since redux-thunk import changed in 4 files, verify all Redux-related tests pass:

bundle exec rspec --tag redux

🔒 Security & Performance

Security: ✅ No Issues

  • Dependency updates are from trusted sources
  • @dr.pogodin/react-helmet is a well-maintained fork addressing React 19 compatibility
  • No new security vulnerabilities introduced

Performance: ✅ Neutral

  • React 19 should provide performance improvements
  • HelmetProvider context pattern is the standard approach (no perf concerns)

📋 Pre-Merge Checklist

Based on CLAUDE.md requirements:

  • Run linting locally: bundle exec rubocop (MANDATORY)
  • Verify trailing newlines: All files must end with newline
  • Test locally: Run bundle exec rspec to verify tests pass
  • Consider Pro package: Decide if Pro needs similar updates
  • Fix ReactHelmetApp.server.jsx: Use <ReactHelmet /> component instead of duplicating structure

📝 Minor Suggestions

  1. Gemfile.lock Shakapacker Update: The bump from 9.3.0 → 9.4.0 is included. Verify this doesn't introduce breaking changes.

  2. TypeScript Types Cleanup: Removed @types/react-helmet from devDependencies ✅ (correct, since new package likely has built-in types)


🎯 Summary

Overall Assessment: Good PR with one structural issue to address.

Required Changes:

  1. Fix ReactHelmetApp.server.jsx to use <ReactHelmet /> component
  2. Run local tests and update test plan checkboxes
  3. Consider Pro package parity

Recommended Changes:

  1. Update Pro dummy app to @dr.pogodin/react-helmet for consistency
  2. Document why Pro uses different shakapacker version if intentional

Approval Status: ⚠️ Conditional - Fix the component duplication issue, run tests locally, then this is good to merge.


Great work on the thorough dependency migration! The react-helmet → @dr.pogodin/react-helmet migration is especially important for React 19 compatibility. 🚀

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx (1)

8-32: Thunk update is correct; consider React 19 render API for this legacy entry

The move to import { thunk } from 'redux-thunk' and applyMiddleware(thunk) for store creation is consistent with the rest of the PR and the upgraded Redux stack. However, this entrypoint still uses ReactDOM.render/ReactDOM.hydrate, which are removed in React 19; if this “react16” example is actually executed against the React 19 dependency from spec/dummy/package.json, you may want to mirror the newer client entry’s createRoot/hydrateRoot pattern or clearly scope this bundle to a React 16 build.

Please double-check how this app-react16 bundle is built/loaded in your test matrix to ensure it doesn’t accidentally run against React 19’s removed ReactDOM.render API.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba7b11b and 1026398.

⛔ Files ignored due to path filters (1)
  • react_on_rails/spec/dummy/Gemfile.lock is excluded by !**/*.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/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/package.json
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
  • react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
  • react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.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.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: 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)
📚 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/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
  • react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
  • react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.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/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/package.json
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
  • react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
  • react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx
📚 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/spec/dummy/client/app/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/package.json
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
  • react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
  • react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx
📚 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-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/package.json
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
  • react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
  • react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.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/package.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: 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
📚 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/package.json
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.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.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
  • react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.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
🧬 Code graph analysis (6)
react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.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.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-react16/startup/ReduxApp.client.jsx (2)
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/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/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)
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)
⏰ 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). (6)
  • GitHub Check: build-dummy-app-webpack-test-bundles (3.2, 20, minimum)
  • GitHub Check: build-dummy-app-webpack-test-bundles (3.4, 22, latest)
  • GitHub Check: build
  • GitHub Check: build-dummy-app-webpack-test-bundles (3.4, 22, latest)
  • GitHub Check: build
  • GitHub Check: claude-review
🔇 Additional comments (12)
react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx (1)

2-7: Helmet import and provider expectations look good

Switching to @dr.pogodin/react-helmet and documenting that this component must be wrapped in a HelmetProvider aligns with the rest of the PR; no further changes needed here.

Please confirm your local build/SSR tests that exercise Helmet continue to pass with @dr.pogodin/react-helmet as configured in spec/dummy/package.json.

react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx (1)

9-31: Server Redux store now uses named thunk consistently

The switch to import { thunk } from 'redux-thunk' and applyMiddleware(thunk)(createStore)(...) keeps the server-side store in sync with the client and shared store setups.

Please rely on your server-rendering tests to confirm redux-thunk behavior is unchanged after the move to the named thunk export.

react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx (1)

2-15: Shared Redux store thunk wiring matches other entrypoints

Using the named thunk export in applyMiddleware(thunk)(createStore)(...) keeps the shared store aligned with the client/server Redux setups and the upgraded redux-thunk version.

Confirm any consumers of this shared store behave as before (especially async action flows) after the thunk import change.

react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx (1)

3-14: Client ReactHelmet is correctly wrapped in HelmetProvider

Wrapping ReactHelmet in <HelmetProvider> on the client matches the expectations documented in ReactHelmet.jsx and the usage pattern for @dr.pogodin/react-helmet; the export signature remains compatible.

Please confirm client-side Helmet behavior (e.g., title updates) still works as expected when exercising this “broken” example in the dummy app.

react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx (1)

6-32: Server ‘broken’ Helmet example now follows HelmetProvider SSR pattern

Using HelmetProvider with a per-request helmetContext and deriving title from helmet.title.toString() matches the recommended SSR usage for @dr.pogodin/react-helmet, while preserving the intentionally “broken” single-argument signature described in the comments.

Please exercise the server-side dummy route that uses this startup file to confirm that both the intended error path (due to the non-generator signature) and the captured <title> still behave as expected under React 19.

react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx (1)

8-37: All redux-thunk imports consistently use named export pattern

Verification confirms the review comment is accurate:

  • All 4 files with redux-thunk imports use import { thunk } from 'redux-thunk' (named import)
  • No default imports remain
  • All store creation calls properly wire middleware: applyMiddleware(thunk)
  • File under review (lines 8 and 37) follows the same consistent pattern as other entrypoints
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx (4)

19-21: LGTM! Thread-safe per-request context pattern.

The per-request helmetContext initialization correctly enables thread-safe helmet data capture for server-side rendering, consistent with the @dr.pogodin/react-helmet API pattern.


23-33: LGTM! Correct server-side rendering with HelmetProvider.

The rendering logic properly:

  • Wraps the component tree with HelmetProvider passing the per-request context
  • Uses inline Helmet to set the page title
  • Renders the HelloWorld component with forwarded props

This pattern aligns with the reference implementation in ReactHelmetAppBroken.server.jsx.


35-39: LGTM! Safe helmet data extraction.

The helmet extraction correctly:

  • Retrieves helmet data from the context after rendering
  • Includes a null check to prevent runtime errors
  • Converts helmet.title to string with a safe fallback

This matches the pattern in ReactHelmetAppBroken.server.jsx.


4-5: All imports are valid and correctly used.

The verification confirms:

  • HelloWorld.jsx exists at the expected path react_on_rails/spec/dummy/client/app/startup/HelloWorld.jsx
  • Helmet and HelmetProvider are correctly exported from @dr.pogodin/react-helmet per the library's API
  • The usage in the file is correct: HelmetProvider wraps components with an optional context object for SSR, and Helmet wraps head elements like <title>. This aligns exactly with the library's documentation
  • The file properly ends with a newline
react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx (2)

3-3: Import aligns with client-side helmet usage pattern.

The HelmetProvider import from @dr.pogodin/react-helmet is correct for client-side rendering. Note: Library API verification requested in the server file review (ReactHelmetApp.server.jsx) applies here as well.


9-14: LGTM! Correct client-side HelmetProvider wrapper.

The client-side implementation correctly:

  • Wraps ReactHelmet with HelmetProvider (no context prop needed for client rendering)
  • Forwards props to the wrapped component
  • Matches the pattern in ReactHelmetAppBroken.client.jsx

This completes the client-side migration to @dr.pogodin/react-helmet.

Comment on lines +21 to +28
"@dr.pogodin/react-helmet": "^3.0.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-on-rails": "link:.yalc/react-on-rails",
"react-redux": "^8.0.2",
"react-redux": "^9.2.0",
"react-router-dom": "^6.0.0",
"redux": "^4.0.1",
"redux-thunk": "^2.2.0",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Script executed:

#!/bin/bash
# Find all package.json files in the repository
fd package.json -t f

Repository: shakacode/react_on_rails


<shell_result>
Repository: shakacode/react_on_rails
Exit code: 0

stdout:

package.json
packages/react-on-rails/package.json
packages/react-on-rails-pro/package.json
packages/react-on-rails-pro-node-renderer/package.json
react_on_rails/spec/dummy/package.json
react_on_rails/spec/react_on_rails/fixtures/absolute_path_package.json
react_on_rails/spec/react_on_rails/fixtures/beta_package.json
react_on_rails/spec/react_on_rails/fixtures/git_package.json
react_on_rails/spec/react_on_rails/fixtures/normal_package.json
react_on_rails/spec/react_on_rails/fixtures/pro_package.json
react_on_rails/spec/react_on_rails/fixtures/pro_semver_caret_package.json
react_on_rails/spec/react_on_rails/fixtures/relative_path_package.json
react_on_rails/spec/react_on_rails/fixtures/semver_caret_package.json
react_on_rails/spec/react_on_rails/fixtures/semver_exact_package.json
react_on_rails/spec/react_on_rails/fixtures/semver_range_package.json
react_on_rails/spec/react_on_rails/fixtures/semver_tilde_package.json
react_on_rails/spec/react_on_rails/fixtures/similar_packages_package.json
react_on_rails/spec/react_on_rails/fixtures/yalc_package.json
react_on_rails_pro/package.json
react_on_rails_pro/spec/dummy/package.json
react_on_rails_pro/spec/execjs-compatible-dummy/package.json

</shell_result>


Script executed:

#!/bin/bash
# Extract React/Redux/Helmet versions from key package.json files
echo "=== Root package.json ==="
cat package.json | jq '.dependencies // empty | {react: .react, "react-dom": .["react-dom"], "react-redux": .["react-redux"], redux: .redux, "redux-thunk": .["redux-thunk"], "@dr.pogodin/react-helmet": .["@dr.pogodin/react-helmet"]} | del(.[] | select(. == null))' 2>/dev/null || echo "No dependencies section"

echo -e "\n=== packages/react-on-rails/package.json ==="
cat packages/react-on-rails/package.json | jq '.peerDependencies // empty | {react: .react, "react-dom": .["react-dom"], "react-redux": .["react-redux"], redux: .redux, "redux-thunk": .["redux-thunk"], "@dr.pogodin/react-helmet": .["@dr.pogodin/react-helmet"]} | del(.[] | select(. == null))' 2>/dev/null || echo "No peerDependencies section"

echo -e "\n=== react_on_rails/spec/dummy/package.json ==="
cat react_on_rails/spec/dummy/package.json | jq '.dependencies // empty | {react: .react, "react-dom": .["react-dom"], "react-redux": .["react-redux"], redux: .redux, "redux-thunk": .["redux-thunk"], "@dr.pogodin/react-helmet": .["@dr.pogodin/react-helmet"]} | del(.[] | select(. == null))' 2>/dev/null || echo "No dependencies section"

echo -e "\n=== react_on_rails_pro/package.json ==="
cat react_on_rails_pro/package.json | jq '.dependencies // empty | {react: .react, "react-dom": .["react-dom"], "react-redux": .["react-redux"], redux: .redux, "redux-thunk": .["redux-thunk"], "@dr.pogodin/react-helmet": .["@dr.pogodin/react-helmet"]} | del(.[] | select(. == null))' 2>/dev/null || echo "No dependencies section"

echo -e "\n=== react_on_rails_pro/spec/dummy/package.json ==="
cat react_on_rails_pro/spec/dummy/package.json | jq '.dependencies // empty | {react: .react, "react-dom": .["react-dom"], "react-redux": .["react-redux"], redux: .redux, "redux-thunk": .["redux-thunk"], "@dr.pogodin/react-helmet": .["@dr.pogodin/react-helmet"]} | del(.[] | select(. == null))' 2>/dev/null || echo "No dependencies section"

Repository: shakacode/react_on_rails


<shell_result>
Repository: shakacode/react_on_rails
Exit code: 0

stdout:

=== Root package.json ===

=== packages/react-on-rails/package.json ===
{
  "react": ">= 16",
  "react-dom": ">= 16"
}

=== react_on_rails/spec/dummy/package.json ===
{
  "react": "^19.0.0",
  "react-dom": "^19.0.0",
  "react-redux": "^9.2.0",
  "redux": "^5.0.1",
  "redux-thunk": "^3.1.0",
  "@dr.pogodin/react-helmet": "^3.0.4"
}

=== react_on_rails_pro/package.json ===

=== react_on_rails_pro/spec/dummy/package.json ===
{
  "react": "19.0.0",
  "react-dom": "19.0.0",
  "react-redux": "^9.2.0",
  "redux": "^5.0.1",
  "redux-thunk": "^3.1.0"
}

</shell_result>


Script executed:

#!/bin/bash
# Check if CHANGELOG.md was updated
echo "=== Recent CHANGELOG.md entries ==="
head -50 CHANGELOG.md

echo -e "\n=== Check git diff for CHANGELOG.md ==="
git diff HEAD~1 CHANGELOG.md 2>/dev/null | head -30 || echo "Cannot get git diff"

Repository: shakacode/react_on_rails


<shell_result>
Repository: shakacode/react_on_rails
Exit code: 0

stdout:

=== Recent CHANGELOG.md entries ===
# Change Log

All notable changes to this project's source code will be documented in this file. Items under `Unreleased` is upcoming features that will be out in the next version.

Migration instructions for the major updates can be found [here](https://www.shakacode.com/react-on-rails/docs/guides/upgrading-react-on-rails#upgrading-to-version-9.md). Some smaller migration information can be found here.

## Want to Save Time Updating?

If you need help upgrading `react_on_rails`, `webpacker` to `shakapacker`, or JS packages, contact justin@shakacode.com. We can upgrade your project and improve your development and customer experiences, allowing you to focus on building new features or fixing bugs instead.

For an overview of working with us, see our [Client Engagement Model](https://www.shakacode.com/blog/client-engagement-model/) article and [how we bill for time](https://www.shakacode.com/blog/shortcut-jira-trello-github-toggl-time-and-task-tracking/).

If you think ShakaCode can help your project, [click here](https://meetings.hubspot.com/justingordon/30-minute-consultation) to book a call with [Justin Gordon](mailto:justin@shakacode.com), the creator of React on Rails and Shakapacker.

## Contributors

Please follow the recommendations outlined at [keepachangelog.com](http://keepachangelog.com/). Please use the existing headings and styling as a guide.
After a release, please make sure to run `bundle exec rake update_changelog`. This will add a heading for the latest version and update the links at the end of the file.

## Versions

### [Unreleased]

Changes since the last non-beta release.

#### Added

- **Service Dependency Checking for bin/dev**: Added optional `.dev-services.yml` configuration to validate required external services (Redis, PostgreSQL, Elasticsearch, etc.) are running before `bin/dev` starts the development server. Provides clear error messages with start commands and install hints when services are missing. Zero impact if not configured - backwards compatible with all existing installations. [PR 2098](https://github.com/shakacode/react_on_rails/pull/2098) by [justin808](https://github.com/justin808).

#### Changed

- **Monorepo Structure Reorganization**: Restructured the monorepo to use two top-level product directories (`react_on_rails/` and `react_on_rails_pro/`) instead of mixing source files at the root level. This improves organization and clarity for contributors working on either the open-source or Pro versions. **Important for contributors**: If you have an existing clone of the repository, you may need to update your IDE exclusion patterns and paths. See the updated `CLAUDE.md` for current project structure. [PR 2114](https://github.com/shakacode/react_on_rails/pull/2114) by [justin808](https://github.com/justin808).

- **Package Manager Migration to pnpm (Contributors Only)**: Migrated the monorepo from Yarn Classic to pnpm for improved dependency management and faster installs. **This only affects contributors** - end users can continue using any package manager (npm, yarn, pnpm) with their applications. Contributors should reinstall dependencies with `pnpm install` after pulling this change. [PR 2121](https://github.com/shakacode/react_on_rails/pull/2121) by [justin808](https://github.com/justin808).

#### Improved

- **Automatic Precompile Hook Coordination in bin/dev**: The `bin/dev` command now automatically runs Shakapacker's `precompile_hook` once before starting development processes and sets `SHAKAPACKER_SKIP_PRECOMPILE_HOOK=true` to prevent duplicate execution in spawned webpack processes.
  - Eliminates the need for manual coordination, sleep hacks, and duplicate task calls in Procfile.dev
  - Users can configure expensive build tasks (like locale generation or ReScript compilation) once in `config/shakapacker.yml` and `bin/dev` handles coordination automatically
  - Includes warning for Shakapacker versions below 9.4.0 (the `SHAKAPACKER_SKIP_PRECOMPILE_HOOK` environment variable is only supported in 9.4.0+)
  - The `SHAKAPACKER_SKIP_PRECOMPILE_HOOK` environment variable is set for all spawned processes, making it available for custom scripts that need to detect when `bin/dev` is managing the precompile hook
  - Addresses [2091](https://github.com/shakacode/react_on_rails/issues/2091) by [justin808](https://github.com/justin808)

- **Idempotent Locale Generation**: The `react_on_rails:locale` rake task is now idempotent, automatically skipping generation when locale files are already up-to-date. This makes it safe to call multiple times (e.g., in Shakapacker's `precompile_hook`) without duplicate work. Added `force=true` option to override timestamp checking. [PR 2090](https://github.com/shakacode/react_on_rails/pull/2090) by [justin808](https://github.com/justin808).

### [v16.2.0.beta.12] - 2025-11-20

#### Added


=== Check git diff for CHANGELOG.md ===

</shell_result>


Script executed:

#!/bin/bash
# Check lines 35-45 in spec/dummy/package.json to see the devDependencies
sed -n '35,45p' react_on_rails/spec/dummy/package.json

Repository: shakacode/react_on_rails


<shell_result>
Repository: shakacode/react_on_rails
Exit code: 0

stdout:

    "@babel/preset-react": "^7.10.4",
    "@playwright/test": "^1.55.1",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.5.1",
    "@rescript/react": "^0.13.0",
    "@types/react": "^19.0.0",
    "@types/react-dom": "^19.0.0",
    "babel-loader": "8.2.4",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "compression-webpack-plugin": "9",
    "css-loader": "^6.5.1",
    "expose-loader": "^1.0.3",

</shell_result>


Based on my verification, I've identified real cross-package inconsistencies and a missing CHANGELOG entry. Here's the rewritten review comment:


Version inconsistencies exist across spec/dummy packages; React 19 upgrade missing from CHANGELOG

Cross-package comparison reveals:

  • react_on_rails/spec/dummy/package.json: React ^19.0.0, React-Redux ^9.2.0, Redux ^5.0.1, redux-thunk ^3.1.0, @dr.pogodin/react-helmet ^3.0.4
  • react_on_rails_pro/spec/dummy/package.json: React 19.0.0 (exact version, not caret), React-Redux ^9.2.0, Redux ^5.0.1, redux-thunk ^3.1.0, @dr.pogodin/react-helmet missing

The semver mismatch (^19.0.0 vs 19.0.0) and missing Helmet dependency between the two spec/dummy packages should be reconciled. Additionally, per project guidelines, the React 19 upgrade and dependency bumps should be documented in CHANGELOG.md under the Unreleased section.

🤖 Prompt for AI Agents
In react_on_rails/spec/dummy/package.json around lines 21-28 there is a
semver/dep mismatch vs react_on_rails_pro/spec/dummy/package.json (this file
uses "react": "^19.0.0" and includes "@dr.pogodin/react-helmet": "^3.0.4", while
the pro package uses "react": "19.0.0" and omits Helmet); make the versions
consistent across both spec/dummy package.json files (choose careted or exact
for react and apply the same style to react-dom), add the missing
@dr.pogodin/react-helmet dependency to
react_on_rails_pro/spec/dummy/package.json with the same version, and add a
brief entry under the Unreleased section of CHANGELOG.md documenting the React
19 upgrade and dependency bumps.

@justin808
Copy link
Member Author

/run-skipped-ci

@github-actions
Copy link
Contributor

🚀 Full CI Mode Enabled

Triggered all workflows for full CI coverage

Note: Added the full-ci label to this PR. All future commits will run the full CI suite (including minimum dependency tests) until the label is removed.

To disable full CI mode, use the /stop-run-skipped-ci command.

View progress in the Actions tab.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants