Docs: fix RSC migration gaps found during real-world migration#2842
Docs: fix RSC migration gaps found during real-world migration#2842AbanoubGhadban merged 1 commit intomainfrom
Conversation
Based on issues encountered migrating HiChee to RSC: rsc-preparing-app.md: - Add ReScript/transpiled language guidance to Step 5 (missing 'use client' on wrapper .jsx files caused silent server component misclassification) - Add compression middleware warning to Step 6 (Rack::Deflater deadlocks with ActionController::Live streaming) rsc-troubleshooting.md: - Add railsContext non-serializable functions section (addPostSSRHook, getRSCPayloadStream can't cross RSC boundary) - Add view annotations and railsContext entries to error message catalog render-functions-and-railscontext.md: - Add RSC note about non-serializable functions in railsContext Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
WalkthroughDocumentation updates addressing RSC adoption gaps: added guidance for handling non-serializable functions in railsContext when crossing RSC boundaries, clarified transpiled language component directive placement, documented compression middleware streaming compatibility, and expanded RSC troubleshooting error catalog with JSON parsing and railsContext-related issues. Changes
Poem
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~8 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR fills documentation gaps discovered during a real-world RSC migration, covering ReScript/transpiled-language
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Server Component render function\n(props, railsContext)"] --> B{"Does railsContext\ncontain functions?"}
B -- "Yes (Pro: addPostSSRHook,\ngetRSCPayloadStream)" --> C["Destructure: strip\nnon-serializable keys"]
C --> D["Pass serializableContext\nto Client Component"]
B -- "No functions" --> D
D --> E["RSC boundary ✅\nClient Component receives\nplain-object railsContext"]
F["Wrapper .jsx file\n(ror_components/)"] --> G{"Language?"}
G -- "JS/TS" --> H["Add 'use client'\nto .jsx/.tsx"]
G -- "ReScript/Reason" --> I["Add 'use client'\nto .client.jsx and\n.server.jsx wrappers\nNOT .bs.js compiled files"]
H --> J["Pack generator registers\nas Client Component ✅"]
I --> J
K["Missing 'use client'"] --> L["Silently registered as\nServer Component ❌\nBreaks at runtime"]
Reviews (1): Last reviewed commit: "Docs: fix RSC migration gaps found durin..." | Re-trigger Greptile |
|
|
||
| Replace synchronous view helpers and controller rendering with their streaming equivalents. | ||
|
|
||
| > **Warning: Compression middleware.** If your app uses `Rack::Deflater`, `Rack::Brotli`, or similar compression middleware, streaming responses will deadlock. The middleware calls `body.each` to check the response size, which blocks on `ActionController::Live::Buffer`. See [Compression Middleware Compatibility](../building-features/streaming-server-rendering.md#compression-middleware-compatibility) for the fix. |
There was a problem hiding this comment.
Broken anchor link for compression middleware section
The link ../building-features/streaming-server-rendering.md#compression-middleware-compatibility will not work as intended. The streaming-server-rendering.md file does not contain a #compression-middleware-compatibility section — it only has a short overview page that links to the Pro guide. The actual anchor lives at docs/pro/streaming-ssr.md#compression-middleware-compatibility.
Other docs in the repo confirm the correct relative path from docs/oss/migrating/ — for example, docs/oss/deployment/server-rendering-tips.md uses ../../pro/streaming-ssr.md#compression-middleware-compatibility.
| > **Warning: Compression middleware.** If your app uses `Rack::Deflater`, `Rack::Brotli`, or similar compression middleware, streaming responses will deadlock. The middleware calls `body.each` to check the response size, which blocks on `ActionController::Live::Buffer`. See [Compression Middleware Compatibility](../building-features/streaming-server-rendering.md#compression-middleware-compatibility) for the fix. | |
| > **Warning: Compression middleware.** If your app uses `Rack::Deflater`, `Rack::Brotli`, or similar compression middleware, streaming responses will deadlock. The middleware calls `body.each` to check the response size, which blocks on `ActionController::Live::Buffer`. See [Compression Middleware Compatibility](../../pro/streaming-ssr.md#compression-middleware-compatibility) for the fix. |
| return () => ( | ||
| <ClientComponent {...props} railsContext={serializableContext} /> | ||
| ); |
There was a problem hiding this comment.
Thunk pattern may be confusing in RSC context
The return () => (...) thunk is the correct React on Rails render-function pattern for SSR (required when the function takes two params per the upgrading guide). However, a developer reading this in an RSC troubleshooting guide might be confused because Server Components are typically async functions that return JSX directly.
Consider adding a brief inline comment clarifying why the thunk is needed here:
| return () => ( | |
| <ClientComponent {...props} railsContext={serializableContext} /> | |
| ); | |
| return () => ( | |
| // React on Rails render functions that accept (props, railsContext) must return | |
| // a thunk — a function that returns JSX — rather than JSX directly. | |
| <ClientComponent {...props} railsContext={serializableContext} /> | |
| ); |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
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 `@docs/oss/migrating/rsc-troubleshooting.md`:
- Around line 109-112: Update the unlabeled fenced code block containing the
message "Functions cannot be passed directly to Client Components unless you
explicitly expose it by marking it with 'use server'." to include a language tag
by changing the fence to use "text" (i.e., mark the block as ```text) so the
snippet is labeled for MD040 and editor syntax highlighting.
🪄 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: 5d0d1a0e-71bc-4656-978a-c056db1dc9c3
📒 Files selected for processing (3)
docs/oss/core-concepts/render-functions-and-railscontext.mddocs/oss/migrating/rsc-preparing-app.mddocs/oss/migrating/rsc-troubleshooting.md
| ``` | ||
| Functions cannot be passed directly to Client Components | ||
| unless you explicitly expose it by marking it with "use server". | ||
| ``` |
There was a problem hiding this comment.
Add a language to the fenced code block.
Line 109 uses an unlabeled fenced block, which triggers MD040 and reduces editor syntax support. Use ```text for this error snippet.
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 109-109: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/oss/migrating/rsc-troubleshooting.md` around lines 109 - 112, Update the
unlabeled fenced code block containing the message "Functions cannot be passed
directly to Client Components unless you explicitly expose it by marking it with
'use server'." to include a language tag by changing the fence to use "text"
(i.e., mark the block as ```text) so the snippet is labeled for MD040 and editor
syntax highlighting.
|
|
||
| Replace synchronous view helpers and controller rendering with their streaming equivalents. | ||
|
|
||
| > **Warning: Compression middleware.** If your app uses `Rack::Deflater`, `Rack::Brotli`, or similar compression middleware, streaming responses will deadlock. The middleware calls `body.each` to check the response size, which blocks on `ActionController::Live::Buffer`. See [Compression Middleware Compatibility](../building-features/streaming-server-rendering.md#compression-middleware-compatibility) for the fix. |
There was a problem hiding this comment.
Two issues with this warning:
1. Broken link — The anchor #compression-middleware-compatibility does not exist in ../building-features/streaming-server-rendering.md. That file only has a one-line blurb that itself links to the Pro guide. The section lives in docs/pro/streaming-ssr.md. The correct relative path from this file is:
| > **Warning: Compression middleware.** If your app uses `Rack::Deflater`, `Rack::Brotli`, or similar compression middleware, streaming responses will deadlock. The middleware calls `body.each` to check the response size, which blocks on `ActionController::Live::Buffer`. See [Compression Middleware Compatibility](../building-features/streaming-server-rendering.md#compression-middleware-compatibility) for the fix. | |
| > **Warning: Compression middleware.** If your app uses `Rack::Deflater`, `Rack::Brotli`, or similar compression middleware **with an `:if` condition that calls `body.each`**, streaming responses will deadlock. The `:if` callback destructively consumes all chunks from the queue before the compressor can read them. See [Compression Middleware Compatibility](../../pro/streaming-ssr.md#compression-middleware-compatibility) for the safe pattern. |
2. Misleading framing — The current text says "streaming responses will deadlock" any time these middlewares are present, but docs/pro/streaming-ssr.md line 168 explicitly states: "Standard Rack compression middleware (Rack::Deflater, Rack::Brotli) works correctly with streaming by default." The deadlock only triggers when an :if lambda calls body.each on the streaming body. The warning should scope the condition so developers don't unnecessarily disable compression.
| ```jsx | ||
| // Server Component (render function) | ||
| const MyPage = (props, railsContext) => { | ||
| const { addPostSSRHook, getRSCPayloadStream, ...serializableContext } = railsContext; | ||
| return () => ( | ||
| <ClientComponent {...props} railsContext={serializableContext} /> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
The return () => (...) pattern here is the React on Rails render-function-returns-a-component idiom, which differs from the async function Page() pattern used in every other RSC example in this file (e.g. lines 134–145). Without explanation a reader will be confused about which pattern to use.
Consider adding a one-sentence note like:
MyPageis a React on Rails render function (registered viaReactOnRails.register). It returns a thunk() => (...)which React on Rails renders as the Server Component. If you are writing an async Server Component directly, drop the outer wrapper and return JSX or a Promise directly.
Also, if the outer function (props, railsContext) is the render function, the inner () => (...) is the actual component — but that inner function receives no props and no railsContext, yet it references both via closure. Make sure the example is intentional and not a copy-paste artefact from a simpler case.
|
|
||
| Plus, you can add your customizations to this. See "rendering extension" below. | ||
|
|
||
| > **RSC Note:** When using React on Rails Pro with RSC, `railsContext` also includes functions like `addPostSSRHook` and `getRSCPayloadStream`. These **cannot** be passed from Server Components to Client Components across the RSC boundary. Strip them before passing: `const { addPostSSRHook, getRSCPayloadStream, ...serializableContext } = railsContext;`. See [RSC Troubleshooting](../migrating/rsc-troubleshooting.md#common-error-railscontext-contains-functions). |
There was a problem hiding this comment.
The destructuring fix hardcodes exactly two function names:
const { addPostSSRHook, getRSCPayloadStream, ...serializableContext } = railsContext;If React on Rails Pro ever adds another non-serializable property to railsContext, this snippet silently becomes incomplete — developers who copy it will still hit the serialization error with the new property, and the doc will give them no hint that more exclusions might be needed.
A defensive alternative (or at least a note alongside the current snippet) would be:
Strip only the functions you know about or, if you never need to forward
railsContextto a Client Component, just don't pass it at all. For a future-proof guard you can filter by type:Object.fromEntries(Object.entries(railsContext).filter(([, v]) => typeof v !== 'function')).
At minimum, consider adding a note that addPostSSRHook / getRSCPayloadStream are the currently known non-serializable keys and that callers should re-check when upgrading Pro.
Review: Docs — RSC migration gapsThe additions address real, silent failure points and the troubleshooting table entries are a welcome improvement. Three issues worth fixing before merge: Must fix
Should fix
Looks good
|
## Summary - Stamp `### [16.5.0.rc.0]` version header with today's date - Add 10 new changelog entries for PRs merged since v16.4.0 - Fix incomplete PR 2818 entry (missing author link) ### New entries added **Added:** - `create-react-on-rails-app --pro` support (PR 2818) - Global prerender env override `REACT_ON_RAILS_PRERENDER_OVERRIDE` (PR 2816) - `react_on_rails:sync_versions` rake task (PR 2797) - Pro/RSC setup checks in `react_on_rails:doctor` (PR 2674) **Changed:** - [Pro] Canonical env var for worker count is now `RENDERER_WORKERS_COUNT` (PR 2611) **Improved:** - Smoother `create-react-on-rails-app` and install generator flows (PR 2650) - Pro upgrade hint after install (PR 2642) **Fixed:** - Preserve runtime env vars across `Bundler.with_unbundled_env` (PR 2836) - Fix doctor prerender check and ExecJS display for Pro/RSC apps (PR 2773) - Fix doctor false positives for custom layouts (PR 2612) ### Skipped PRs (not user-visible) Docs-only: #2845, #2842, #2826, #2830, #2820, #2809, #2803, #2785, #2801, #2791, #2789, #2788, #2772, #2778, #2780, #2784, #2671, #2676, #2662, #2657, #2669 CI/internal tooling: #2825, #2817, #2819, #2812, #2815, #2810, #2808, #2807, #2634, #2798, #2761, #2760, #2658, #2639, #2667, #2656 ## Test plan - [x] Verified version header and diff links are correct - [x] Verified all entries follow changelog formatting conventions - [x] Verified file ends with newline - [ ] After merge, run `rake release` to publish 16.5.0.rc.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Documentation-only change updating `CHANGELOG.md` with a new `16.5.0.rc.0` section and compare links; no runtime code is modified. > > **Overview** > Adds a new `16.5.0.rc.0` (2026-03-25) section to `CHANGELOG.md`, consolidating recent PR entries under **Added/Changed/Improved/Fixed** and correcting the previously incomplete `--pro` CLI entry author attribution. > > Updates the bottom compare links so `[unreleased]` now compares from `v16.5.0.rc.0` and adds a link definition for `[16.5.0.rc.0]`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 481a71c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes - v16.5.0.rc.0 * **New Features** * Added sync_versions task for streamlined version management * Expanded doctor checks for Pro and RSC support * **Improvements** * Enhanced generator workflow and Pro upgrade guidance * Improved environment variable handling and preservation * **Bug Fixes** * Fixed detection issues with doctor tools and ExecJS/prerender functionality <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
…olve-2835 * origin/main: (21 commits) docs: fix profiling node renderer command (#2863) generators: point Pro install fallback to upgrade guide (#2868) Add RSC Flight payload optimization guide (Article 7) (#2827) Migrate from deprecated Async::Variable to Async::Promise (#2832) docs: turn pro quick start into a gateway (#2862) Fix upload-assets endpoint duplicating bundles across directories (#2768) docs: fix stale docs links and help URLs (#2850) docs: replace dead pro.reactonrails.com links (#2851) docs: refresh generator and helper URLs (#2852) Add standalone RSC upgrade guide for existing Pro apps (#2831) Raise docs version floor to 16.4.0 in install/demo guidance (#2610) Fix release script: require changelog, fix RC version computation (#2848) Bump version to 16.5.0 Bump version to 16.5.0.rc.0 Update CHANGELOG.md for 16.5.0.rc.0 (#2847) Docs: add memory leak prevention guide for Node Renderer SSR (#2845) Docs: fix RSC migration gaps found during real-world migration (#2842) Add common mistakes sections to RSC migration guides (#2826) fix: preserve runtime env vars across Bundler.with_unbundled_env (#2836) Skip Pro CI workflows for Dependabot PRs (#2825) ... # Conflicts: # CHANGELOG.md
Summary
Fixes documentation gaps discovered during a real-world RSC migration (HiChee). These caused silent failures that were difficult to debug.
Closes #2841
Changes
rsc-preparing-app.md.jsxfiles inror_components/need'use client', not the compiled.bs.jsfiles. Includes warning about silent misclassification when the directive is missing.Rack::Deflater/Rack::Brotlideadlocks withActionController::Livestreaming. Cross-references the existing streaming SSR docs.rsc-troubleshooting.mdrailsContextincludesaddPostSSRHookandgetRSCPayloadStreamwhich can't cross the RSC boundary. Shows the destructuring fix.render-functions-and-railscontext.mdrailsContextTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit