-
- Notifications
You must be signed in to change notification settings - Fork 638
Add example for returning component from async render function #1829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add example for returning component from async render function #1829
Conversation
make renderer runnable on one process Modify example views to pass props to components and add integration tests for async rendering functionality. Revert "make renderer runnable on one process" This reverts commit 91efa37a665f836b05a116e6548ef809d956a67c. Update Gemfile and package.json to use the master branch of react_on_rails Update component source paths and improve menu link labels for clarity revert changes to react on rails dependency
…nt-side rendering support
WalkthroughAdds two demo pages, routes, components, and tests to showcase async server render functions in React on Rails that either return an HTML string or a React component. Includes client and server files for each example, menu links, and system specs validating server-rendered output and logs. Changes
Sequence Diagram(s)sequenceDiagram autonumber actor U as User Browser participant R as Rails (Pages#async_render_function_returns_string) participant V as View (.erb) participant RoR as ReactOnRails (SSR) participant RF as Async Render Function (returns string) participant RDS as ReactDOMServer U->>R: GET /async_render_function_returns_string R->>V: Render view V->>RoR: react_component(..., prerender: true) RoR->>RF: Call async render(props, railsContext) RF->>RDS: renderToString(<EchoProps {...props} />) RDS-->>RF: HTML string RF-->>RoR: Promise resolves to HTML string RoR-->>V: Inject server HTML V-->>U: Response with SSR HTML note over U,RoR: Client hydration occurs after load sequenceDiagram autonumber actor U as User Browser participant R as Rails (Pages#async_render_function_returns_component) participant V as View (.erb) participant RoR as ReactOnRails (SSR) participant RF as Async Render Function (returns component) U->>R: GET /async_render_function_returns_component R->>V: Render view V->>RoR: react_component(..., prerender: true) RoR->>RF: Call async render(props, railsContext) RF-->>RoR: Promise resolves to React component RoR->>RoR: SSR render of returned component RoR-->>V: Inject server HTML V-->>U: Response with SSR HTML note over U,RoR: Client hydration follows Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code ReviewThank you for adding examples for async render functions. This demonstrates both patterns well (returning components and strings). Strengths
Issues to Address
Performance
SecurityNo issues found - props handled safely StylePer CLAUDE.md: Ensure newlines at file ends and run bundle exec rubocop Good addition overall - addressing these points would make it excellent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx (1)
1-17
: Drop 'use client' in server render-function and fix misleading comment; optionally name returned component.
The server file shouldn’t advertise client-only rendering; naming the returned component improves DevTools traces.Apply:
-'use client'; - -// Top level component for simple client side only rendering +// Server render-function that resolves to a React component import React from 'react'; import EchoProps from '../components/EchoProps'; @@ export default async (props, _railsContext) => { await Promise.resolve(); - return () => <EchoProps {...props} />; + return function AsyncReturnsComponentInner() { + return <EchoProps {...props} />; + }; };react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx (1)
1-4
: Drop the'use client'
directive from this server render exampleThis module is meant to run on the server bundle, so marking it as a client component is misleading and risks confusing toolchains that honor the directive (and might try to tree-shake it into the client build). Let’s remove the directive and update the comment to describe the async server render use case instead.
-'use client'; - -// Top level component for simple client side only rendering +// Async server render function returning an HTML string example
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
react_on_rails_pro/spec/dummy/app/views/pages/async_render_function_returns_component.html.erb
(1 hunks)react_on_rails_pro/spec/dummy/app/views/pages/async_render_function_returns_string.html.erb
(1 hunks)react_on_rails_pro/spec/dummy/app/views/shared/_menu.erb
(1 hunks)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.client.jsx
(1 hunks)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx
(1 hunks)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx
(1 hunks)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx
(1 hunks)react_on_rails_pro/spec/dummy/config/routes.rb
(1 hunks)react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
{Gemfile,Rakefile,**/*.{rb,rake,gemspec,ru}}
📄 CodeRabbit inference engine (CLAUDE.md)
{Gemfile,Rakefile,**/*.{rb,rake,gemspec,ru}}
: Before every commit/push, runbundle exec rubocop
and fix all violations in Ruby code
Let RuboCop handle all Ruby code formatting; never manually format Ruby files
Files:
react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb
react_on_rails_pro/spec/dummy/config/routes.rb
{Gemfile,Rakefile,**/*.{rb,rake,gemspec,ru,js,jsx,ts,tsx,json,yml,yaml,md,css,scss}}
📄 CodeRabbit inference engine (CLAUDE.md)
Ensure all committed files end with a trailing newline character
Files:
react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.client.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx
react_on_rails_pro/spec/dummy/config/routes.rb
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESLint for JavaScript/TypeScript and fix all linter offenses before committing
Files:
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.client.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx
**/*.{js,jsx,ts,tsx,json,yml,yaml,md,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
Let Prettier handle all non-Ruby file formatting; never manually format these files
Files:
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.client.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx
🧠 Learnings (3)
📚 Learning: 2024-07-27T10:08:35.868Z
Learnt from: theforestvn88 PR: shakacode/react_on_rails#1620 File: spec/dummy/client/app/startup/HelloTurboStream.jsx:3-3 Timestamp: 2024-07-27T10:08:35.868Z Learning: The `RailsContext` import in `spec/dummy/client/app/startup/HelloTurboStream.jsx` is used later in the project, as clarified by the user theforestvn88.
Applied to files:
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx
📚 Learning: 2025-02-13T16:50:47.848Z
Learnt from: AbanoubGhadban PR: shakacode/react_on_rails#1644 File: node_package/src/clientStartup.ts:18-21 Timestamp: 2025-02-13T16:50:47.848Z Learning: In the react_on_rails module, the `reactOnRailsPageUnloaded` function in clientStartup.ts is intentionally kept private as it's only used internally as a callback for `onPageUnloaded`.
Applied to files:
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx
📚 Learning: 2025-07-08T05:57:29.630Z
Learnt from: AbanoubGhadban PR: shakacode/react_on_rails#1745 File: node_package/src/RSCRequestTracker.ts:8-14 Timestamp: 2025-07-08T05:57:29.630Z Learning: The global `generateRSCPayload` function in React on Rails Pro (RORP) is provided by the framework during rendering requests, not implemented in application code. The `declare global` statements are used to document the expected interface that RORP will inject at runtime.
Applied to files:
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx
🧬 Code graph analysis (4)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx (3)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.client.jsx (1)
props
(8-8)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx (1)
props
(14-17)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx (1)
props
(17-20)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.client.jsx (2)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx (1)
props
(14-17)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx (1)
props
(8-8)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx (2)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.client.jsx (1)
props
(8-8)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx (1)
props
(17-20)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx (3)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx (1)
props
(14-17)react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ConsoleLogsInAsyncServer.server.jsx (1)
_railsContext
(7-39)node_package/src/ReactDOMServer.cts (1)
renderToString
(4-4)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: dummy-app-integration-tests (3.4, 22)
- GitHub Check: dummy-app-integration-tests (3.2, 20)
- GitHub Check: rspec-package-tests (3.4, minimum)
- GitHub Check: rspec-package-tests (3.4, latest)
- GitHub Check: rspec-package-tests (3.2, latest)
- GitHub Check: rspec-package-tests (3.2, minimum)
- GitHub Check: claude-review
- GitHub Check: build
- GitHub Check: build-and-test
🔇 Additional comments (7)
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.client.jsx (1)
8-8
: LGTM, mirrors the string example and keeps props forwarding simple.
Consistent with other client examples.react_on_rails_pro/spec/dummy/app/views/shared/_menu.erb (1)
58-63
: Menu entries wired correctly to new routes.
Helpers exist and placement matches nearby examples.react_on_rails_pro/spec/dummy/app/views/pages/async_render_function_returns_component.html.erb (1)
6-6
: LGTM: Proper react_component invocation with prerender and trace.
Matches the server render-function returning a component.react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb (1)
220-240
: Solid coverage for both async-return variants.
Assertions mirror existing patterns and should be stable.react_on_rails_pro/spec/dummy/app/views/pages/async_render_function_returns_string.html.erb (1)
6-6
: LGTM: Invokes the string-returning render-function with prerender + trace.
Consistent with component-return example.react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.client.jsx (1)
8-8
: LGTM, consistent with other client-only examples.
Simple props echo for parity with server example.react_on_rails_pro/spec/dummy/config/routes.rb (1)
37-38
: Routes look good.
REST helpers are generated; no conflicts with existing routes.
Summary by CodeRabbit
New Features
Tests
This change is