Skip to content

test(dummy): enable StrictMode in OSS and Pro dummies#3206

Merged
justin808 merged 6 commits intomainfrom
jg-conductor/fix-1465
Apr 30, 2026
Merged

test(dummy): enable StrictMode in OSS and Pro dummies#3206
justin808 merged 6 commits intomainfrom
jg-conductor/fix-1465

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Apr 25, 2026

Summary

  • Enables React StrictMode in the OSS spec/dummy startup paths by wrapping normal ReactOnRails.register registrations and direct manual renderer roots.
  • Covers both OSS dummy variants: the React 19 client/app/ path and the React 16 client/app-react16/ path.
  • Extends the same coverage to the Pro dummy with webpack aliases for the Pro package entrypoints, so async/generated registrations are patched before startup imports run.
  • Leaves 3-argument renderer functions in control of their own roots and wraps those manual roots explicitly.
  • Adds Jest coverage for the OSS StrictMode helper's wrapping, caching, and render-function skip behavior.

Closes #1465

Test plan

  • pnpm --dir react_on_rails/spec/dummy run test:js
  • pnpm --dir react_on_rails/spec/dummy run build:test (passes with existing DefinePlugin warnings)
  • pnpm exec eslint --no-ignore react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsPro.js react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsProClient.js react_on_rails_pro/spec/dummy/config/webpack/alias.js react_on_rails_pro/spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ManualRenderApp.jsx react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ReduxApp.client.jsx react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ReduxSharedStoreApp.client.jsx
  • pnpm --dir react_on_rails_pro/spec/dummy run build:test (passes with existing DefinePlugin warnings)
  • pre-commit hook: trailing-newlines, Prettier, ESLint on Pro changed files
  • pre-push hook: branch-lint, markdown-links

Summary by CodeRabbit

  • New Features

    • Enable React Strict Mode consistently for client render/hydration flows, registered components, and pro/auto-loaded entry points; add bundler/alias updates so client/server bundles resolve strict-mode-aware implementations.
  • Tests

    • Add comprehensive tests validating strict-mode wrapping behavior, wrapper caching, render-function exemptions, and opt-out handling.

Note

Low Risk
Low risk because changes are confined to spec/dummy apps and webpack configs used for dummy/test builds; main risk is unexpected StrictMode double-invocation effects causing flaky dummy tests or examples.

Overview
Enables React StrictMode across the OSS and Pro dummy apps by adding shared helpers to wrap rendered element trees and to automatically wrap registered components.

In OSS spec/dummy, startup entrypoints (including the React 16 variant) now wrap manual render roots and Redux provider trees via wrapElementInStrictMode, and client-bundle.js monkey-patches ReactOnRails.register to StrictMode-wrap non-render-function registrations.

In Pro spec/dummy, a TypeScript strictModeSupport adds component/render-function wrapping (including async render results), webpack aliases redirect react-on-rails-pro imports to StrictMode-enabled shims for client/server builds (with RSC config explicitly removing that alias), and several startup apps wrap their roots explicitly; Jest coverage is added for the OSS helper.

Reviewed by Cursor Bugbot for commit 45da8de. Bugbot is set up for automated code reviews on this repo. Configure here.

Wrap registered components and manually-rendered trees in StrictMode so
the spec/dummy app surfaces deprecated lifecycle, unsafe side-effects,
and other StrictMode-detected issues during integration testing. Render
functions and renderer functions are intentionally skipped — they own
their own root and would double-wrap.

Adds a small strictModeSupport helper plus unit tests for the wrapping
logic and caching behavior.

Closes #1465

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds StrictMode support across spec/dummy: new strict-mode utility modules, updates to app startups and ReactOnRails registration to wrap elements/components in React.StrictMode, new pro entry shims and webpack alias changes, and tests validating wrapping behavior and caching.

Changes

Cohort / File(s) Summary
StrictMode support modules
react_on_rails/spec/dummy/client/app/strictModeSupport.jsx, react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
New utilities: wrapElementInStrictMode, wrapRegisteredComponentsWithStrictMode, and enableStrictModeForReactOnRails. Detects components vs render functions, memoizes wrappers, normalizes promise/element/component render results, and patches registration.
Startup: React 16 apps
react_on_rails/spec/dummy/client/app-react16/startup/ManualRenderApp.jsx, .../ReduxApp.client.jsx, .../ReduxSharedStoreApp.client.jsx
Import and apply wrapElementInStrictMode to constructed react elements before hydrate/render; hot-reload and store selection flows preserved.
Startup: React 18+ apps
react_on_rails/spec/dummy/client/app/startup/ManualRenderApp.jsx, .../ReduxApp.client.jsx, .../ReduxSharedStoreApp.client.jsx
Wrap created React element with wrapElementInStrictMode prior to createRoot/hydrateRoot or render; added imports for strict-mode helper.
Pro app: auto-load / Apollo / Redux clients
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/*, react_on_rails_pro/spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx
Hydration/render flows updated to wrap provider/App trees with wrapElementInStrictMode before hydrateRoot/hydrateOrRender; strict-mode imports added.
ReactOnRails Pro strict-mode entries
react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsPro.js, .../strictModeReactOnRailsProClient.js, .../strictModeReactOnRailsProNode.js
New modules exporting enableStrictModeForReactOnRails(ReactOnRails) as default to provide strict-mode-enabled ReactOnRails entrypoints for client and node.
Client bundle / registration patch
react_on_rails/spec/dummy/client/app/packs/client-bundle.js
One-time patch of ReactOnRails.register to call wrapRegisteredComponentsWithStrictMode(components) before delegating; sentinel prevents repeated patching.
Webpack alias and RSC/server configs
react_on_rails_pro/spec/dummy/config/webpack/alias.js, .../rscWebpackConfig.js, .../serverWebpackConfig.js
Adds aliases mapping react-on-rails-pro imports to strict-mode entry files, removes those aliases from the RSC alias clone, and ensures server webpack resolves pro imports to strict-mode node entry.
Tests
react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx
New Jest suite verifying wrapper creation, caching, displayName formatting, preserving renderer/render-function exceptions, element wrapping, and pass-through behavior for non-elements.
Misc startup changes
react_on_rails/spec/dummy/client/app/packs/client-bundle.js, various manual/render/Redux startup files across spec/dummy and react_on_rails_pro/spec/dummy
Replaced direct JSX elements with results of wrapElementInStrictMode(...) when constructing reactElement used for hydrate/render paths.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer Code
    participant Bundle as Client Bundle
    participant ROR as ReactOnRails
    participant Registry as Component Registry

    Dev->>Bundle: call ReactOnRails.register(components)
    Bundle->>Bundle: wrapRegisteredComponentsWithStrictMode(components)
    Bundle->>ROR: originalRegister(wrappedComponents)
    ROR-->>Registry: components registered (wrapped)
Loading
sequenceDiagram
    participant Startup as App Startup
    participant Wrapper as strictModeSupport.wrapElementInStrictMode
    participant React as React hydrate/render

    Startup->>Wrapper: pass created React element (Provider/App)
    Wrapper-->>Startup: wrapped element (React.StrictMode(...))
    Startup->>React: hydrateRoot/createRoot/render(wrapped element)
    React-->>Startup: app initialized
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Judahmeek
  • alexeyr-ci
  • ihabadham

Poem

🐇 I tuck each tree in StrictMode's embrace,
Wrappers cached snug in a quiet place,
From register to hydrate the branches align,
Tests nod in chorus — the strict path is fine,
A hopping hooray with a carrot and grace!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: enabling StrictMode in both OSS and Pro dummy applications across multiple startup paths.
Linked Issues check ✅ Passed The PR fully addresses issue #1465 by applying React StrictMode across all spec/dummy applications including both OSS variants (React 19 and React 16) and Pro dummy, covering all startup paths.
Out of Scope Changes check ✅ Passed All changes are directly scoped to enabling StrictMode in spec/dummy as required; webpack alias modifications and server/RSC config updates are necessary supporting infrastructure for this objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg-conductor/fix-1465

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 25, 2026

Greptile Summary

This PR adds React.StrictMode wrapping across all spec/dummy startup paths by introducing a strictModeSupport.jsx helper and patching ReactOnRails.register in client-bundle.js. Renderer functions (which own their own roots) are handled via direct wrapElementInStrictMode calls, while registered components are auto-wrapped through the patched register.

Confidence Score: 4/5

Safe to merge for the dummy/spec use case; the P2 findings are design fragilities that won't break the integration test suite but are worth addressing.

All findings are P2. The arity heuristic and Map vs WeakMap issues are minor concerns that only affect correctness in edge cases unlikely to appear in the dummy app. No security or data-loss risks.

react_on_rails/spec/dummy/client/app/strictModeSupport.jsx — arity heuristic and Map vs WeakMap concerns.

Important Files Changed

Filename Overview
react_on_rails/spec/dummy/client/app/strictModeSupport.jsx New helper module; arity heuristic for render-function detection is fragile, and a plain Map is used where WeakMap would be more appropriate for non-function components.
react_on_rails/spec/dummy/client/app/packs/client-bundle.js Patches ReactOnRails.register to auto-wrap components in StrictMode; works correctly but relies on module singleton behaviour for coverage.
react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx Good coverage of wrapping, caching, and element wrapping; missing a test for the ambiguous 2-arg functional component case.
react_on_rails/spec/dummy/client/app/startup/ManualRenderApp.jsx Correctly wraps the manually-rendered element in StrictMode via wrapElementInStrictMode.
react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx Renderer function manually wraps its Provider tree in StrictMode; correct approach since it owns its own root.
react_on_rails/spec/dummy/client/app/startup/ReduxSharedStoreApp.client.jsx Same pattern as ReduxApp.client.jsx; renderer function correctly uses wrapElementInStrictMode directly.
react_on_rails/spec/dummy/client/app-react16/startup/ManualRenderApp.jsx React 16 variant; imports wrapElementInStrictMode from the React 19 app path — cross-app import is intentional for code reuse.
react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx React 16 renderer function correctly wraps element in StrictMode.
react_on_rails/spec/dummy/client/app-react16/startup/ReduxSharedStoreApp.client.jsx React 16 renderer function correctly wraps element in StrictMode.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ReactOnRails.register called] --> B[wrapRegisteredComponentsWithStrictMode]
    B --> C{isRenderFunction?}
    C -- "renderFunction flag OR\nlength >= 2" --> D[Pass through unchanged]
    C -- "regular component" --> E[wrapComponentInStrictMode]
    E --> F{typeof function?}
    F -- yes --> G[Check WeakMap cache\nwrappedFunctionComponents]
    F -- no --> H[Check Map cache\nwrappedOtherComponents]
    G --> I[Return cached or create\nStrictModeWrapper]
    H --> I
    I --> J[originalRegister with wrapped components]

    K[Renderer function startup file] --> L[wrapElementInStrictMode]
    L --> M[React.StrictMode element]
    M --> N[ReactDOM render / hydrateRoot]
Loading

Reviews (1): Last reviewed commit: "test(dummy): enable React StrictMode acr..." | Re-trigger Greptile

Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx
Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx Outdated
Comment thread react_on_rails/spec/dummy/client/app/packs/client-bundle.js Outdated
Comment thread react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx Outdated
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 25, 2026

Code Review

Overview

This PR enables React.StrictMode across all spec/dummy startup paths by:

  1. Adding a strictModeSupport.jsx helper with caching and render-function detection
  2. Wrapping manual-render trees directly via wrapElementInStrictMode
  3. Monkey-patching ReactOnRails.register in client-bundle.js so all batch registrations are automatically wrapped

The goal is sound and the implementation is mostly clean. A few things worth addressing:


Issues

Duplication of isRenderFunction logic (Medium)

strictModeSupport.jsx reimplements the detection logic verbatim from packages/react-on-rails/src/isRenderFunction.ts. If the core logic evolves (e.g., to handle async components, exotic objects, or additional heuristics), this copy silently drifts.

Since strictModeSupport.jsx lives inside spec/dummy which resolves react-on-rails through the workspace, it should be able to import the canonical function directly:

import isRenderFunction from 'react-on-rails/isRenderFunction';
// or from the internal package path if that's not a public export

If that import path isn't publicly exposed, consider at minimum adding a comment that this logic mirrors isRenderFunction.ts so future editors know to keep them in sync.


Redundant conditional inside createStrictModeWrapper (Low)

typeof Component === 'function' ? <Component {...props} /> : React.createElement(Component, props)

In JSX, <Component {...props} /> where Component is a variable reference always compiles to React.createElement(Component, props) — whether Component is a function, class, or string. Both branches are identical. The conditional can be dropped:

function StrictModeWrapper(props) {
  return (
    <React.StrictMode>
      <Component {...props} />
    </React.StrictMode>
  );
}

Inline-script registrations are covered, but implicitly (Low)

Several ERB views contain inline ReactOnRails.register(...) calls (e.g., client_side_hello_world.html.erb, server_side_redux_app.html.erb). These calls execute after client-bundle.js loads, so they pick up the monkey-patched register automatically — but this dependency on load order is silent. A brief comment in client-bundle.js noting that the patch is intentionally applied before any inline view scripts would make the intent clear.


Test coverage gaps (Low)

The existing tests cover the happy path well. A few edge cases are missing:

  • renderFunction flag: No test for fn.renderFunction = true — the explicit opt-in path in isRenderFunction. Currently only arity-based detection is exercised.
  • Class components: The check component.prototype?.isReactComponent should prevent class components from being skipped, but there's no test confirming they get wrapped.
  • displayName on wrapper: The StrictMode(...) display name is set but never asserted in tests.

Nits

  • wrappedOtherComponents uses a plain Map (correct, since WeakMap requires object keys), but the asymmetry with wrappedFunctionComponents (WeakMap) is surprising without a comment.
  • The cross-tree import in app-react16/startup/*.jsx (../../app/strictModeSupport) works but creates a coupling between the React 16 test subtree and the React 19 one. A one-line comment explaining the intentional sharing would help.

What's working well

  • Caching via WeakMap for functions is correct and avoids wrapper churn on repeated registration.
  • Skipping renderer functions (3-arg, or .renderFunction = true) is the right call — they own their roots and must not be double-wrapped.
  • The wrapElementInStrictMode / wrapRegisteredComponentsWithStrictMode naming split is clear.
  • Jest tests are well-structured and cover the core contract.

Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx
Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx Outdated
Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx Outdated
Comment thread react_on_rails/spec/dummy/client/app/packs/client-bundle.js Outdated
Comment thread react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx Outdated
Copy link
Copy Markdown
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 (2)
react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx (1)

34-45: Consider also covering the renderFunction-flag detection branch.

The test exercises arity-based skipping (renderFunction with arity 2, rendererFunction with arity 3), but per the PR description the helper also skips functions tagged via a renderFunction flag. A short additional case would lock in that branch and prevent regressions if arity heuristics change.

♻️ Suggested test addition
   it('does not wrap render functions or renderer functions', () => {
     const renderFunction = (props, railsContext) => ({ props, railsContext });
     const rendererFunction = (props, railsContext, domNodeId) => ({ props, railsContext, domNodeId });

     const wrappedComponents = wrapRegisteredComponentsWithStrictMode({
       renderFunction,
       rendererFunction,
     });

     expect(wrappedComponents.renderFunction).toBe(renderFunction);
     expect(wrappedComponents.rendererFunction).toBe(rendererFunction);
   });
+
+  it('does not wrap functions explicitly flagged as render functions', () => {
+    const flaggedRenderFunction = (props) => ({ props });
+    flaggedRenderFunction.renderFunction = true;
+
+    const wrappedComponents = wrapRegisteredComponentsWithStrictMode({ flaggedRenderFunction });
+
+    expect(wrappedComponents.flaggedRenderFunction).toBe(flaggedRenderFunction);
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx` around lines 34
- 45, Add a test case to exercise the branch where a function is detected as a
render function via the renderFunction flag (not just by arity): create a
function whose length/arity would normally cause wrapping, set its
renderFunction property to true (e.g., renderFunction.flag = true or
renderFunction.renderFunction = true according to how detection is implemented),
call wrapRegisteredComponentsWithStrictMode with that function in the
renderFunction slot, and assert that the returned
wrappedComponents.renderFunction strictly equals the original function;
reference the helper wrapRegisteredComponentsWithStrictMode and the
renderFunction rendererFunction symbols to locate where to add the test.
react_on_rails/spec/dummy/client/app/strictModeSupport.jsx (1)

22-38: Redundant branching in createStrictModeWrapper.

Both arms of the ternary on line 26 produce the same output: JSX <Component {...props} /> compiles to React.createElement(Component, props), which is exactly what the else branch does. React happily accepts strings, function components, class components, forwardRef/memo objects, etc. as the type argument, so a single expression covers all cases.

♻️ Proposed simplification
 const createStrictModeWrapper = (Component) => {
   function StrictModeWrapper(props) {
     return (
       <React.StrictMode>
-        {typeof Component === 'function' ? <Component {...props} /> : React.createElement(Component, props)}
+        <Component {...props} />
       </React.StrictMode>
     );
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/spec/dummy/client/app/strictModeSupport.jsx` around lines 22 -
38, The StrictModeWrapper in createStrictModeWrapper has a redundant ternary
when rendering Component; remove the typeof check and always render the
Component using a single expression (either JSX <Component {...props} /> or
React.createElement(Component, props)) inside the React.StrictMode in the
StrictModeWrapper function, leaving the componentName/displayName logic intact;
update StrictModeWrapper so it returns React.StrictMode with that single render
expression.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@react_on_rails/spec/dummy/client/app/packs/client-bundle.js`:
- Around line 12-16: The monkey-patch replacing ReactOnRails.register is being
re-applied on every HMR update, nesting wrappers; guard it with an idempotency
flag (e.g. ReactOnRails.__registerWrapped or a module-scoped boolean) so the
patch runs only once: check the flag before binding originalRegister and
assigning ReactOnRails.register, and set the flag after assignment; keep using
wrapRegisteredComponentsWithStrictMode to wrap the incoming components and
preserve originalRegister by binding it once (references: ReactOnRails.register,
originalRegister, wrapRegisteredComponentsWithStrictMode).

---

Nitpick comments:
In `@react_on_rails/spec/dummy/client/app/strictModeSupport.jsx`:
- Around line 22-38: The StrictModeWrapper in createStrictModeWrapper has a
redundant ternary when rendering Component; remove the typeof check and always
render the Component using a single expression (either JSX <Component {...props}
/> or React.createElement(Component, props)) inside the React.StrictMode in the
StrictModeWrapper function, leaving the componentName/displayName logic intact;
update StrictModeWrapper so it returns React.StrictMode with that single render
expression.

In `@react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx`:
- Around line 34-45: Add a test case to exercise the branch where a function is
detected as a render function via the renderFunction flag (not just by arity):
create a function whose length/arity would normally cause wrapping, set its
renderFunction property to true (e.g., renderFunction.flag = true or
renderFunction.renderFunction = true according to how detection is implemented),
call wrapRegisteredComponentsWithStrictMode with that function in the
renderFunction slot, and assert that the returned
wrappedComponents.renderFunction strictly equals the original function;
reference the helper wrapRegisteredComponentsWithStrictMode and the
renderFunction rendererFunction symbols to locate where to add the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a1026fda-cee0-475f-bca2-d885bd7fdac4

📥 Commits

Reviewing files that changed from the base of the PR and between 3605761 and 3e9a18f.

📒 Files selected for processing (9)
  • react_on_rails/spec/dummy/client/app-react16/startup/ManualRenderApp.jsx
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxSharedStoreApp.client.jsx
  • react_on_rails/spec/dummy/client/app/packs/client-bundle.js
  • react_on_rails/spec/dummy/client/app/startup/ManualRenderApp.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app/startup/ReduxSharedStoreApp.client.jsx
  • react_on_rails/spec/dummy/client/app/strictModeSupport.jsx
  • react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx

Comment thread react_on_rails/spec/dummy/client/app/packs/client-bundle.js Outdated
@justin808 justin808 changed the title test(dummy): enable React StrictMode across spec/dummy startup test(dummy): enable StrictMode in OSS and Pro dummies Apr 25, 2026
Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx Outdated
Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx Outdated
Comment thread react_on_rails/spec/dummy/client/app/packs/client-bundle.js Outdated
Comment thread react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
Comment thread react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx Outdated
Copy link
Copy Markdown
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_pro/spec/dummy/client/app/strictModeSupport.tsx (1)

157-167: Nit: patchedReactOnRails alias reads as if it's a separate object.

patchedReactOnRails is just a same-reference alias for reactOnRails, so all assignments below mutate the input singleton. The naming hides the in-place mutation; either drop the alias and operate on reactOnRails directly, or add a brief comment that this intentionally mutates the passed-in instance.

♻️ Proposed simplification
-  const originalRegister = reactOnRails.register.bind(reactOnRails);
-  const patchedReactOnRails = reactOnRails;
-
-  patchedReactOnRails.register = (components: ComponentRegistry) => {
-    originalRegister(wrapRegisteredComponentsWithStrictMode(components));
-  };
-
-  Object.defineProperty(patchedReactOnRails, STRICT_MODE_PATCHED, { value: true });
-
-  return patchedReactOnRails;
+  // Mutates `reactOnRails` in place so all default-import consumers observe the patch.
+  const originalRegister = reactOnRails.register.bind(reactOnRails);
+  reactOnRails.register = (components: ComponentRegistry) => {
+    originalRegister(wrapRegisteredComponentsWithStrictMode(components));
+  };
+  Object.defineProperty(reactOnRails, STRICT_MODE_PATCHED, { value: true });
+
+  return reactOnRails;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx` around lines
157 - 167, The name patchedReactOnRails misleadingly suggests a new object when
it is just an alias to the input reactOnRails and the code mutates the
singleton; either remove the alias and call reactOnRails.register directly (use
originalRegister = reactOnRails.register.bind(reactOnRails);
reactOnRails.register = (components) =>
originalRegister(wrapRegisteredComponentsWithStrictMode(components));
Object.defineProperty(reactOnRails, STRICT_MODE_PATCHED, { value: true });
return reactOnRails) or keep patchedReactOnRails but add a concise comment above
its definition stating it intentionally aliases and mutates the passed-in
reactOnRails instance; update usages of patchedReactOnRails accordingly and
ensure symbols originalRegister, wrapRegisteredComponentsWithStrictMode, and
STRICT_MODE_PATCHED are referenced as shown.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsPro.js`:
- Around line 1-5: This file re-exports the original module's named exports via
"export *" which bypasses the strict-mode wrapper applied to the default with
enableStrictModeForReactOnRails(ReactOnRails); remove the export * line in
strictModeReactOnRailsPro.js so consumers must use the wrapped default (or
alternatively explicitly re-export wrapped versions of specific symbols like
RailsContext or ReactComponentOrRenderFunction by obtaining them from the
wrapped ReactOnRails and exporting those), ensuring all public APIs go through
enableStrictModeForReactOnRails and not the unwrapped originals.

---

Nitpick comments:
In `@react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx`:
- Around line 157-167: The name patchedReactOnRails misleadingly suggests a new
object when it is just an alias to the input reactOnRails and the code mutates
the singleton; either remove the alias and call reactOnRails.register directly
(use originalRegister = reactOnRails.register.bind(reactOnRails);
reactOnRails.register = (components) =>
originalRegister(wrapRegisteredComponentsWithStrictMode(components));
Object.defineProperty(reactOnRails, STRICT_MODE_PATCHED, { value: true });
return reactOnRails) or keep patchedReactOnRails but add a concise comment above
its definition stating it intentionally aliases and mutates the passed-in
reactOnRails instance; update usages of patchedReactOnRails accordingly and
ensure symbols originalRegister, wrapRegisteredComponentsWithStrictMode, and
STRICT_MODE_PATCHED are referenced as shown.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2c0c97ca-883a-4887-a5e0-75731facab02

📥 Commits

Reviewing files that changed from the base of the PR and between 3e9a18f and d466e91.

📒 Files selected for processing (10)
  • react_on_rails_pro/spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx
  • react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ApolloGraphQLApp.client.jsx
  • react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/LazyApolloGraphQLApp.client.tsx
  • react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ManualRenderApp.jsx
  • react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ReduxApp.client.jsx
  • react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ReduxSharedStoreApp.client.jsx
  • react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsPro.js
  • react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsProClient.js
  • react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
  • react_on_rails_pro/spec/dummy/config/webpack/alias.js

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 25, 2026

Code Review

Overall this is a clean, well-structured PR. The approach — patching register at the entry-point level and manually wrapping renderer-function roots — is sound, and the webpack alias trick for the Pro dummy is a good way to intercept imports before startup runs. The Jest coverage for the OSS helper is a nice addition.

A few issues worth addressing:

Bugs / Correctness

  • Missing idempotency guard in client-bundle.js (inline comment): The ReactOnRails.register monkey-patch has no guard against being applied twice, unlike the Pro version's STRICT_MODE_PATCHED sentinel. Double-patching would silently nest two StrictMode layers around every component. The guard pattern from the Pro version should be ported over.

Code Quality

  • Redundant ternary in OSS createStrictModeWrapper (inline comment, line 26): typeof Component === 'function' ? <Component {...props} /> : React.createElement(Component, props) — both branches compile to identical JS. The Pro version already uses a single React.createElement call.

  • Missing displayName on StrictModeRenderFunction (inline comment, Pro strictModeSupport.tsx line 125): The wrapped render function never gets a displayName, making it anonymous in DevTools/stack traces. createStrictModeWrapper sets one for component wrappers — the same should apply here.

Clarity / Documentation

  • OSS vs Pro behavior divergence for 2-arg render functions (inline comment, OSS line 68): The OSS version skips all functions with length >= 2, while the Pro version wraps 2-arg render functions via wrapRenderFunctionInStrictMode. This asymmetry is intentional (the OSS dummy has no registered 2-arg render functions), but a short comment would prevent future confusion.

  • isRendererFunction edge case (inline comment, Pro line 55): The interaction of the renderFunction flag with the length === 3 check is subtle enough to warrant a comment.

Test Coverage

The OSS test suite covers the core paths well. Two gaps worth considering:

  1. No test for renderFunction = true flag behavior (a component with renderFunction = true and length < 2 should still be skipped).
  2. No tests for the Pro-specific paths: wrapRenderFunctionInStrictMode, enableStrictModeForReactOnRails, and the async (Promise-returning) render function case in wrapRenderFunctionResult. These are the most novel logic in the PR and the most likely to regress.

Minor

  • The isRenderFunction length heuristic (>= 2) is inherited from React on Rails' existing conventions and is acceptable here, but it would misclassify any 2-arg arrow function that happens to not be a render function. This is a pre-existing limitation and not a blocker for this PR.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d466e91b3d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Non-React plain object incorrectly wrapped as component
    • Updated strict mode registration wrapping to leave non-React plain object registrations unchanged while still wrapping valid React component element types.

Create PR

Or push these changes by commenting:

@cursor push 57f91ed27a
Preview (57f91ed27a)
diff --git a/react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx b/react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
--- a/react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
+++ b/react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
@@ -17,7 +17,13 @@
   prototype?: ReactClassPrototype;
 };
 
-type RegisteredComponent = string | ComponentWithMetadata | RenderFunction;
+type ReactElementTypeObject = {
+  $$typeof?: unknown;
+  displayName?: string;
+  name?: string;
+};
+type StrictModeWrappableComponent = string | ComponentWithMetadata | RenderFunction | ReactElementTypeObject;
+type RegisteredComponent = StrictModeWrappableComponent | object;
 type ComponentRegistry = Record<string, RegisteredComponent>;
 type ReactOnRailsWithRegister = {
   register: (components: ComponentRegistry) => void;
@@ -26,9 +32,12 @@
 
 const STRICT_MODE_PATCHED = '__reactOnRailsProDummyStrictModePatched';
 
-const wrappedFunctionComponents = new WeakMap<ComponentWithMetadata | RenderFunction, RegisteredComponent>();
+const wrappedFunctionComponents = new WeakMap<
+  ComponentWithMetadata | RenderFunction,
+  StrictModeWrappableComponent
+>();
 const wrappedRenderFunctions = new WeakMap<RenderFunction, RenderFunction>();
-const wrappedOtherComponents = new Map<RegisteredComponent, RegisteredComponent>();
+const wrappedOtherComponents = new Map<StrictModeWrappableComponent, StrictModeWrappableComponent>();
 
 const isPromiseLike = (value: unknown): value is Promise<unknown> =>
   typeof value === 'object' &&
@@ -41,11 +50,11 @@
     return false;
   }
 
-  if (component.prototype?.isReactComponent) {
+  if ((component.prototype as ReactClassPrototype | undefined)?.isReactComponent) {
     return false;
   }
 
-  if (component.renderFunction) {
+  if ('renderFunction' in component && component.renderFunction) {
     return true;
   }
 
@@ -55,7 +64,12 @@
 const isRendererFunction = (component: RegisteredComponent): component is RenderFunction =>
   isRenderFunction(component) && component.length === 3;
 
-const createStrictModeWrapper = (Component: RegisteredComponent): React.FC<Record<string, unknown>> => {
+const isReactElementTypeObject = (component: RegisteredComponent): component is ReactElementTypeObject =>
+  typeof component === 'object' && '$$typeof' in component && typeof component.$$typeof === 'symbol';
+
+const createStrictModeWrapper = (
+  Component: StrictModeWrappableComponent,
+): React.FC<Record<string, unknown>> => {
   function StrictModeWrapper(props: Record<string, unknown>) {
     const childElement =
       typeof Component === 'string'
@@ -74,7 +88,7 @@
   return StrictModeWrapper;
 };
 
-const wrapComponentInStrictMode = (component: RegisteredComponent): RegisteredComponent => {
+const wrapComponentInStrictMode = (component: StrictModeWrappableComponent): StrictModeWrappableComponent => {
   if (typeof component === 'function') {
     const cachedComponent = wrappedFunctionComponents.get(component);
     if (cachedComponent) {
@@ -110,7 +124,7 @@
   }
 
   if (typeof result === 'function') {
-    return wrapComponentInStrictMode(result as RegisteredComponent);
+    return wrapComponentInStrictMode(result as StrictModeWrappableComponent);
   }
 
   return result;
@@ -145,9 +159,17 @@
         return [name, wrapRenderFunctionInStrictMode(component)];
       }
 
+      if (
+        typeof component !== 'function' &&
+        typeof component !== 'string' &&
+        !isReactElementTypeObject(component)
+      ) {
+        return [name, component];
+      }
+
       return [name, wrapComponentInStrictMode(component)];
     }),
-  );
+  ) as ComponentRegistry;
 
 export const enableStrictModeForReactOnRails = <T extends ReactOnRailsWithRegister>(reactOnRails: T): T => {
   if (reactOnRails[STRICT_MODE_PATCHED]) {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit d466e91. Configure here.

Comment thread react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
@coderabbitai coderabbitai Bot added the P3 Parked priority label Apr 25, 2026
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 25, 2026

Code Review: Enable StrictMode in OSS and Pro Dummies

Overview

This PR adds React StrictMode wrappers to the OSS and Pro dummy apps via two complementary approaches: monkey-patching ReactOnRails.register to auto-wrap registered components, and explicit wrapElementInStrictMode calls in 3-arg renderer files that own their own roots. Scoped entirely to spec/dummy so production code is unaffected.

The implementation is well-structured, the Pro version's TypeScript types are precise, and the caching design (WeakMap for functions/objects, Map for strings) prevents wrapper duplication. Good work overall — a few issues below worth addressing before merge.


Issues

1. Potential Bug — RSC config only removes one of two StrictMode aliases

rscWebpackConfig.js deletes react-on-rails-pro$ from the RSC aliases but leaves react-on-rails-pro/client$ in place. If any RSC component (or a transitive import) pulls in the client path, it will receive the StrictMode client shim inside a React server bundle — which could cause a runtime error since the shim renders <React.StrictMode> using client-only APIs.

The fix is one extra line:

delete rscAliases['react-on-rails-pro$'];
delete rscAliases['react-on-rails-pro/client$']; // ← add this

2. Subtle edge case — isRendererFunction and the renderFunction = true flag

isRendererFunction is defined as isRenderFunction(component) && component.length === 3. A function that has both renderFunction = true and exactly 3 declared parameters will be classified as a renderer (skipped from wrapping) rather than as a render function (result-wrapped). Because isRenderFunction short-circuits on the flag, the length check then becomes the sole decider.

This edge case is unlikely in practice (explicit flag + 3 args is unusual), but a brief comment acknowledging it would help future readers.

3. No tests for Pro strictModeSupport.tsx

The OSS file ships with a solid Jest suite. The Pro version is substantially more complex (async result wrapping, render-function result interception, the enableStrictModeForReactOnRails patch) but has zero dedicated tests. At minimum, cover:

  • Render functions returning a JSX element have the result wrapped.
  • Async render functions have the resolved value wrapped.
  • enableStrictModeForReactOnRails is idempotent (double-call is a no-op).

4. OSS behaviour silently diverges from Pro

In OSS, all render functions (2-arg and 3-arg) are passed through unchanged. In Pro, only 3-arg renderer functions are skipped — 2-arg render functions have their results wrapped via wrapRenderFunctionInStrictMode. This means StrictMode penetration differs between the two dummy apps. The comment in the OSS file ("OSS dummy registered render functions own their root") explains the intent but is no longer accurate for the Pro side. A follow-up to align the two (or at least update the comment) would reduce future confusion.

5. serverWebpackConfig.resolve.alias accessed without null guard

serverWebpackConfig.resolve.alias['react-on-rails-pro$'] = ... will throw if commonWebpackConfig() ever returns a config without an initialized resolve.alias object. Given the existing alias setup in alias.js, this is unlikely to fail in practice, but a guard or the same spread-style used in the client config would be more robust.


Minor Notes

  • The module-level wrappedOtherComponents = new Map() in the OSS file will grow for the lifetime of the process, unlike the WeakMaps. For a test dummy this is not a memory concern, but the comment already acknowledges it.
  • The monkey-patched ReactOnRails.register in client-bundle.js uses a plain property assignment while STRICT_MODE_PATCHED uses Object.defineProperty. This asymmetry is harmless but slightly surprising — a comment noting that the patched register doesn't need to be non-writable would help.
  • React StrictMode on the server side (via strictModeReactOnRailsProNode.js) causes double-rendering of render functions to detect side effects. This is intentional, but if any server-rendered component has non-idempotent side effects, dummy server tests may see unexpected duplicate work. Worth a note in that shim file.

Comment thread react_on_rails_pro/spec/dummy/config/webpack/rscWebpackConfig.js
Comment thread react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js Outdated
Comment thread react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
Comment thread react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
Copy link
Copy Markdown
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.

🧹 Nitpick comments (3)
react_on_rails_pro/spec/dummy/config/webpack/rscWebpackConfig.js (1)

37-43: Consider adding a comment explaining the intentional asymmetry in the alias map, or defensively remove react-on-rails-pro/client$.

You scrub react-on-rails-pro$ so the RSC bundle resolves via the package's react-server conditional export. However, the inherited react-on-rails-pro/client$ alias still points to strictModeReactOnRailsProClient.js (which imports ReactOnRails.client). The Pro dummy's RSC graph does not currently import the /client subpath, but adding a comment clarifying this intentional asymmetry—or optionally removing the alias as a defensive measure—would prevent future accidental inclusion of client-only code in the react-server bundle.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails_pro/spec/dummy/config/webpack/rscWebpackConfig.js` around
lines 37 - 43, The alias map currently deletes 'react-on-rails-pro$' via
rscAliases but leaves 'react-on-rails-pro/client$' pointing to
strictModeReactOnRailsProClient.js, which risks pulling client-only code into
the RSC bundle; update the rscWebpackConfig logic to either remove
'react-on-rails-pro/client$' from rscAliases or add a concise comment next to
the rscAliases deletion explaining the intentional asymmetry (that the RSC graph
must resolve via the package's react-server conditional export and does not
import the /client subpath), referencing rscAliases, rscConfig.resolve.alias,
'react-on-rails-pro$', and 'react-on-rails-pro/client$' so future maintainers
understand or defensively avoid the client alias.
react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js (1)

28-35: Server alias only overrides react-on-rails-pro$, not react-on-rails-pro/client$.

The base alias.js resolves both react-on-rails-pro$ and react-on-rails-pro/client$. Here you only override the bare specifier to the Node strict-mode wrapper, so any server-side import of react-on-rails-pro/client will still pull the client wrapper (strictModeReactOnRailsProClient.js, which wraps ReactOnRails.client). That's currently unused on the server, but it's a latent footgun if/when SSR code starts importing the /client subpath.

Consider either also overriding react-on-rails-pro/client$ here (e.g., to the Node wrapper or to false) or adding a comment that the /client alias is intentionally inherited.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js` around
lines 28 - 35, The server webpack alias currently only overrides
react-on-rails-pro$ to strictModeReactOnRailsProNode.js but leaves
react-on-rails-pro/client$ pointing to the client wrapper
(strictModeReactOnRailsProClient.js); update serverWebpackConfig.resolve.alias
to also set 'react-on-rails-pro/client$' to the Node wrapper (or to false) to
prevent server bundles from resolving the client wrapper, or alternatively add a
clear comment next to serverWebpackConfig.resolve.alias documenting that the
client subpath is intentionally inherited; reference the alias map
(serverWebpackConfig.resolve.alias), the specifier 'react-on-rails-pro/client$',
and the files strictModeReactOnRailsProNode.js and
strictModeReactOnRailsProClient.js when making the change.
react_on_rails/spec/dummy/client/app/strictModeSupport.jsx (1)

1-68: LGTM — clean, well-scoped StrictMode helper.

The isRenderFunction heuristic faithfully mirrors the public react-on-rails convention (class detection via prototype.isReactComponent, explicit .renderFunction flag, arity ≥ 2 covering both 2‑arg render and 3‑arg renderer signatures). Caching is sensible: WeakMap for function/class components allows GC when originals go unreferenced, while Map correctly handles non‑function component types (e.g., React.memo/React.forwardRef objects, which are typeof === 'object'). displayName resolution including the string‑component branch is a nice touch for debuggability.

One minor optional consideration: the wrappedOtherComponents Map is module‑scoped and never pruned, so any non‑function components registered over time stay referenced for the lifetime of the JS runtime. In a dummy app this is fine — just noting it in case the helper ever gets reused outside spec/dummy.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react_on_rails/spec/dummy/client/app/strictModeSupport.jsx` around lines 1 -
68, The module-scoped Map wrappedOtherComponents can hold non-function component
keys indefinitely; to avoid memory growth, add an explicit cleanup/unregister
API (e.g., export a function like unregisterWrappedComponent(nameOrComponent)
and/or clearWrappedOtherComponents()) and call it when dummy registered
components are torn down; implement the functions near wrapComponentInStrictMode
and update any test dummy teardown to call them so
wrappedOtherComponents.delete(key) or wrappedOtherComponents.clear() runs as
part of lifecycle to release references.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@react_on_rails_pro/spec/dummy/config/webpack/rscWebpackConfig.js`:
- Around line 37-43: The alias map currently deletes 'react-on-rails-pro$' via
rscAliases but leaves 'react-on-rails-pro/client$' pointing to
strictModeReactOnRailsProClient.js, which risks pulling client-only code into
the RSC bundle; update the rscWebpackConfig logic to either remove
'react-on-rails-pro/client$' from rscAliases or add a concise comment next to
the rscAliases deletion explaining the intentional asymmetry (that the RSC graph
must resolve via the package's react-server conditional export and does not
import the /client subpath), referencing rscAliases, rscConfig.resolve.alias,
'react-on-rails-pro$', and 'react-on-rails-pro/client$' so future maintainers
understand or defensively avoid the client alias.

In `@react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js`:
- Around line 28-35: The server webpack alias currently only overrides
react-on-rails-pro$ to strictModeReactOnRailsProNode.js but leaves
react-on-rails-pro/client$ pointing to the client wrapper
(strictModeReactOnRailsProClient.js); update serverWebpackConfig.resolve.alias
to also set 'react-on-rails-pro/client$' to the Node wrapper (or to false) to
prevent server bundles from resolving the client wrapper, or alternatively add a
clear comment next to serverWebpackConfig.resolve.alias documenting that the
client subpath is intentionally inherited; reference the alias map
(serverWebpackConfig.resolve.alias), the specifier 'react-on-rails-pro/client$',
and the files strictModeReactOnRailsProNode.js and
strictModeReactOnRailsProClient.js when making the change.

In `@react_on_rails/spec/dummy/client/app/strictModeSupport.jsx`:
- Around line 1-68: The module-scoped Map wrappedOtherComponents can hold
non-function component keys indefinitely; to avoid memory growth, add an
explicit cleanup/unregister API (e.g., export a function like
unregisterWrappedComponent(nameOrComponent) and/or
clearWrappedOtherComponents()) and call it when dummy registered components are
torn down; implement the functions near wrapComponentInStrictMode and update any
test dummy teardown to call them so wrappedOtherComponents.delete(key) or
wrappedOtherComponents.clear() runs as part of lifecycle to release references.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6e83f9b0-e1a5-430c-8f09-32cf06266714

📥 Commits

Reviewing files that changed from the base of the PR and between d466e91 and 45da8de.

📒 Files selected for processing (9)
  • react_on_rails/spec/dummy/client/app/packs/client-bundle.js
  • react_on_rails/spec/dummy/client/app/strictModeSupport.jsx
  • react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx
  • react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsPro.js
  • react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsProClient.js
  • react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsProNode.js
  • react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
  • react_on_rails_pro/spec/dummy/config/webpack/rscWebpackConfig.js
  • react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js
✅ Files skipped from review due to trivial changes (1)
  • react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • react_on_rails_pro/spec/dummy/client/app/strictModeReactOnRailsProClient.js
  • react_on_rails/spec/dummy/client/app/packs/client-bundle.js

Picks up the optional-tier review feedback on PR #3206:

- RSC bundle now also drops the `react-on-rails-pro/client$` alias so the
  client-only StrictMode shim cannot resolve inside the React server bundle.
- `serverWebpackConfig` writes its alias override via a defensive spread
  rather than mutating `resolve.alias` directly.
- OSS `strictModeSupport` splits the non-function cache into a WeakMap for
  object components (memo/forwardRef/lazy) and a Map for string keys, so
  registered objects are no longer pinned for the lifetime of the module.
- OSS `isRenderFunction` documents the `length >= 2` heuristic and how to
  opt out of it.
- `client-bundle.js` documents the bundle-scope limitation of the register
  patch.
- Adds a Jest case that pins down 2-arg functional component handling.
- React 16 dummy startup files document the intentional cross-tree import
  of `app/strictModeSupport`.
- Pro `wrapRenderFunctionInStrictMode` documents the `length === 2`
  invariant and why STRICT_MODE_PATCHED keeps it safe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@justin808
Copy link
Copy Markdown
Member Author

Review summary update — 3dd51c984

I (Claude Code) worked through the remaining unresolved review threads (greptile / claude / chatgpt-codex / coderabbit / cursor) on this PR. All 20 unresolved threads are now answered and resolved.

What changed in this push

3dd51c984 test(dummy): address StrictMode review feedback (commit):

  • RSC bundle alias hardeningrscWebpackConfig.js now also deletes react-on-rails-pro/client$ so the client-only StrictMode shim cannot resolve inside the React server bundle.
  • Defensive serverWebpackConfig alias write — switched from serverWebpackConfig.resolve.alias['react-on-rails-pro$'] = ... to a spread that mirrors rscWebpackConfig.js.
  • OSS WeakMap / Map splitwrappedFunctionComponents (WeakMap), wrappedObjectComponents (WeakMap, for memo/forwardRef/lazy), and wrappedStringComponents (Map) so non-function React objects are no longer pinned for the lifetime of the module.
  • Heuristic + scope docs — added inline comments above OSS isRenderFunction (length>=2 heuristic, opt-out path) and on the client-bundle.js register-patch scope (covers this bundle + inline ERB; would not affect packs that import react-on-rails/client independently).
  • 2-arg functional component teststrict-mode-support.test.jsx now pins down arity-based detection so a future change to isRenderFunction has to update the test alongside the behavior.
  • React 16 cross-tree import note — the three app-react16/startup files explicitly call out the intentional reuse of app/strictModeSupport.
  • Pro length === 2 invariant — added a comment above wrapRenderFunctionInStrictMode documenting why STRICT_MODE_PATCHED keeps the wrapper from being re-classified.

Local check: pnpm exec eslint, pnpm exec prettier --check, and cd react_on_rails/spec/dummy && pnpm exec jest tests/strict-mode-support.test.jsx (6 tests, all green).

Threads marked as already addressed in earlier commits

These reviewer threads were already covered by 3e9a18fd1, d466e91b3, and 45da8decf before this round; I posted a rationale reply on each pointing at the relevant commit/line and marked them resolved:

  • isRenderFunction is a verbatim copy — comment added at OSS strictModeSupport.jsx:6.
  • redundant ternary (×2) — createStrictModeWrapper now uses React.createElement directly.
  • WeakMap vs Map asymmetry — see the cache split above.
  • register-patch scope — comment added in client-bundle.js; further refined in this push.
  • OSS skips all length>=2 vs Pro wraps 2-arg — divergence note in wrapRegisteredComponentsWithStrictMode.
  • No idempotency guardSTRICT_MODE_PATCHED sentinel.
  • Wrapped render function lacks displayName — set on wrappedRenderFunction.displayName.
  • renderFunction=true + length=3 edge case (×2) — comment above isRendererFunction.
  • No test for renderFunction = true flag — covered by the flaggedRenderFunction case.
  • codex P1: preserve conditional Pro entrypoints — three shims (full/client/Node) plus the RSC alias deletes.

Already-resolved bot threads (cursor, coderabbit ×2) were left as-is.

CI is currently running on 3dd51c984; I'll keep an eye on it. Happy to chase the optional follow-up of adding a Jest suite for react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx in a separate PR if you'd like — it was flagged in the claude[bot] summary review but isn't in scope for this PR.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 29, 2026

Code Review

Overview

This PR adds React StrictMode to the OSS and Pro spec/dummy apps. All changes are correctly scoped to test/dummy files, with no production code modified. The core mechanism is a helper module per dummy app that wraps components in <React.StrictMode> at registration time, combined with webpack aliases to redirect react-on-rails-pro imports through the StrictMode shims.


Strengths

  • Correct scope: Only touches spec/dummy - zero production risk.
  • Idempotency guard: STRICT_MODE_PATCHED sentinel on both the OSS and Pro patched singletons correctly prevents double-wrapping.
  • Three-tier cache: Using separate WeakMaps for function and object components plus a Map for string components is the right approach (strings are primitives and cannot be WeakMap keys).
  • RSC alias cleanup: rscWebpackConfig.js correctly removes both strict-mode shim aliases before adding react-server overrides.
  • Documented cross-tree import: React 16 files importing from the React 19 app/ tree are flagged with clear inline comments.
  • Tests pin down heuristics: The 2-arg component test explicitly documents the arity heuristic so future changes must update both code and test together.

Issues

1. Server-side StrictMode is a no-op (adds dead weight)

strictModeReactOnRailsProNode.js patches register to wrap SSR components in <React.StrictMode>. React StrictMode checks (double-invocation of effects/lifecycles, strict ref checks) do not run during server-side rendering — the <React.StrictMode> wrapper is silently ignored by React in SSR. The serverWebpackConfig.js alias therefore adds complexity and function-call overhead for no benefit. Consider either omitting the server alias or adding a comment acknowledging the no-op.

2. OSS and Pro render-function handling are asymmetric

  • OSS (strictModeSupport.jsx): skips wrapping for ALL length >= 2 functions (both 2-arg render functions and 3-arg renderer functions).
  • Pro (strictModeSupport.tsx): skips 3-arg renderer functions but wraps 2-arg render functions by intercepting their return values via wrapRenderFunctionResult.

This means a 2-arg render function registered in the OSS dummy gets no StrictMode coverage, while the same pattern in the Pro dummy does. If the OSS dummy has 2-arg render functions that return React elements, they're silently excluded. Is this intentional, or should OSS be brought to parity?

3. Missing test coverage for Pro's additional logic

The Jest suite only tests the OSS helper. Pro's strictModeSupport.tsx adds meaningful extra logic with no tests:

  • enableStrictModeForReactOnRails (singleton mutation + idempotency guard)
  • wrapRenderFunctionResult (async/Promise-returning render functions)
  • wrapRenderFunctionInStrictMode (render function interception)

At minimum, a TODO comment in the Pro helper pointing to where tests could live would prevent the coverage gap from going unnoticed.

4. Minor: wrappedStringComponents Map never gets garbage collected

The module-level Map (lines 185 in OSS, 577 in Pro) accumulates entries for every unique string component name and holds them for the lifetime of the module. For a test dummy this is negligible, but a short comment acknowledging this would prevent future confusion.


Verdict

Implementation is correct and well-considered. Issues 1 and 2 are worth addressing before merge; issues 3 and 4 are polish.

Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx Outdated
Comment thread react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx Outdated
Comment thread react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
Comment thread react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@react_on_rails/spec/dummy/client/app/strictModeSupport.jsx`:
- Around line 23-27: The current detection in strictModeSupport.jsx treats only
truthy component.renderFunction as an override, so setting
component.renderFunction = false doesn't opt out; update the logic in the
detection function to first check whether the component has an explicit
renderFunction property (e.g., via "renderFunction" in component or
hasOwnProperty) and if present return its boolean value (false to opt out, true
to opt in); otherwise fall back to the existing length check (component.length
>= 2). Ensure you update the branch that currently uses if
(component.renderFunction) and the final return using component.length to follow
this explicit-property-first behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cdb11ff6-2ec2-408d-b03d-a2218c79ac8f

📥 Commits

Reviewing files that changed from the base of the PR and between 45da8de and 3dd51c9.

📒 Files selected for processing (9)
  • react_on_rails/spec/dummy/client/app-react16/startup/ManualRenderApp.jsx
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxSharedStoreApp.client.jsx
  • react_on_rails/spec/dummy/client/app/packs/client-bundle.js
  • react_on_rails/spec/dummy/client/app/strictModeSupport.jsx
  • react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx
  • react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
  • react_on_rails_pro/spec/dummy/config/webpack/rscWebpackConfig.js
  • react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js
✅ Files skipped from review due to trivial changes (1)
  • react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js
  • react_on_rails/spec/dummy/client/app/packs/client-bundle.js
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxSharedStoreApp.client.jsx
  • react_on_rails_pro/spec/dummy/config/webpack/rscWebpackConfig.js
  • react_on_rails/spec/dummy/client/app-react16/startup/ManualRenderApp.jsx
  • react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
  • react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx

Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx Outdated
Address remaining review feedback on PR #3206:

- OSS strictModeSupport.jsx now mirrors the Pro structure: adds
  isRendererFunction, isReactComponent, wrapRenderFunctionResult, and
  wrapRenderFunctionInStrictMode so 2-arg render functions
  (e.g. ContextFunctionReturnInvalidJSX, HelloWorldHooksContext) get
  StrictMode coverage via return-value interception instead of being
  skipped entirely.
- isRenderFunction in OSS and Pro now honors explicit
  `renderFunction = false` so legacy 2-arg `(props, context)` components
  can opt out of the render-function classification (matches the
  contract in the comment block).
- Pro RenderFunction type widens `renderFunction?: true` to
  `renderFunction?: boolean` to reflect the new opt-out.
- Pro Node shim documents that <React.StrictMode> is a no-op in SSR; we
  keep the wrapping for client/server uniformity.
- Adds inline comments on Pro `wrappedStringComponents` Map and the
  wrapper-arity edge case for direct callers; adds TODO for Pro test
  coverage of `enableStrictModeForReactOnRails` / Promise paths.
- Updates jest tests to cover the new wrapping paths plus the
  `renderFunction = false` opt-out.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@justin808
Copy link
Copy Markdown
Member Author

Review summary update — ae6c115b3

I (Claude Code) addressed the 6 remaining unresolved review threads on this PR.

MUST-FIX

  • renderFunction = false opt-out (@coderabbitai). isRenderFunction now honors an explicit boolean (true or false) before falling back to the length >= 2 heuristic, so legacy 2-arg (props, context) components can opt out of the render-function classification — matching the contract in the comment block. Applied symmetrically to OSS strictModeSupport.jsx and Pro strictModeSupport.tsx. Pro RenderFunction type widened from renderFunction?: true to renderFunction?: boolean. New jest test "respects explicit renderFunction = false on 2-arg components" pins the behavior.

DISCUSS — addressed in code

  • OSS/Pro parity (@claude). OSS strictModeSupport.jsx is now structurally a port of Pro: adds isRendererFunction, isReactComponent, wrapRenderFunctionResult, and wrapRenderFunctionInStrictMode. 2-arg render functions (e.g. ContextFunctionReturnInvalidJSX, HelloWorldHooksContext) that previously fell through unwrapped now flow through the render-function path with their return values intercepted in <React.StrictMode>. 3-arg renderers still skipped (they own their root). Tests updated to cover the new paths (12 passing).
  • SSR no-op (@claude). strictModeReactOnRailsProNode.js now documents that <React.StrictMode> is a client-only construct (no double-invocation, deprecated-API, or ref-validation checks at SSR time). The wrap is kept in place for client/server uniformity; runtime cost is bounded by the WeakMap caches.

OPTIONAL

  • Pro wrappedStringComponents Map now carries the same "strings can't key a WeakMap" comment as OSS line 6 (@claude).
  • Pro wrapRenderFunctionInStrictMode block-comment extended to call out the direct-caller arity precondition (@claude). The isRendererFunction ordering inside wrapRegisteredComponentsWithStrictMode keeps the unsafe path unreachable through the registry.
  • Pro strictModeSupport.tsx carries a TODO pointing maintainers at where Pro-specific test coverage (Promise/enableStrictModeForReactOnRails/idempotency) could land (@claude).

Verification

  • pnpm jest react_on_rails/spec/dummy/tests/strict-mode-support.test.jsx — 12/12 passing.
  • pnpm run type-check (workspace-wide tsc) — clean.
  • pnpm run eslint on all four touched files — clean (Pro lint runs through its own config).
  • Pre-commit hooks (prettier + eslint on changed root and Pro files) — green.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

Review rate limit: 6/8 reviews remaining, refill in 8 minutes and 47 seconds.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 29, 2026

Code Review — PR #3206: Enable StrictMode in OSS and Pro Dummies

Overall: This is a well-thought-out implementation. The design rationale (monkey-patching register, WeakMap caching, renderer-function exemptions, RSC alias cleanup) is solid. A few issues worth addressing before merge:


Bugs / Correctness

String component wrapping produces invalid output. isReactComponent returns true for strings, so createStrictModeWrapper('MyComponent') creates a StrictModeWrapper that calls React.createElement('MyComponent', props) — this renders an unknown HTML/custom element, not a ReactOnRails-registered component. Since RoR component registrations always supply actual function/class/object values (not strings), this code path is currently unreachable. But the type signature and string-keyed Map imply it's intended to work, which it does not. Either remove the string branch or add a clarifying comment that it is dead/reserved code.

Server bundle inherits react-on-rails-pro/client$ alias. serverWebpackConfig.js spreads all aliases from commonWebpackConfig() (which includes react-on-rails-pro/client$strictModeReactOnRailsProClient.js) and only overrides react-on-rails-pro$. If any server-side code ever imports react-on-rails-pro/client, it will pull the browser-specific shim into the server bundle. The RSC config correctly deletes this alias for the same reason; the server config should do the same.


Test Coverage

Pro-specific paths have no tests. enableStrictModeForReactOnRails singleton patching, idempotency, and the async Promise-result wrapping path in wrapRenderFunctionResult are only covered by a TODO comment in the Pro file. Given that the OSS dummy already has a Jest harness, it would be low-effort to add a parallel strict-mode-support.test under react_on_rails_pro/spec/dummy/tests/.


Code Quality

Duplication between OSS .jsx and Pro .tsx. The two strictModeSupport files share ~80% of their logic but diverge at enableStrictModeForReactOnRails. If the shared logic needs a bug fix, both files must be updated. A shared base module would reduce drift risk; at minimum, a cross-reference comment linking the two files would help maintainers.

Cross-tree React-16 imports are a silent fragility. The three React 16 startup files import from ../../app/strictModeSupport (the React 19 tree). The comments explain the intent clearly, but this path won't be caught if the helper is moved and only the React 19 tree is searched. A lint rule or path alias would make this more robust.

Wrapped render-function arity footgun. wrapRenderFunctionInStrictMode returns a function with hardcoded length === 2. The STRICT_MODE_PATCHED guard prevents re-entry through the registry path, but the comment warns that direct callers must not pass a 3-arg renderer here. This is a subtle precondition that will likely surprise future maintainers — worth adding a runtime length assertion or making the guard more explicit.


Minor

  • wrappedStringComponents is a plain Map (strong references). Not an issue for a test/dummy app, but it's inconsistent with the WeakMap choices for function and object components.
  • Test assertions like wrappedElement.props.children.type inspect internal React element structure and may need updating if React's element representation changes.

Comment thread react_on_rails/spec/dummy/client/app/strictModeSupport.jsx Outdated
Comment thread react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js
Comment thread react_on_rails_pro/spec/dummy/client/app/strictModeSupport.tsx Outdated
Comment thread react_on_rails/spec/dummy/client/app/packs/client-bundle.js Outdated
… scope comment, Pro tests

Addresses the four unresolved review threads on #3206:

- Pro `serverWebpackConfig.js` now drops the `react-on-rails-pro/client$` alias before applying its own `react-on-rails-pro$` override, mirroring the RSC config so the SSR bundle never resolves to the browser-only StrictMode shim.
- Removed the unreachable `typeof component === 'string'` branch (and `wrappedStringComponents` Map) from both OSS `strictModeSupport.jsx` and Pro `strictModeSupport.tsx`. ReactOnRails registrations only ever pass actual component values; the dead branch would have rendered an unknown HTML element if hit.
- Expanded the scope comment in `client-bundle.js` to enumerate what's currently covered (this pack, the auto-generated `packs/generated/*.js`, ERB-inline `register` calls) and to spell out how a future independent pack should opt in.
- Added a Jest harness in `react_on_rails_pro/spec/dummy/tests/` (jest.config.cjs + ts-jest) with five tests pinning the Pro-specific behaviors that previously had only a TODO: register-time wrapping, `enableStrictModeForReactOnRails` idempotency, async `Promise<ReactElement>` results, 3-arg renderer skip, and `wrapElementInStrictMode`. Removed the now-resolved TODO comment.

Verification:
- `pnpm --filter react_on_rails_pro_dummy run test:js` — 5/5 passing
- `pnpm --filter react-on-rails run test:js` — 14/14 passing
- `pnpm run type-check` (workspace) — clean
- ESLint + Prettier on all touched files — clean (root and Pro configs)
- `RAILS_ENV=test NODE_ENV=test bin/shakapacker` for Pro dummy — succeeds; resulting `ssr-generated/server-bundle.js` references `strictModeReactOnRailsProNode` only (no `strictModeReactOnRailsProClient` strings)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@justin808
Copy link
Copy Markdown
Member Author

Review summary update — d526ecd18

I (Claude Code) addressed the four unresolved review threads on this PR and posted rationale on the remaining minor items from the latest code review summary.

MUST-FIX

  • Pro server bundle alias (@claude). react_on_rails_pro/spec/dummy/config/webpack/serverWebpackConfig.js now clones the alias map, deletes react-on-rails-pro/client$ (the browser-only StrictMode shim), and then applies the react-on-rails-pro$ Node override — mirroring the RSC config. Verified by grepping the resulting ssr-generated/server-bundle.js: strictModeReactOnRailsProClient no longer appears; only strictModeReactOnRailsProNode is referenced.

OPTIONAL — addressed in code

  • Dead string-component branch removed (@claude). Both OSS strictModeSupport.jsx and Pro strictModeSupport.tsx lost the typeof component === 'string' branch in isReactComponent, the string branch in wrapComponentInStrictMode, the wrappedStringComponents Map, and the string-displayName branch in createStrictModeWrapper. Pro ComponentWithMetadata narrowed from string | CallableComponent | ObjectComponent to CallableComponent | ObjectComponent. ReactOnRails registrations only ever pass actual component values, so the path was unreachable.
  • Pro Jest harness added (@claude). react_on_rails_pro/spec/dummy/jest.config.cjs (ts-jest) plus tests/strict-mode-support.test.tsx with 5 tests pinning the Pro-specific behaviors that previously had only a TODO: register-time wrapping, enableStrictModeForReactOnRails idempotency, async Promise<ReactElement> results from wrapRenderFunctionResult, 3-arg renderer skip, and wrapElementInStrictMode. Pulls jest/ts-jest/@types/jest from the workspace root — no new dummy-level dev deps. New pnpm run test:js script and tests/** added to tsconfig.json. Removed the now-resolved TODO comment in strictModeSupport.tsx.
  • Scope comment in client-bundle.js (@claude). Replaced the short caveat with an explicit coverage list (this pack + its imports, the packs/generated/*.js entries, ERB-inline register calls, manual-render trees that wrap directly) and a "what to do when adding a new pack" note. Kept inline rather than a separate README so contributors see it right where they're editing the pack.

Rationale on remaining review-summary minor items

  • "Cross-tree React-16 imports are a silent fragility" — declined as scope creep. Each app-react16/startup/*.jsx file already carries an explicit comment about the cross-tree import to app/strictModeSupport. A lint rule or path alias is a meaningful addition that should land in its own PR if it's wanted.
  • "Test assertions like wrappedElement.props.children.type inspect internal React element structure" — declined as a style nit. React.isValidElement + .type / .props is a stable React 18/19 public element API used widely in test code; switching to react-test-renderer or @testing-library/react would expand the dummy's test surface without pinning anything new.
  • "wrappedStringComponents is a plain Map" — moot now that the string branch is gone (the Map and its callsites were deleted along with the dead branch).
  • "Duplication between OSS .jsx and Pro .tsx" — the prior pass (3dd51c984) already brought the OSS file structurally to parity with Pro. A shared base module would require moving the helper out of spec/dummy into a shared location, which is a refactor beyond the scope of "enable StrictMode in the dummies."
  • "Wrapped render-function arity footgun" — already documented via the block comment above wrapRenderFunctionInStrictMode in both OSS and Pro (the STRICT_MODE_PATCHED guard plus isRendererFunction ordering keep the unsafe path unreachable through the registry; direct callers should treat the 2-arity wrapper as a precondition).

Verification

  • pnpm --filter react_on_rails_pro_dummy run test:js — 5/5 passing
  • pnpm --filter react-on-rails run test:js — 14/14 passing
  • pnpm run type-check (workspace) — clean
  • ESLint + Prettier on all touched files — clean (root and Pro configs)
  • RAILS_ENV=test NODE_ENV=test bin/shakapacker for Pro dummy — succeeds; SSR bundle no longer references strictModeReactOnRailsProClient

@justin808 justin808 merged commit 573c89f into main Apr 30, 2026
43 of 44 checks passed
@justin808 justin808 deleted the jg-conductor/fix-1465 branch April 30, 2026 08:48
justin808 added a commit that referenced this pull request Apr 30, 2026
* origin/main:
  Document examples catalog and naming plan (#3191)
  test(dummy): enable StrictMode in OSS and Pro dummies (#3206)
  ci: exclude bot-blocking URLs from lychee link check (#3214)
  Remove stale Coveralls integration (#3204)
  docs: normalize external GitHub repo slugs in links and generators (#3198)

# Conflicts:
#	.lychee.toml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Parked priority review-needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable StrictMode everywhere in spec/dummy

1 participant