- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 631
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
[WIP] Add support for RSC #1644
base: master
Are you sure you want to change the base?
Conversation
WalkthroughThe changes introduce extensive enhancements to the React on Rails framework. Major modifications include new methods for streaming React Server Components using fibers, improved error handling, and enhanced Redux store hydration. Key updates span from refactoring internal helper methods and render options to expanding Node package functionalities with asynchronous registration and retrieval of components and stores. Additionally, configuration files, asset/pack utilities, and test suites have been updated to support React 19 features, advanced streaming strategies, and improved lifecycle management. Changes
Possibly related PRs
Suggested reviewers
Poem
Tip CodeRabbit's docstrings feature is now available as part of our Pro Plan! Simply use the command ✨ Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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
Outside diff range, codebase verification and nitpick comments (4)
spec/dummy/config/webpack/alias.js (1)
7-7
: Add a comment explaining the alias mapping.Adding a comment to explain why the
stream
alias is needed would improve maintainability.+ // Alias for stream module to ensure compatibility with browser environments stream: 'stream-browserify'
spec/dummy/config/webpack/webpackConfig.js (1)
7-7
: Add a comment explaining the fallback configuration.Adding a comment to explain why the
stream
fallback is needed would improve maintainability.+ // Fallback configuration for stream module to ensure compatibility with browser environments clientConfig.resolve.fallback = { stream: require.resolve('stream-browserify') };
node_package/src/ReactOnRailsRSC.ts (2)
13-20
: Handle the absence ofAsyncLocalStorage
more robustly.Consider providing more details in the log message or handling the absence of
AsyncLocalStorage
in a way that informs the user of potential limitations.- console.log('AsyncLocalStorage not found'); + console.warn('AsyncLocalStorage not found. Some features may not work as expected.');
29-76
: Ensure comprehensive test coverage forserverRenderRSCReactComponent
.Given the complexity of this function, ensure that it is comprehensively tested, especially for error handling and edge cases.
- No references to
serverRenderRSCReactComponent
were found in the existing test files.Analysis chain
Ensure comprehensive test coverage for
serverRenderRSCReactComponent
.Given the complexity of this function, ensure that it is comprehensively tested, especially for error handling and edge cases.
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify if comprehensive tests are provided for `serverRenderRSCReactComponent`. # Test: Search for test cases related to `serverRenderRSCReactComponent`. Expect: Comprehensive test cases. rg --type javascript --type typescript 'serverRenderRSCReactComponent'Length of output: 105
Script:
#!/bin/bash # Description: Verify if comprehensive tests are provided for `serverRenderRSCReactComponent`. # Test: Search for test cases related to `serverRenderRSCReactComponent`. Expect: Comprehensive test cases. rg --type js --type ts 'serverRenderRSCReactComponent'Length of output: 488
Script:
#!/bin/bash # Description: Verify if comprehensive tests are provided for `serverRenderRSCReactComponent`. # Step 1: Find all test files in the repository. test_files=$(fd --type f --extension js --extension ts --glob '*test*') # Step 2: Search for references to `serverRenderRSCReactComponent` in the identified test files. if [ -n "$test_files" ]; then rg 'serverRenderRSCReactComponent' $test_files else echo "No test files found." fiLength of output: 1289
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files ignored due to path filters (2)
Gemfile.lock
is excluded by!**/*.lock
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
Files selected for processing (11)
- lib/react_on_rails/helper.rb (4 hunks)
- lib/react_on_rails/react_component/render_options.rb (1 hunks)
- lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (1 hunks)
- lib/react_on_rails/utils.rb (2 hunks)
- node_package/src/ReactOnRails.ts (2 hunks)
- node_package/src/ReactOnRailsRSC.ts (1 hunks)
- node_package/src/serverRenderReactComponent.ts (4 hunks)
- node_package/src/types/index.ts (2 hunks)
- package.json (3 hunks)
- spec/dummy/config/webpack/alias.js (1 hunks)
- spec/dummy/config/webpack/webpackConfig.js (1 hunks)
Additional comments not posted (26)
node_package/src/ReactOnRailsRSC.ts (3)
22-27
: LGTM!The
stringToStream
function is correctly implemented.
78-79
: LGTM!The export statements are correctly implemented.
1-4
: Ensure type definitions are added for the modules.The
@ts-expect-error
comments indicate that type definitions are pending. Ensure these are added to avoid type errors.Verification successful
Ensure type definitions are added for the modules.
The
@ts-expect-error
comments indicate that type definitions are pending for therenderToReadableStream
andPassThrough
modules. Ensure these are added to avoid type errors.
node_package/src/ReactOnRailsRSC.ts
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify if type definitions for the modules are added or tracked in the codebase. # Test: Search for type definition files or TODO comments. Expect: Type definitions or tracking comments. rg --type typescript -A 2 '@ts-expect-error'Length of output: 79
Script:
#!/bin/bash # Description: Verify if type definitions for the modules are added or tracked in the codebase. # Test: Search for type definition files or TODO comments. Expect: Type definitions or tracking comments. rg --type-add 'ts:*.ts' -A 2 '@ts-expect-error'Length of output: 883
package.json (5)
23-23
: LGTM!Updating
@types/react
to^18.2.0
ensures better type safety and compatibility with the latest React version.
24-24
: LGTM!Updating
@types/react-dom
to^18.2.0
ensures better type safety and compatibility with the latest React version.
49-49
: LGTM! Verify the usage of the new dependency.Adding
react-server-dom-webpack
enhances server-side rendering capabilities.However, ensure that the new dependency is correctly utilized in the codebase.
Verification successful
Verified Usage of
react-server-dom-webpack
The
react-server-dom-webpack
dependency is correctly utilized in the codebase, specifically innode_package/src/ReactOnRailsRSC.ts
.
node_package/src/ReactOnRailsRSC.ts
: Import and usage ofrenderToReadableStream
fromreact-server-dom-webpack/server.edge
.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the usage of the new dependency in the codebase. # Test: Search for the usage of `react-server-dom-webpack`. Expect: Correct usage of the new dependency. rg --type js -A 5 $'react-server-dom-webpack'Length of output: 44
Script:
#!/bin/bash # Description: Verify the usage of the new dependency in the codebase. # Test: Search for the usage of `react-server-dom-webpack` in all file types. rg -A 5 'react-server-dom-webpack' # Test: Search for import statements that might alias `react-server-dom-webpack`. rg -A 5 'import .* from .*react-server-dom-webpack'Length of output: 1847
5-10
: LGTM! Verify the usage of new entry points.The addition of the
exports
field enhances module interoperability by specifying entry points for both server-side and default usage.However, ensure that the new entry points are correctly utilized in the codebase.
47-48
: LGTM! Verify compatibility with the rest of the codebase.Updating
react
andreact-dom
to18.3.0-canary-670811593-20240322
aligns with modern React practices but ensure compatibility with the rest of the codebase.Verification successful
Verify compatibility with the rest of the codebase.
Updating
react
andreact-dom
to18.3.0-canary-670811593-20240322
aligns with modern React practices but ensure compatibility with the rest of the codebase by checking for deprecated or breaking changes.
Verify compatibility with the rest of the codebase.
Updating
react
andreact-dom
to18.3.0-canary-670811593-20240322
aligns with modern React practices but ensure compatibility with the rest of the codebase by conducting a comprehensive check.
LGTM! Verify compatibility with the rest of the codebase.
Updating
react
andreact-dom
to18.3.0-canary-670811593-20240322
aligns with modern React practices. The search did not reveal any deprecated lifecycle methods or breaking changes. Ensure compatibility with the rest of the codebase by conducting manual verification if necessary.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify compatibility with the rest of the codebase. # Test: Search for the usage of `react` and `react-dom`. Expect: No compatibility issues. rg --type js -A 5 $'react' rg --type js -A 5 $'react-dom'Length of output: 44790
Script:
#!/bin/bash # Description: Verify compatibility with the rest of the codebase for deprecated or breaking changes. # Test: Search for deprecated React lifecycle methods that might be affected by the update. rg --type js -A 5 'componentWillMount|componentWillReceiveProps|componentWillUpdate' # Test: Search for usage of ReactDOM methods that might have breaking changes. rg --type js -A 5 'ReactDOM.render|ReactDOM.hydrate|ReactDOM.createPortal'Length of output: 163
Script:
#!/bin/bash # Description: Verify compatibility with the rest of the codebase for React components and ReactDOM usages. # Test: Search for all React component definitions. rg --type js -A 5 'React.Component|React.PureComponent|function\s+\w+\s*\(' # Test: Search for all ReactDOM usages. rg --type js -A 5 'ReactDOM.render|ReactDOM.hydrate|ReactDOM.createRoot|ReactDOM.hydrateRoot'Length of output: 10621
lib/react_on_rails/react_component/render_options.rb (2)
106-108
: LGTM!The
stream?
method provides a straightforward way to query the:stream?
option.
110-112
: LGTM!The
rsc?
method provides a straightforward way to query the:rsc?
option.node_package/src/types/index.ts (2)
142-142
: LGTM! Verify the implementation of the new method.The
serverRenderRSCReactComponent
method enhances performance and user experience by enabling progressive rendering.However, ensure that the new method is correctly implemented in the codebase.
141-141
: LGTM! Verify the implementation of the new method.The
streamServerRenderedReactComponent
method enhances performance and user experience by enabling progressive rendering.However, ensure that the new method is correctly implemented in the codebase.
Verification successful
The
streamServerRenderedReactComponent
method is correctly implemented.The method is defined in
serverRenderReactComponent.ts
and handles the streaming of server-rendered React components usingReactDOMServer.renderToPipeableStream
. It also includes error handling to manage exceptions during rendering.
- Implementation found in
node_package/src/serverRenderReactComponent.ts
from lines 209 to 249.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the implementation of the new method in the codebase. # Test: Search for the implementation of `streamServerRenderedReactComponent`. Expect: Correct implementation of the new method. rg --type ts -A 5 $'streamServerRenderedReactComponent'Length of output: 2064
Script:
#!/bin/bash # Description: Extract the full implementation of the `streamServerRenderedReactComponent` method. # Test: Retrieve the implementation details of `streamServerRenderedReactComponent`. rg --type ts -A 20 $'export const streamServerRenderedReactComponent = (options: RenderParams) => {'Length of output: 321
Script:
#!/bin/bash # Description: Extract the full implementation of the `streamServerRenderedReactComponent` method. # Test: Retrieve the implementation details of `streamServerRenderedReactComponent`. rg --type ts -A 50 $'export const streamServerRenderedReactComponent = \\(options: RenderParams\\) => {'Length of output: 327
Script:
#!/bin/bash # Description: Extract the full implementation of the `streamServerRenderedReactComponent` method using ast-grep. # Test: Retrieve the implementation details of `streamServerRenderedReactComponent`. ast-grep --lang typescript --pattern $'export const streamServerRenderedReactComponent = (options: RenderParams) => { $$$ }'Length of output: 3488
node_package/src/serverRenderReactComponent.ts (3)
1-2
: Update import statements forReact
andPipeableStream
.The import of
React
andPipeableStream
fromreact-dom/server
aligns with the new stream-based rendering approach.
74-101
: Implement stream-based rendering usingrenderToPipeableStream
.The new implementation uses
renderToPipeableStream
for stream-based rendering. This approach enhances performance and allows for asynchronous processing of the rendered output. Ensure that the stream is correctly handled and errors are properly managed.
209-249
: IntroducestreamServerRenderedReactComponent
function.The new function encapsulates the logic for rendering a React component into a stream. It checks for conditions and handles errors appropriately. This addition enhances the server-side rendering capabilities by supporting stream-based rendering.
lib/react_on_rails/utils.rb (3)
Line range hint
69-92
:
Redefinebundle_js_file_path
method.The method now includes a new parameter
bundle_name
, allowing it to handle different bundle names dynamically. This change enhances the flexibility and robustness of the method.
96-110
: Updateserver_bundle_js_file_path
method.The method now uses the new
bundle_js_file_path
method, aligning with the new structure for managing bundle paths. This update enhances maintainability and clarity.
112-117
: Introducersc_bundle_js_file_path
method.The new method handles the RSC bundle path, following the same pattern as the
server_bundle_js_file_path
method. This addition improves the modularity and configurability of the code.lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (1)
95-99
: Introduceexec_server_render_streaming_js
method.The new method handles JavaScript code execution in a streaming manner. It accepts three parameters:
js_code
,render_options
, and an optionaljs_evaluator
. This addition expands the capabilities of the module by allowing for streaming JavaScript execution.node_package/src/ReactOnRails.ts (2)
245-251
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
streamServerRenderedReactComponent
are correctly implemented.
253-260
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that the function
serverRenderRSCReactComponent
is not mistakenly invoked in the wrong context.Verification successful
The function
serverRenderRSCReactComponent
is not mistakenly invoked in the wrong context.
- The function is defined in
node_package/src/ReactOnRails.ts
and throws an error if invoked.- It is referenced in
node_package/src/ReactOnRailsRSC.ts
andnode_package/src/types/index.ts
, but no invocations were found outside these contexts.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all function calls to `serverRenderRSCReactComponent` are correctly implemented. # Test: Search for the function usage. Expect: Correct implementation of the function calls. rg --type ts -A 5 $'serverRenderRSCReactComponent'Length of output: 1445
Script:
#!/bin/bash # Description: Verify the context of the function usage in `node_package/src/ReactOnRailsRSC.ts` and `node_package/src/types/index.ts`. # Search for the function usage in `node_package/src/ReactOnRailsRSC.ts` with more context lines. rg --type ts -A 10 -B 10 $'serverRenderRSCReactComponent' node_package/src/ReactOnRailsRSC.ts # Search for the function usage in `node_package/src/types/index.ts` with more context lines. rg --type ts -A 10 -B 10 $'serverRenderRSCReactComponent' node_package/src/types/index.tsLength of output: 1701
Script:
#!/bin/bash # Description: Verify that `serverRenderRSCReactComponent` is not mistakenly invoked outside the intended context. # Search for invocations of `serverRenderRSCReactComponent` across the codebase. rg --type ts $'serverRenderRSCReactComponent('Length of output: 158
Script:
#!/bin/bash # Description: Verify that `serverRenderRSCReactComponent` is not mistakenly invoked outside the intended context. # Search for invocations of `serverRenderRSCReactComponent` across the codebase with corrected regex pattern. rg --type ts 'serverRenderRSCReactComponent\('Length of output: 252
lib/react_on_rails/helper.rb (5)
480-484
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
internal_rsc_react_component
are correctly implemented.
113-121
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
stream_react_component_async
are correctly implemented.
103-111
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
stream_react_component
are correctly implemented.Verification successful
Verified: The function usage of
stream_react_component
is correctly implemented.The only usage of
stream_react_component
is within thestream_react_component_async
method, and it is used appropriately in an asynchronous context.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all function calls to `stream_react_component` are correctly implemented. # Test: Search for the function usage. Expect: Correct implementation of the function calls. rg --type ruby -A 5 $'stream_react_component'Length of output: 1048
Script:
#!/bin/bash # Description: Verify all function calls to `stream_react_component` are correctly implemented across the entire codebase. # Test: Search for the function usage. Expect: Correct implementation of the function calls. rg --type ruby 'stream_react_component'Length of output: 319
94-101
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
rsc_react_component
are correctly implemented.
393-417
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
build_react_component_result_for_server_streamed_content
are correctly implemented.Verification successful
Verify the function call context in the codebase.
The function
build_react_component_result_for_server_streamed_content
is called within the same file where it is defined. Ensure that the parametersresult[:result]
,result[:tag]
, andresult[:render_options]
are correctly defined and passed in the calling context.
Verify the function call context in the codebase.
The previous script failed due to a regex parse error. Let's correct the search pattern and re-run the script to verify the context of the function call to
build_react_component_result_for_server_streamed_content
.
Verify the return value of the
internal_react_component
method.The function call to
build_react_component_result_for_server_streamed_content
is found within thestream_react_component
method. We need to verify theinternal_react_component
method to ensure that it returns a hash with the keys:result
,:tag
, and:render_options
.
Verify the complete implementation of the
internal_react_component
method.We need to see the full implementation of the
internal_react_component
method to confirm if it returns a hash with the keys:result
,:tag
, and:render_options
.
Function usage verified successfully.
The function
build_react_component_result_for_server_streamed_content
is correctly implemented and called within the codebase. Theinternal_react_component
method returns a hash with the keys:render_options
,:tag
, and:result
, ensuring that the parameters passed tobuild_react_component_result_for_server_streamed_content
are correctly defined.
stream_react_component
method callsinternal_react_component
, which returns the necessary keys.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all function calls to `build_react_component_result_for_server_streamed_content` are correctly implemented. # Test: Search for the function usage. Expect: Correct implementation of the function calls. rg --type ruby -A 5 $'build_react_component_result_for_server_streamed_content'Length of output: 994
Script:
#!/bin/bash # Description: Verify the context of the function call to `build_react_component_result_for_server_streamed_content` to ensure the parameters are correctly defined and passed. # Search for the context around the function call to examine the definition of `result`. rg --type ruby -A 10 -B 10 $'build_react_component_result_for_server_streamed_content('Length of output: 253
Script:
#!/bin/bash # Description: Verify the context of the function call to `build_react_component_result_for_server_streamed_content` to ensure the parameters are correctly defined and passed. # Search for the context around the function call to examine the definition of `result`. rg --type ruby -A 10 -B 10 $'build_react_component_result_for_server_streamed_content\('Length of output: 3034
Script:
#!/bin/bash # Description: Verify the return value of the `internal_react_component` method to ensure it returns a hash with the keys `:result`, `:tag`, and `:render_options`. # Search for the definition of the `internal_react_component` method. rg --type ruby -A 10 $'def internal_react_component'Length of output: 989
Script:
#!/bin/bash # Description: Retrieve the complete implementation of the `internal_react_component` method. # Search for the complete implementation of the `internal_react_component` method. rg --type ruby -A 50 -B 10 $'def internal_react_component'Length of output: 4813
4e3ad5b
to
440511d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Outside diff range, codebase verification and nitpick comments (2)
node_package/src/ReactOnRails.ts (1)
253-260
: LGTM! Consider adding a more descriptive error message.The implementation looks good. Consider providing more context in the error message to help developers understand why this method is not supported.
- throw new Error('serverRenderRSCReactComponent is supported in RSC bundle only.'); + throw new Error('serverRenderRSCReactComponent is supported in RSC bundle only. Ensure you are using the correct bundle for React Server Components.');CHANGELOG.md (1)
8-8
: Format bare URL as a proper link.Bare URLs should be formatted as proper links in markdown files.
- If you need help upgrading `react_on_rails`, `webpacker` to `shakapacker`, or JS packages, contact justin@shakacode.com. + If you need help upgrading `react_on_rails`, `webpacker` to `shakapacker`, or JS packages, contact [justin@shakacode.com](mailto:justin@shakacode.com).Tools
Markdownlint
8-8: null
Bare URL used(MD034, no-bare-urls)
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files ignored due to path filters (2)
Gemfile.lock
is excluded by!**/*.lock
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
Files selected for processing (12)
- CHANGELOG.md (2 hunks)
- lib/react_on_rails/helper.rb (5 hunks)
- lib/react_on_rails/react_component/render_options.rb (1 hunks)
- lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (1 hunks)
- lib/react_on_rails/utils.rb (2 hunks)
- node_package/src/ReactOnRails.ts (2 hunks)
- node_package/src/ReactOnRailsRSC.ts (1 hunks)
- node_package/src/serverRenderReactComponent.ts (4 hunks)
- node_package/src/types/index.ts (2 hunks)
- package.json (3 hunks)
- spec/dummy/config/webpack/alias.js (1 hunks)
- spec/dummy/config/webpack/webpackConfig.js (1 hunks)
Additional context used
Markdownlint
CHANGELOG.md
8-8: null
Bare URL used(MD034, no-bare-urls)
Additional comments not posted (32)
spec/dummy/config/webpack/alias.js (1)
7-7
: Alias addition forstream
module looks good.The alias for
stream
module mapping tostream-browserify
enhances module resolution for browser environments.spec/dummy/config/webpack/webpackConfig.js (1)
7-7
: Fallback configuration forstream
module looks good.The fallback configuration for
stream
module usingstream-browserify
ensures compatibility for environments where the nativestream
module may not be available.node_package/src/ReactOnRailsRSC.ts (5)
1-12
: Import statements look good.The import statements bring in necessary modules and types for the functionalities being introduced.
13-20
: Async function for settingAsyncLocalStorage
looks good.The function attempts to set
AsyncLocalStorage
in the global scope and handles its absence gracefully.
22-27
:stringToStream
function looks good.The function correctly converts a string to a stream using
PassThrough
.
29-37
:getBundleConfig
function looks good.The function correctly reads the JSON file and processes its keys to remove the
file://
prefix.
88-89
: Export statements look good.The export statements appropriately export types and the default
ReactOnRails
object.package.json (2)
5-10
: LGTM! Theexports
field enhances module compatibility.The addition of the
exports
field provides more granular control over how the module is imported in different environments. Ensure that the paths toReactOnRailsRSC.js
andReactOnRails.js
are correct.
23-24
: Approve dependency updates but verify compatibility.The updates to
@types/react
,@types/react-dom
,react
,react-dom
, and the addition ofreact-server-dom-webpack
are approved. Ensure that these updates are compatible with the rest of the codebase and do not introduce breaking changes.Also applies to: 47-49
lib/react_on_rails/react_component/render_options.rb (1)
106-113
: LGTM! The new methodsstream?
andrsc?
are well integrated.The methods correctly retrieve the options from the
options
hash. Ensure that these options are set correctly in the codebase.node_package/src/types/index.ts (1)
2-2
: LGTM! The new methodsstreamServerRenderedReactComponent
andserverRenderRSCReactComponent
are well defined.The methods are correctly integrated into the
ReactOnRails
interface. Ensure that these methods are implemented correctly in the codebase.Also applies to: 141-142
node_package/src/serverRenderReactComponent.ts (4)
1-3
: Imports look good.The new imports
ReactDOMServer
andPassThrough
are necessary for the new streaming rendering approach.
202-207
: Function looks good.The
stringToStream
function correctly converts a string to a stream.
209-248
: Function looks good.The
streamServerRenderedReactComponent
function correctly manages the rendering process and handles errors using the new streaming rendering approach.However, ensure the new function is used correctly throughout the codebase.
Verification successful
Function looks good.
The
streamServerRenderedReactComponent
function correctly manages the rendering process and handles errors using the new streaming rendering approach.However, ensure the new function is used correctly throughout the codebase.
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the usage of the new function. # Test: Search for the function usage. Expect: Correct usage of `streamServerRenderedReactComponent`. rg --type ts -A 5 $'streamServerRenderedReactComponent'Length of output: 2064
74-101
: New rendering approach looks good.The use of
renderToPipeableStream
improves performance by streaming the rendered output. The function handles different rendering results and includes error handling.However, ensure the new function is used correctly throughout the codebase.
lib/react_on_rails/utils.rb (3)
Line range hint
69-95
:
Method looks good.The
bundle_js_file_path
method has been renamed and modified to handle different bundle names dynamically. The error handling and default path construction are correct.
96-110
: Method looks good.The
server_bundle_js_file_path
method has been modified to use the newbundle_js_file_path
method, improving maintainability.
112-117
: Method looks good.The new
rsc_bundle_js_file_path
method improves configurability by managing the retrieval of a resource bundle path.lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (1)
95-99
: Method looks good.The new
exec_server_render_streaming_js
method enhances functionality by providing an alternative for JavaScript execution with streaming capabilities.node_package/src/ReactOnRails.ts (1)
245-251
: LGTM! Verify the correct usage ofRenderParams
andstreamServerRenderedReactComponent
.The implementation looks good. Ensure that
RenderParams
andstreamServerRenderedReactComponent
are correctly defined and imported.Verification successful
Verified: The
RenderParams
andstreamServerRenderedReactComponent
are correctly defined and imported.
RenderParams
is defined innode_package/src/types/index.ts
.streamServerRenderedReactComponent
is defined innode_package/src/serverRenderReactComponent.ts
and imported innode_package/src/ReactOnRails.ts
.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the correct usage of `RenderParams` and `streamServerRenderedReactComponent`. # Test: Search for the definitions of `RenderParams` and `streamServerRenderedReactComponent`. Expect: Correct definitions and imports. rg --type typescript -A 5 $'RenderParams' rg --type typescript -A 5 $'streamServerRenderedReactComponent'Length of output: 173
Script:
#!/bin/bash # Description: Verify the correct usage of `RenderParams` and `streamServerRenderedReactComponent`. # Test: Search for the definitions of `RenderParams` and `streamServerRenderedReactComponent`. Expect: Correct definitions and imports. rg -A 5 'RenderParams' rg -A 5 'streamServerRenderedReactComponent'Length of output: 7052
lib/react_on_rails/helper.rb (5)
115-123
: LGTM! Verify the correct usage ofstream_react_component
andFiber
.The implementation looks good. Ensure that
stream_react_component
is correctly defined and that theFiber
usage is appropriate.Verification successful
LGTM!
The implementation of
stream_react_component_async
and the usage ofstream_react_component
andFiber
are correct and consistent.
stream_react_component
is correctly defined and used withinstream_react_component_async
.- The
Fiber
usage is appropriate for yielding chunks of data asynchronously.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the correct usage of `stream_react_component` and `Fiber`. # Test: Search for the definition of `stream_react_component`. Expect: Correct definition and usage. rg --type ruby -A 5 $'def stream_react_component' # Test: Check for the usage of `Fiber`. Expect: Appropriate usage. rg --type ruby -A 5 $'Fiber'Length of output: 2275
94-103
: LGTM! Verify the correct usage ofinternal_rsc_react_component
andFiber
.The implementation looks good. Ensure that
internal_rsc_react_component
is correctly defined and that theFiber
usage is appropriate.Verification successful
LGTM! The implementation of
rsc_react_component
is correct.
- The
internal_rsc_react_component
method is correctly defined and used.- The
Fiber
usage is appropriate and consistent.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the correct usage of `internal_rsc_react_component` and `Fiber`. # Test: Search for the definition of `internal_rsc_react_component`. Expect: Correct definition and usage. rg --type ruby -A 5 $'def internal_rsc_react_component' # Test: Check for the usage of `Fiber`. Expect: Appropriate usage. rg --type ruby -A 5 $'Fiber'Length of output: 1924
105-113
: LGTM! Verify the correct usage ofinternal_react_component
and options modification.The implementation looks good. Ensure that
internal_react_component
is correctly defined and that the options are appropriately modified for streaming.
396-420
: LGTM! Verify the correct transformation logic.The implementation looks good. Ensure that the transformation logic for the rendered HTML stream is correctly implemented.
Verification successful
Verified: The transformation logic for the rendered HTML stream in the method
build_react_component_result_for_server_streamed_content
is correctly implemented.
- The first chunk includes the necessary hydration tags.
- The subsequent chunks are correctly processed.
- The final transformation ensures the HTML is marked as safe.
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the correct transformation logic for the rendered HTML stream. # Test: Search for the transformation logic in `build_react_component_result_for_server_streamed_content`. Expect: Correct implementation. rg --type ruby -A 10 $'def build_react_component_result_for_server_streamed_content'Length of output: 1107
Script:
#!/bin/bash # Description: Retrieve the complete implementation of the method `build_react_component_result_for_server_streamed_content`. # Search for the complete implementation of the method `build_react_component_result_for_server_streamed_content` in the Ruby file. rg --type ruby -A 20 $'def build_react_component_result_for_server_streamed_content'Length of output: 1744
Script:
#!/bin/bash # Description: Retrieve the complete implementation of the method `build_react_component_result_for_server_streamed_content`. # Search for the complete implementation of the method `build_react_component_result_for_server_streamed_content` in the Ruby file. rg --type ruby -A 30 $'def build_react_component_result_for_server_streamed_content'Length of output: 2428
483-487
: LGTM! Verify the correct usage ofserver_rendered_react_component
and thersc
option.The implementation looks good. Ensure that
server_rendered_react_component
is correctly defined and that thersc
option is appropriately handled.Verification successful
LGTM! The
server_rendered_react_component
method is correctly defined, and thersc
option is appropriately handled.
- The
server_rendered_react_component
method includes logic for server-side rendering and error management.- The
rsc
option is set and checked within the rendering process, ensuring it is handled correctly.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the correct usage of `server_rendered_react_component` and the `rsc` option. # Test: Search for the definition of `server_rendered_react_component`. Expect: Correct definition and usage. rg --type ruby -A 5 $'def server_rendered_react_component' # Test: Check for the handling of the `rsc` option. Expect: Appropriate handling. rg --type ruby -A 5 $'options = options.merge(rsc?: true)'Length of output: 542
Script:
#!/bin/bash # Description: Gather full implementation of `server_rendered_react_component` and check for `rsc` option handling. # Get the full implementation of `server_rendered_react_component` rg --type ruby -A 20 $'def server_rendered_react_component' lib/react_on_rails/helper.rb # Search for any usage of `rsc` option in the codebase rg --type ruby 'rsc?: true'Length of output: 1348
Script:
#!/bin/bash # Description: Gather complete implementation of `server_rendered_react_component` and check for `rsc` option handling within `lib/react_on_rails/helper.rb`. # Get the complete implementation of `server_rendered_react_component` rg --type ruby -A 50 $'def server_rendered_react_component' lib/react_on_rails/helper.rb # Search for any references to `rsc` within `lib/react_on_rails/helper.rb` rg --type ruby 'rsc' lib/react_on_rails/helper.rbLength of output: 3052
CHANGELOG.md (7)
9-9
: LGTM!The link is properly formatted.
10-10
: LGTM!The link is properly formatted.
20-20
: LGTM!The new version entry is properly formatted.
21-21
: LGTM!The new section header is properly formatted.
22-22
: LGTM!The new entry under the "Fixed" section is properly formatted.
1131-1131
: LGTM!The link to the "Unreleased" comparison is properly formatted.
1132-1132
: LGTM!The link to the
[14.0.1]
comparison is properly formatted.
440511d
to
1c026a7
Compare
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.
Caution
Inline review comments failed to post
Actionable comments posted: 1
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
Files selected for processing (16)
- .gitignore (1 hunks)
- jest.config.js (1 hunks)
- lib/react_on_rails/helper.rb (5 hunks)
- lib/react_on_rails/react_component/render_options.rb (1 hunks)
- lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (1 hunks)
- lib/react_on_rails/utils.rb (3 hunks)
- node_package/src/ReactOnRails.ts (2 hunks)
- node_package/src/ReactOnRailsRSC.ts (1 hunks)
- node_package/src/serverRenderReactComponent.ts (2 hunks)
- node_package/src/types/index.ts (2 hunks)
- node_package/tests/ReactOnRails.test.js (1 hunks)
- node_package/tests/jest.setup.js (1 hunks)
- package.json (3 hunks)
- spec/dummy/config/webpack/alias.js (1 hunks)
- spec/dummy/config/webpack/commonWebpackConfig.js (1 hunks)
- spec/dummy/config/webpack/webpackConfig.js (1 hunks)
Files skipped from review due to trivial changes (2)
- .gitignore
- spec/dummy/config/webpack/alias.js
Files skipped from review as they are similar to previous changes (7)
- lib/react_on_rails/helper.rb
- lib/react_on_rails/react_component/render_options.rb
- lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
- node_package/src/ReactOnRailsRSC.ts
- node_package/src/types/index.ts
- package.json
- spec/dummy/config/webpack/webpackConfig.js
Additional comments not posted (14)
jest.config.js (1)
4-4
: Ensure the setup script exists and is correctly placed.The
setupFiles
option specifies a setup script located at<rootDir>/node_package/tests/jest.setup.js
. Verify that this file exists and is correctly configured.Verification successful
The setup script
node_package/tests/jest.setup.js
exists and is correctly configured.
- The script contains necessary polyfills for
TextEncoder
andTextDecoder
in the jsdom environment, ensuring Jest tests run smoothly.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify that the setup script exists at the specified location. # Test: Check if the file exists. Expect: The file should exist. if [ ! -f "node_package/tests/jest.setup.js" ]; then echo "Error: The setup script node_package/tests/jest.setup.js does not exist." exit 1 fi echo "The setup script node_package/tests/jest.setup.js exists."Length of output: 174
Script:
#!/bin/bash # Description: Output the contents of the jest.setup.js file to verify its configuration. # Display the contents of the setup script cat node_package/tests/jest.setup.jsLength of output: 672
node_package/tests/jest.setup.js (1)
1-13
: Ensure polyfills do not conflict with existing definitions.The polyfills for
TextEncoder
andTextDecoder
are necessary for environments where they are not defined. Ensure that these polyfills do not conflict with any existing definitions.Verification successful
No conflicting definitions of
TextEncoder
andTextDecoder
found.The verification process confirms that there are no existing definitions or imports of
TextEncoder
andTextDecoder
in the codebase. The polyfills innode_package/tests/jest.setup.js
do not conflict with any existing definitions.
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify that the polyfills for TextEncoder and TextDecoder do not conflict with existing definitions. # Test: Check if TextEncoder and TextDecoder are already defined in the global scope. Expect: They should not be defined. node -e "if (typeof global.TextEncoder !== 'undefined' || typeof global.TextDecoder !== 'undefined') { console.error('Error: TextEncoder or TextDecoder is already defined.'); process.exit(1); } else { console.log('TextEncoder and TextDecoder are not defined.'); }"Length of output: 362
Script:
#!/bin/bash # Search for any definitions or imports of TextEncoder and TextDecoder in the codebase ast-grep --lang javascript --pattern 'const TextEncoder = $_;' ast-grep --lang javascript --pattern 'const TextDecoder = $_;' ast-grep --lang javascript --pattern 'import { TextEncoder } from $_;' ast-grep --lang javascript --pattern 'import { TextDecoder } from $_;'Length of output: 1183
Script:
#!/bin/bash # Corrected ast-grep patterns for searching definitions or imports of TextEncoder and TextDecoder in the codebase ast-grep --lang javascript --pattern 'const TextEncoder = $_;' ast-grep --lang javascript --pattern 'const TextDecoder = $_;' ast-grep --lang javascript --pattern 'import { TextEncoder } from "$_";' ast-grep --lang javascript --pattern 'import { TextDecoder } from "$_";' # Fallback to rg for searching definitions or imports of TextEncoder and TextDecoder in the codebase rg 'const TextEncoder' --context 5 rg 'const TextDecoder' --context 5 rg 'import { TextEncoder' --context 5 rg 'import { TextDecoder' --context 5Length of output: 657
Script:
#!/bin/bash # Corrected rg patterns for searching definitions or imports of TextEncoder and TextDecoder in the codebase rg 'const TextEncoder' --context 5 rg 'const TextDecoder' --context 5 rg 'import \{ TextEncoder' --context 5 rg 'import \{ TextDecoder' --context 5Length of output: 155
spec/dummy/config/webpack/commonWebpackConfig.js (1)
44-44
: Ensure compatibility with the newprocess
configuration.The addition of
process: 'process/browser'
in theProvidePlugin
configuration is intended to improve compatibility with certain libraries. Verify that this change does not introduce any conflicts or issues.Verification successful
Verification successful: The new
process
configuration does not introduce any conflicts or issues.The addition of
process: 'process/browser'
in theProvidePlugin
configuration is intended to provide a polyfill for theprocess
object in the browser environment. The search results indicate that theprocess
object is used primarily for setting and checking environment variables, which should not be affected by this change.
spec/dummy/babel.config.js
spec/dummy/config/webpack/webpackConfig.js
spec/dummy/config/webpack/test.js
spec/dummy/config/webpack/production.js
spec/dummy/config/webpack/development.js
spec/dummy/config/webpack/commonWebpackConfig.js
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify that the new process configuration does not introduce any conflicts or issues. # Test: Check if the process object is available globally in the browser environment. Expect: The process object should be defined. node -e "const webpack = require('webpack'); const config = require('./spec/dummy/config/webpack/commonWebpackConfig.js')(); webpack(config, (err, stats) => { if (err || stats.hasErrors()) { console.error('Error: Webpack compilation failed.'); process.exit(1); } else { console.log('Webpack compilation succeeded.'); } });"Length of output: 421
Script:
#!/bin/bash # Description: Search for the usage of the `process` object in the codebase to identify potential issues or conflicts. # Search for the usage of `process` in JavaScript files rg 'process' --glob '*.js' -A 3Length of output: 2474
node_package/tests/ReactOnRails.test.js (1)
22-30
: LGTM! Improved test clarity by directly manipulating the DOM.The changes enhance the clarity of the test by directly manipulating the DOM and checking the visible output rather than relying on internal component details.
node_package/src/serverRenderReactComponent.ts (4)
2-2
: LGTM! New import forPassThrough
stream.The
PassThrough
stream from thestream
module is correctly imported for use in the new rendering approach.
170-175
: LGTM! New functionstringToStream
correctly implemented.The function converts a string to a stream using
PassThrough
, which is useful for converting error messages to streams.
177-219
: LGTM! Enhanced server-side rendering withrenderToPipeableStream
.The new function
streamServerRenderedReactComponent
enhances server-side rendering by allowing for more efficient streaming of rendered output. Error handling and logging are appropriately implemented.
219-220
: LGTM! Correct return statement forrenderResult
.The return statement correctly returns the
renderResult
stream.lib/react_on_rails/utils.rb (3)
Line range hint
69-97
:
LGTM! Enhanced flexibility withbundle_js_file_path
.The new method
bundle_js_file_path
enhances the flexibility of the bundle path retrieval process by allowing it to handle different bundle names dynamically.
98-112
: LGTM! Streamlined logic withbundle_js_file_path
.The method
server_bundle_js_file_path
has been updated to use the newbundle_js_file_path
method, streamlining the logic for retrieving the server bundle path.
114-119
: LGTM! New methodrsc_bundle_js_file_path
enhances configurability.The new method
rsc_bundle_js_file_path
enhances configurability by allowing the retrieval of a resource bundle path, with a default bundle name for the development environment.node_package/src/ReactOnRails.ts (3)
262-264
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
handleError
are correctly implemented.Verification successful
All usages of
handleError
are correctly implemented.The function
handleError
is consistently used across the codebase, and no issues were found.
serverRenderReactComponent.ts
: Multiple valid usages.ReactOnRails.ts
: Valid usage.handleError.ts
: Proper definition and export.Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all function calls to `handleError` are correctly implemented. # Test: Search for the function usage. Expect: Only valid occurrences. rg --type python -A 5 $'handleError'Length of output: 66
Script:
#!/bin/bash # Description: Verify all function calls to `handleError` are correctly implemented. # Test: Search for the function usage. Expect: Only valid occurrences. rg --type ts -A 5 $'handleError'Length of output: 3682
258-260
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
serverRenderRSCReactComponent
are correctly implemented.Verification successful
Function usage verified.
The function
serverRenderRSCReactComponent
is correctly implemented and used only in the appropriate context.
- Definition and error throwing:
node_package/src/ReactOnRails.ts
- Implementation for RSC bundle:
node_package/src/ReactOnRailsRSC.ts
- Type declaration:
node_package/src/types/index.ts
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all function calls to `serverRenderRSCReactComponent` are correctly implemented. # Test: Search for the function usage. Expect: Only valid occurrences. rg --type python -A 5 $'serverRenderRSCReactComponent'Length of output: 84
Script:
#!/bin/bash # Description: Verify all function calls to `serverRenderRSCReactComponent` are correctly implemented. # Test: Search for the function usage. Expect: Only valid occurrences. rg --type ts -A 5 $'serverRenderRSCReactComponent'Length of output: 1445
249-251
: LGTM! Verify the function usage in the codebase.The code changes are approved.
However, ensure that all function calls to
streamServerRenderedReactComponent
are correctly implemented.Verification successful
Verification Successful: Function usage is correct.
The
streamServerRenderedReactComponent
function is correctly implemented and used within the codebase.
- Definition:
node_package/src/serverRenderReactComponent.ts
- Usage:
node_package/src/ReactOnRails.ts
- Type Declaration:
node_package/src/types/index.ts
Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify all function calls to `streamServerRenderedReactComponent` are correctly implemented. # Test: Search for the function usage. Expect: Only valid occurrences. rg --type python -A 5 $'streamServerRenderedReactComponent'Length of output: 89
Script:
#!/bin/bash # Description: Verify all function calls to `streamServerRenderedReactComponent` are correctly implemented. # Test: Search for the function usage. Expect: Only valid occurrences. rg --type ts -A 5 $'streamServerRenderedReactComponent'Length of output: 2038
Comments failed to post (1)
node_package/src/serverRenderReactComponent.ts
205-207: Reminder: Add console replay script to the stream.
The TODO comment indicates that the console replay script needs to be added to the stream to avoid console messages leaking between different components rendering.
Do you want me to generate the code for adding the console replay script to the stream or open a GitHub issue to track this task?
1c026a7
to
40c89e4
Compare
f38ed50
to
0c2313e
Compare
d5d5d68
to
8937c5f
Compare
40c89e4
to
d437954
Compare
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: 9
🧹 Outside diff range and nitpick comments (9)
lib/react_on_rails/react_component/render_options.rb (2)
118-120
: Consider adding configuration fallback for consistency.For consistency with other options like
stream?
, consider adding a configuration fallback using theretrieve_configuration_value_for
pattern. This would allow setting a default RSC behavior in the global configuration.Here's a suggested implementation:
def rsc? - options[:rsc?] + retrieve_configuration_value_for(:rsc?) end
118-120
: Add documentation for the RSC feature.Since this is part of adding React Server Components support, it would be helpful to add documentation explaining:
- The purpose of the RSC option
- How it interacts with other rendering options (especially
stream?
)- Any requirements or constraints when using RSC
Add RDoc documentation above the method:
+# Returns whether React Server Components (RSC) rendering is enabled. +# @return [Boolean] true if RSC rendering is enabled, false otherwise def rsc? options[:rsc?] endnode_package/src/types/index.ts (1)
174-174
: Add JSDoc documentation and consider RSC-specific typesWhile the method signature is correct, consider these improvements:
Add JSDoc documentation explaining:
- The RSC-specific behavior and constraints
- How it differs from
streamServerRenderedReactComponent
- Error handling approach
Consider creating an RSC-specific params type:
interface RSCRenderParams extends RenderParams { // Add any RSC-specific options rscMode?: boolean; // ... other RSC-specific fields }lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (3)
Line range hint
59-63
: Document RSC implementation detailsWhile the code structure for RSC support is clean, please add documentation explaining:
- The RSC implementation approach
- How
eval_streaming_js
handles RSC differently from regular streaming- Any specific requirements or limitations of RSC support
79-82
: Improve readability of conditional returnThe current line is too long and complex. Consider refactoring for better readability:
- return parse_result_and_replay_console_messages(result, render_options) unless render_options.stream? || render_options.rsc? + if render_options.stream? || render_options.rsc? + # Streamed component is returned as stream of strings. + # We need to parse each chunk and replay the console messages. + result.transform { |chunk| parse_result_and_replay_console_messages(chunk, render_options) } + else + parse_result_and_replay_console_messages(result, render_options) + end🧰 Tools
🪛 rubocop
[convention] 79-79: Modifier form of
unless
makes the line too long.(Style/IfUnlessModifier)
[convention] 79-79: Line is too long. [134/120]
(Layout/LineLength)
Line range hint
59-82
: Consider RSC architectural implicationsThe RSC implementation touches core rendering functionality. Please consider:
- Performance implications of RSC vs traditional SSR
- Memory usage with streaming and RSC
- Error boundaries and fallback strategies
- Client/server boundary management
- Caching strategies for RSC components
Would you like assistance in implementing any of these architectural considerations?
🧰 Tools
🪛 rubocop
[convention] 79-79: Modifier form of
unless
makes the line too long.(Style/IfUnlessModifier)
[convention] 79-79: Line is too long. [134/120]
(Layout/LineLength)
node_package/src/ReactOnRailsRSC.ts (2)
1-1
: Remove unused import ofReactElement
.The
ReactElement
type imported from'react'
is not used in this file. Unused imports can clutter the code and should be removed to improve readability.Apply this diff to remove the unused import:
-import type { ReactElement } from 'react';
🧰 Tools
🪛 eslint
[error] 1-1: 'ReactElement' is defined but never used.
(@typescript-eslint/no-unused-vars)
82-88
: Handle error types safely when constructing error messages.In the
catch
block,e
is of typeunknown
. Interpolating it directly into a string may result in"[object Object]"
or other unintended outputs.Apply this diff to safely convert
e
to a string:renderResult = stringToStream(`Error: ${e}`); +// Ensure the error is converted to a meaningful string +const errorMessage = e instanceof Error ? e.message : String(e); +renderResult = stringToStream(`Error: ${errorMessage}`);This ensures that the error message is meaningful and avoids potential issues when
e
is not a string.lib/react_on_rails/utils.rb (1)
114-120
: Makebundle_name
configurable inrsc_bundle_js_file_path
The
rsc_bundle_js_file_path
method currently uses a hardcodedbundle_name
("rsc-bundle.js"
). Making this value configurable would enhance flexibility, allowing users to specify custom bundle names for React Server Components.Would you like assistance in implementing a configuration option for the
rsc_bundle_js_file_path
method?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (2)
Gemfile.lock
is excluded by!**/*.lock
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (8)
lib/react_on_rails/helper.rb
(4 hunks)lib/react_on_rails/react_component/render_options.rb
(1 hunks)lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
(3 hunks)lib/react_on_rails/utils.rb
(2 hunks)node_package/src/ReactOnRails.ts
(2 hunks)node_package/src/ReactOnRailsRSC.ts
(1 hunks)node_package/src/types/index.ts
(2 hunks)package.json
(2 hunks)
🧰 Additional context used
🪛 rubocop
lib/react_on_rails/helper.rb
[convention] 153-159: Redundant assignment before returning detected.
(Style/RedundantAssignment)
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
[convention] 79-79: Modifier form of unless
makes the line too long.
(Style/IfUnlessModifier)
[convention] 79-79: Line is too long. [134/120]
(Layout/LineLength)
[warning] 233-233: Remove debugger entry point binding.pry
.
(Lint/Debugger)
🪛 eslint
node_package/src/ReactOnRailsRSC.ts
[error] 1-1: 'ReactElement' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 32-32: Unexpected any. Specify a different type.
(@typescript-eslint/no-explicit-any)
🔇 Additional comments (8)
package.json (2)
49-49
:
Review the use of canary versions in dependencies
The addition of react-server-dom-webpack
and use of canary versions for React packages raises several concerns:
- Using canary versions in production could lead to instability
- All React-related packages should be pinned to the same version
- The peerDependencies need updating to reflect RSC requirements
Let's verify the React version requirements for RSC support:
Suggested updates:
- Document why canary versions are needed
- Update peerDependencies to reflect minimum React version needed for RSC
- Add a warning in the README about the experimental nature of RSC support
Would you like me to help draft the documentation updates?
5-10
: Verify the exports configuration and file paths
The exports configuration needs attention in several areas:
- The nested structure under "." might cause compatibility issues with some bundlers
- The export paths need verification
Let's verify the export paths and suggest improvements:
Consider restructuring the exports to be more explicit:
"exports": {
- ".": {
- "rsc-server": "./node_package/lib/ReactOnRailsRSC.js",
- "default": "./node_package/lib/ReactOnRails.js"
- }
+ "./rsc-server": "./node_package/lib/ReactOnRailsRSC.js",
+ ".": "./node_package/lib/ReactOnRails.js"
}
lib/react_on_rails/react_component/render_options.rb (1)
118-120
: LGTM! The implementation follows Ruby conventions.
The rsc?
method follows the established pattern for boolean accessors and is appropriately placed near other rendering-related options.
node_package/src/types/index.ts (1)
2-2
: LGTM: Stream type import for RSC support
The addition of PassThrough
type import is appropriate for implementing RSC streaming support.
node_package/src/ReactOnRails.ts (2)
2-2
: LGTM: Stream type import for RSC support
The addition of PassThrough
type import is appropriate for RSC streaming support.
259-266
: 🛠️ Refactor suggestion
Enhance RSC method implementation and documentation
The new RSC method implementation needs improvements in several areas:
- Documentation should explain:
- The purpose of RSC rendering
- When to use this vs regular server rendering
- What an RSC bundle is and how to configure it
- The error message could be more informative about how to resolve the issue
- The eslint-disable comment should be removed and the options parameter should be properly typed or used
Consider this improved implementation:
/**
* Used by server rendering by Rails
+ * Renders a React Server Component (RSC) on the server side.
+ * This method is only available in the RSC-specific bundle and provides streaming support
+ * for React Server Components.
+ *
+ * @see https://react.dev/blog/2020/12/21/data-fetching-with-react-server-components
* @param options Configuration for server-side RSC rendering
+ * @throws {Error} When called from the main bundle instead of the RSC bundle
*/
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
serverRenderRSCReactComponent(options: RenderParams): PassThrough {
- throw new Error('serverRenderRSCReactComponent is supported in RSC bundle only.');
+ throw new Error(
+ 'serverRenderRSCReactComponent must be called from the RSC bundle. ' +
+ 'Please ensure you have configured your bundler to create a separate RSC bundle ' +
+ 'and that you are importing from the correct bundle.'
+ );
}
Let's verify if there are any RSC-related configurations or documentation:
lib/react_on_rails/utils.rb (1)
Line range hint 58-96
: Refactored bundle_js_file_path
enhances maintainability
The introduction of the bundle_js_file_path
method centralizes the logic for determining the bundle file paths. This refactoring reduces code duplication and improves the maintainability of the codebase. The method handles different scenarios effectively.
lib/react_on_rails/helper.rb (1)
532-537
: New method internal_rsc_react_component
implemented correctly
The internal_rsc_react_component
method properly configures the render options for React Server Components and invokes the server render function.
node_package/src/types/index.ts
Outdated
@@ -171,6 +171,7 @@ export interface ReactOnRails { | |||
getComponent(name: string): RegisteredComponent; | |||
serverRenderReactComponent(options: RenderParams): null | string | Promise<RenderResult>; | |||
streamServerRenderedReactComponent(options: RenderParams): Readable; | |||
serverRenderRSCReactComponent(options: RenderParams): PassThrough; |
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.
💡 Codebase verification
Missing test coverage for RSC implementation
The implementation requires test coverage for:
serverRenderRSCReactComponent
methodrsc_react_component
Ruby helper- Error handling scenarios
Key files needing tests:
node_package/src/ReactOnRailsRSC.ts
lib/react_on_rails/helper.rb
🔗 Analysis chain
Verify RSC implementation completeness
Since this is a WIP PR implementing RSC support, let's verify the complete implementation:
RSC implementation needs additional test coverage
The implementation appears incomplete as it requires:
- Test coverage for the RSC-specific functionality
- Tests for the Ruby helper method
rsc_react_component
- Tests for error handling in
serverRenderRSCReactComponent
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify RSC implementation across the codebase
# Check for RSC implementation in ReactOnRails.ts
echo "Checking ReactOnRails implementation..."
rg "serverRenderRSCReactComponent" "node_package/src/ReactOnRails.ts" -A 5
# Check for corresponding Ruby helper methods
echo "Checking Ruby helpers..."
rg "rsc_react_component" "lib/react_on_rails/helper.rb" -A 5
# Check for test coverage
echo "Checking test coverage..."
fd -e spec.rb -e spec.ts -e test.ts | xargs rg "RSC|React Server Components"
Length of output: 2688
Script:
#!/bin/bash
# Check for RSC-specific test files
echo "Checking for RSC test files..."
fd -e spec.rb -e spec.ts -e test.ts | xargs rg "describe.*RSC|test.*RSC"
# Check for test coverage of rsc_react_component helper
echo "Checking Ruby helper tests..."
rg "rsc_react_component" "spec/" -A 5
# Check for error handling tests
echo "Checking error handling tests..."
rg "serverRenderRSCReactComponent.*Error" "spec/" -A 5
Length of output: 380
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
Outdated
Show resolved
Hide resolved
d437954
to
d975912
Compare
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: 7
🧹 Outside diff range and nitpick comments (5)
node_package/src/ReactOnRailsRSC.ts (2)
1-1
: Remove unused importReactElement
.The
ReactElement
type is imported but never used in the code.-import type { ReactElement } from 'react';
🧰 Tools
🪛 eslint
[error] 1-1: 'ReactElement' is defined but never used.
(@typescript-eslint/no-unused-vars)
39-91
: Add comprehensive tests for RSC implementation.The RSC implementation needs thorough testing to ensure reliability. Consider adding tests for:
- Success cases with different component types
- Error cases (invalid components, rendering failures)
- Stream processing edge cases
- Bundle config loading scenarios
Would you like me to help create a test suite for the RSC implementation?
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (2)
Line range hint
59-65
: Consider RSC-specific evaluation pathWhile combining RSC with streaming makes sense, consider if RSC needs additional specific handling:
- RSC might require different error boundaries
- The evaluation context might need RSC-specific setup
- Performance monitoring might need to distinguish between RSC and regular streaming
Consider splitting the condition and adding RSC-specific handling:
- result = if render_options.stream? || render_options.rsc? + result = if render_options.rsc? + js_evaluator.eval_rsc_js(js_code, render_options) + elsif render_options.stream? js_evaluator.eval_streaming_js(js_code, render_options) else js_evaluator.eval_js(js_code, render_options) end
Line range hint
79-83
: Improve stream chunk processing and fix line lengthThe streaming logic looks good, but consider these improvements:
- The line exceeds length limit (134/120)
- Chunk processing could benefit from explicit error handling
Consider this refactoring:
- return parse_result_and_replay_console_messages(result, render_options) unless render_options.stream? || render_options.rsc? + return parse_result_and_replay_console_messages(result, render_options) unless + render_options.stream? || render_options.rsc? - result.transform { |chunk| parse_result_and_replay_console_messages(chunk, render_options) } + result.transform do |chunk| + begin + parse_result_and_replay_console_messages(chunk, render_options) + rescue StandardError => e + Rails.logger.error("[react_on_rails] Error processing stream chunk: #{e.message}") + raise ReactOnRails::Error, "Stream chunk processing failed: #{e.message}" + end + end🧰 Tools
🪛 rubocop
[convention] 79-79: Modifier form of
unless
makes the line too long.(Style/IfUnlessModifier)
[convention] 79-79: Line is too long. [134/120]
(Layout/LineLength)
lib/react_on_rails/helper.rb (1)
152-161
: Add documentation for the RSC streaming methodThe method lacks documentation explaining its purpose, parameters, and usage. Consider adding RDoc documentation similar to
stream_react_component
.Additionally, the code can be simplified by removing the redundant assignment:
def rsc_react_component(component_name, options = {}) - rendering_fiber = Fiber.new do + Fiber.new do res = internal_rsc_react_component(component_name, options) res.each_chunk do |chunk| Fiber.yield chunk end Fiber.yield nil end - rendering_fiber end🧰 Tools
🪛 rubocop
[convention] 153-159: Redundant assignment before returning detected.
(Style/RedundantAssignment)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (2)
Gemfile.lock
is excluded by!**/*.lock
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (8)
lib/react_on_rails/helper.rb
(4 hunks)lib/react_on_rails/react_component/render_options.rb
(1 hunks)lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
(3 hunks)lib/react_on_rails/utils.rb
(2 hunks)node_package/src/ReactOnRails.ts
(2 hunks)node_package/src/ReactOnRailsRSC.ts
(1 hunks)node_package/src/types/index.ts
(2 hunks)package.json
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- lib/react_on_rails/react_component/render_options.rb
- node_package/src/ReactOnRails.ts
- node_package/src/types/index.ts
- package.json
🧰 Additional context used
🪛 rubocop
lib/react_on_rails/helper.rb
[convention] 153-159: Redundant assignment before returning detected.
(Style/RedundantAssignment)
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
[convention] 79-79: Modifier form of unless
makes the line too long.
(Style/IfUnlessModifier)
[convention] 79-79: Line is too long. [134/120]
(Layout/LineLength)
🪛 eslint
node_package/src/ReactOnRailsRSC.ts
[error] 1-1: 'ReactElement' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 32-32: Unexpected any. Specify a different type.
(@typescript-eslint/no-explicit-any)
🔇 Additional comments (4)
lib/react_on_rails/utils.rb (2)
Line range hint 69-96
: LGTM! Well-structured bundle path resolution
The method effectively handles different bundle scenarios with clear documentation and appropriate fallback mechanisms.
98-112
: LGTM! Good refactoring of bundle path resolution
The changes effectively reuse the common bundle path resolution logic while maintaining proper caching behavior.
lib/react_on_rails/helper.rb (2)
532-537
: LGTM!
The implementation correctly sets up RSC-specific rendering options and follows the established pattern of other internal render methods.
389-396
: Clean up commented code
The commented code appears to be obsolete after switching to the simplified bundle loading approach. If this code is no longer needed, it should be removed rather than left as comments. If there's a reason to keep it (e.g., for potential rollback), add a comment explaining why.
Let's verify if this code is referenced elsewhere:
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (1)
lib/react_on_rails/helper.rb (1)
378-402
: Add documentation for the fiber management methodThe
run_stream_inside_fiber
method handles critical fiber management logic for both streaming and RSC. Consider adding documentation to explain:
- The fiber lifecycle management
- The significance of
@rorp_rendering_fibers
- The streaming flow and chunk handling
+ # Manages the lifecycle of a rendering fiber for streaming React components. + # @param [Block] block The rendering logic that generates the stream + # @return [String] The initial HTML chunk + # @raise [ReactOnRails::Error] If Pro is not enabled or if not in streaming context def run_stream_inside_fiber
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
lib/react_on_rails/helper.rb
(4 hunks)
🔇 Additional comments (1)
lib/react_on_rails/helper.rb (1)
364-371
: Verify the impact of removing component-specific pack loading
The change from component-specific packs to always loading "client-bundle" could affect:
- Initial page load performance
- Bundle size optimization
- Development mode debugging
✅ Verification successful
Based on the examination of the codebase, particularly the webpack configuration and packs generator implementation, I can now provide a final response:
Component-specific pack loading removal is part of automated bundle generation
The change from component-specific packs to a single client bundle is intentional and safe because:
- The codebase has implemented an automated pack generation system (PacksGenerator) that handles component bundling efficiently
- Components are automatically registered and included in the client bundle through the
ReactOnRails.register()
mechanism - The webpack configuration (
clientWebpackConfig.js
) is properly set up to handle the consolidated bundle approach
The performance impact is mitigated because:
- The packs generator automatically handles component registration and bundling
- The system supports both common and client-specific components with proper separation
- Bundle optimization is handled at the webpack configuration level
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check the size difference between component-specific and client bundles
echo "Searching for client bundle references..."
rg -l "client-bundle" --type js
echo "Checking for existing component-specific bundles..."
fd -e js . -x echo "Size of {}: $(wc -c < {})" \; | grep "generated/"
Length of output: 507
Script:
#!/bin/bash
# Let's check the webpack configuration and related files for bundle setup
echo "Searching for webpack configuration files..."
fd -e js webpack
echo "Checking for bundle configuration in package.json..."
fd package.json -x cat {}
echo "Looking for client bundle related code..."
rg -A 5 "client-bundle" --type js --type ruby
echo "Searching for component generation or bundling logic..."
rg -l "generated.*component" --type js --type ruby
Length of output: 12484
Script:
#!/bin/bash
# Let's examine the webpack configuration and packs generator
echo "Checking webpack config for bundle setup..."
cat spec/dummy/config/webpack/clientWebpackConfig.js
echo "\nExamining packs generator implementation..."
cat lib/react_on_rails/packs_generator.rb
echo "\nLooking for component-specific pack references..."
rg "generated/.*pack" --type ruby -A 3
Length of output: 9976
3a61c0c
to
268d49d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (1)
lib/react_on_rails/helper.rb (1)
377-401
: Enhance error handling and documentation for fiber managementThe fiber management implementation could benefit from the following improvements:
- More descriptive error messages
- Documentation explaining the fiber lifecycle
- Consideration for fiber cleanup
Consider applying these improvements:
def run_stream_inside_fiber unless ReactOnRails::Utils.react_on_rails_pro? raise ReactOnRails::Error, - "You must use React on Rails Pro to use the stream_react_component method." + "Streaming support requires React on Rails Pro subscription. Please upgrade to use this feature." end if @rorp_rendering_fibers.nil? raise ReactOnRails::Error, - "You must call stream_view_containing_react_components to render the view containing the react component" + "Missing initialization: Call stream_view_containing_react_components before rendering streaming components" end + # Store weak references to avoid memory leaks + require 'weakref' + @rorp_rendering_fibers ||= [] rendering_fiber = Fiber.new do stream = yield stream.each_chunk do |chunk| Fiber.yield chunk end end - @rorp_rendering_fibers << rendering_fiber + @rorp_rendering_fibers << WeakRef.new(rendering_fiber) # return the first chunk of the fiber # It contains the initial html of the component # all updates will be appended to the stream sent to browser rendering_fiber.resume end
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
lib/react_on_rails/helper.rb
(4 hunks)
🔇 Additional comments (1)
lib/react_on_rails/helper.rb (1)
413-420
: 🛠️ Refactor suggestion
Enhance error handling and type safety for RSC
The RSC implementation should include:
- Type validation for the JSON stream
- Error handling for transformation failures
Apply this improvement:
def internal_rsc_react_component(react_component_name, options = {})
options = options.merge(rsc?: true)
render_options = create_render_options(react_component_name, options)
json_stream = server_rendered_react_component(render_options)
+ raise ReactOnRails::Error, "Invalid RSC stream" unless json_stream.respond_to?(:transform)
json_stream.transform do |chunk|
+ raise ReactOnRails::Error, "Invalid chunk format" unless chunk.is_a?(Hash) && chunk.key?(:html)
chunk[:html].html_safe
end
+rescue StandardError => e
+ raise ReactOnRails::PrerenderError.new(
+ component_name: react_component_name,
+ err: e,
+ props: options[:props]
+ )
end
Likely invalid or redundant comment.
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
Outdated
Show resolved
Hide resolved
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
Outdated
Show resolved
Hide resolved
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 (4)
lib/react_on_rails/packer_utils.rb (1)
77-78
: Improve variable naming for clarity.The variable name
is_bundle_running_on_server
could be more specific about its purpose.- is_bundle_running_on_server = (bundle_name == ReactOnRails.configuration.server_bundle_js_file) || - (bundle_name == ReactOnRails.configuration.rsc_bundle_js_file) + is_server_side_bundle = (bundle_name == ReactOnRails.configuration.server_bundle_js_file) || + (bundle_name == ReactOnRails.configuration.rsc_bundle_js_file)lib/react_on_rails/utils.rb (1)
114-119
: Consider adding documentation for RSC bundle configuration.While the implementation is correct, it would be helpful to add documentation explaining:
- The purpose of the RSC bundle
- When and how it's used
- Configuration requirements
spec/react_on_rails/utils_spec.rb (2)
119-121
: Fix RuboCop style issues.Address the following style issues:
- Multiple
before
hooks in the same example group- Default
:each
argument can be omitted- Long lines with modifier conditions
- before :each do + before do - ReactOnRails::PackerUtils.remove_instance_variable(:@using_shakapacker_const) if ReactOnRails::PackerUtils.instance_variable_defined?(:@using_shakapacker_const) - ReactOnRails::PackerUtils.remove_instance_variable(:@using_webpacker_const) if ReactOnRails::PackerUtils.instance_variable_defined?(:@using_webpacker_const) + if ReactOnRails::PackerUtils.instance_variable_defined?(:@using_shakapacker_const) + ReactOnRails::PackerUtils.remove_instance_variable(:@using_shakapacker_const) + end + if ReactOnRails::PackerUtils.instance_variable_defined?(:@using_webpacker_const) + ReactOnRails::PackerUtils.remove_instance_variable(:@using_webpacker_const) + end🧰 Tools
🪛 rubocop (1.69.1)
[convention] 119-119: Omit the default
:each
argument for RSpec hooks.(RSpec/HookArgument)
[convention] 119-122: Do not define multiple
before
hooks in the same example group (also defined on line 108).(RSpec/ScatteredSetup)
[convention] 120-120: Modifier form of
if
makes the line too long.(Style/IfUnlessModifier)
[convention] 120-120: Line is too long. [168/120]
(Layout/LineLength)
[convention] 121-121: Modifier form of
if
makes the line too long.(Style/IfUnlessModifier)
[convention] 121-121: Line is too long. [164/120]
(Layout/LineLength)
191-191
: Fix RuboCop style issues.Address the following style issues:
- Use
%w
for array of words- Add empty lines after
let
declarations- ["shakapacker", "webpacker"].each do |packer_type| + %w[shakapacker webpacker].each do |packer_type| - let(:packer_public_output_path) { Pathname.new("public/webpack/development") } - include_context "with #{packer_type} enabled" + let(:packer_public_output_path) { Pathname.new("public/webpack/development") } + + include_context "with #{packer_type} enabled"Also applies to: 193-193, 255-255
🧰 Tools
🪛 rubocop (1.69.1)
[convention] 191-191: Use
%w
or%W
for an array of words.(Style/WordArray)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
Gemfile.lock
is excluded by!**/*.lock
spec/dummy/Gemfile.lock
is excluded by!**/*.lock
📒 Files selected for processing (6)
Gemfile.development_dependencies
(1 hunks)lib/react_on_rails/configuration.rb
(5 hunks)lib/react_on_rails/packer_utils.rb
(1 hunks)lib/react_on_rails/utils.rb
(2 hunks)node_package/src/ReactOnRailsRSC.ts
(1 hunks)spec/react_on_rails/utils_spec.rb
(4 hunks)
🧰 Additional context used
📓 Learnings (1)
node_package/src/ReactOnRailsRSC.ts (1)
Learnt from: alexeyr-ci
PR: shakacode/react_on_rails#1644
File: node_package/src/ReactOnRailsRSC.ts:87-87
Timestamp: 2024-12-12T13:07:09.929Z
Learning: When handling errors in 'node_package/src/ReactOnRailsRSC.ts', include the error stack in error messages in development and test environments to aid debugging.
🪛 rubocop (1.69.1)
spec/react_on_rails/utils_spec.rb
[convention] 38-38: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 39-39: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 56-56: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 57-57: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 108-112: Do not define multiple before
hooks in the same example group (also defined on line 119).
(RSpec/ScatteredSetup)
[convention] 119-119: Omit the default :each
argument for RSpec hooks.
(RSpec/HookArgument)
[convention] 120-120: Modifier form of if
makes the line too long.
(Style/IfUnlessModifier)
[convention] 120-120: Line is too long. [168/120]
(Layout/LineLength)
[convention] 121-121: Modifier form of if
makes the line too long.
(Style/IfUnlessModifier)
[convention] 121-121: Line is too long. [164/120]
(Layout/LineLength)
[convention] 191-191: Use %w
or %W
for an array of words.
(Style/WordArray)
[convention] 193-193: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
[convention] 255-255: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
🔇 Additional comments (12)
Gemfile.development_dependencies (1)
55-55
: Consider using a stable version of webpacker.
Using a release candidate version (6.0.0.rc.6
) in production code could lead to stability issues. Consider either:
- Using the latest stable version of webpacker
- Documenting why this specific RC version is required
node_package/src/ReactOnRailsRSC.ts (5)
86-86
: 🛠️ Refactor suggestion
Include error stack in development/test environments.
Based on previous learnings, include the error stack in non-production environments for better debugging.
- renderResult = stringToStream(`Error: ${e}`);
+ const isDevOrTest = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
+ const errorMessage = isDevOrTest ? `Error: ${e.stack}` : 'An error occurred while rendering the component';
+ renderResult = stringToStream(errorMessage);
Likely invalid or redundant comment.
28-36
: 🛠️ Refactor suggestion
Improve error handling and configuration in getBundleConfig.
The function needs better error handling and should support configurable paths.
-const getBundleConfig = () => {
+const getBundleConfig = (manifestPath = './public/webpack/development/react-client-manifest.json') => {
try {
- const bundleConfig = JSON.parse(fs.readFileSync('./public/webpack/development/react-client-manifest.json', 'utf8'));
+ const bundleConfig = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
const newBundleConfig: { [key: string]: unknown } = {};
for (const [key, value] of Object.entries(bundleConfig)) {
newBundleConfig[key.replace('file://', '')] = value;
}
return newBundleConfig;
+ } catch (error) {
+ throw new Error(`Failed to read or parse manifest file at ${manifestPath}: ${error}`);
}
}
Likely invalid or redundant comment.
67-80
: 🛠️ Refactor suggestion
Replace recursive stream processing with iteration.
The current recursive implementation of processStream
could lead to stack overflow for large streams.
- const processStream = async () => {
- const { done, value } = await streamReader.read();
- if (done) {
- renderResult?.push(null);
- // @ts-expect-error value is not typed
- debugConsole.log('value', finalValue);
- return;
- }
-
- finalValue += decoder.decode(value);
- renderResult?.push(value);
- processStream();
- }
- processStream();
+ const processStream = async () => {
+ while (true) {
+ const { done, value } = await streamReader.read();
+ if (done) {
+ renderResult?.push(null);
+ break;
+ }
+ finalValue += decoder.decode(value);
+ renderResult?.push(value);
+ }
+ };
+ await processStream();
Likely invalid or redundant comment.
12-19
:
Avoid modifying globalThis for AsyncLocalStorage.
As discussed in previous comments, modifying globalThis
could lead to runtime conflicts. Consider importing AsyncLocalStorage
directly where needed.
-(async () => {
- try {
- // @ts-expect-error AsyncLocalStorage is not in the node types
- globalThis.AsyncLocalStorage = (await import('node:async_hooks')).AsyncLocalStorage;
- } catch (e) {
- console.log('AsyncLocalStorage not found');
- }
-})();
+import { AsyncLocalStorage } from 'node:async_hooks';
Likely invalid or redundant comment.
1-2
: Consider using a more specific import path.
The import from react-server-dom-webpack/server.edge
might need to be server.node
instead, as mentioned in a previous PR discussion. Please verify the correct import path for your environment.
lib/react_on_rails/utils.rb (2)
Line range hint 69-95
: LGTM! Well-structured refactor of bundle path resolution.
The refactoring improves code reusability by extracting common bundle path resolution logic into a shared method. The error handling and caching mechanisms are properly implemented.
98-112
: LGTM! Clean adaptation to use the new bundle path resolution.
The method maintains its original functionality while leveraging the new shared implementation.
lib/react_on_rails/configuration.rb (2)
20-20
: LGTM! Clean addition of RSC bundle configuration.
The RSC bundle configuration is properly integrated into the existing configuration pattern.
Also applies to: 59-59, 75-76
247-247
: LGTM! Proper handling of RSC bundle in webpack generated files.
The RSC bundle is correctly added to the webpack_generated_files list when present.
spec/react_on_rails/utils_spec.rb (2)
9-105
: LGTM! Well-structured test helpers and shared contexts.
The shared contexts and helper methods improve test maintainability and readability.
🧰 Tools
🪛 rubocop (1.69.1)
[convention] 38-38: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 39-39: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 56-56: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 57-57: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
254-312
: LGTM! Comprehensive test coverage for RSC bundle functionality.
The tests thoroughly cover the RSC bundle path resolution under different scenarios:
- Missing manifest entries
- Dev server running
- Client/server bundle configurations
🧰 Tools
🪛 rubocop (1.69.1)
[convention] 255-255: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
node_package/src/ReactOnRailsRSC.ts (1)
12-17
: Consider adding error handling to stringToStream utility.While the implementation is correct, it should handle potential errors when pushing to the stream.
const stringToStream = (str: string) => { const stream = new PassThrough(); - stream.push(str); - stream.push(null); + try { + stream.push(str); + stream.push(null); + } catch (error) { + stream.destroy(new Error(`Failed to write to stream: ${error}`)); + } return stream; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
node_package/src/ReactOnRailsRSC.ts
(1 hunks)
🧰 Additional context used
📓 Learnings (1)
node_package/src/ReactOnRailsRSC.ts (1)
Learnt from: alexeyr-ci
PR: shakacode/react_on_rails#1644
File: node_package/src/ReactOnRailsRSC.ts:87-87
Timestamp: 2024-12-12T13:07:09.929Z
Learning: When handling errors in 'node_package/src/ReactOnRailsRSC.ts', include the error stack in error messages in development and test environments to aid debugging.
🔇 Additional comments (5)
node_package/src/ReactOnRailsRSC.ts (5)
72-78
: Enhance error handling with stack traces in development.
Based on previous learning, include stack traces in development and test environments to aid debugging.
} catch (e: unknown) {
if (throwJsErrors) {
throw e;
}
- renderResult = stringToStream(`Error: ${e}`);
+ const isDevOrTest = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
+ const errorMessage = isDevOrTest && e instanceof Error ?
+ `Error: ${e.stack}` :
+ 'An error occurred while rendering the component';
+ renderResult = stringToStream(errorMessage);
}
83-84
: LGTM! Exports are properly structured.
The exports follow standard practices by re-exporting types and providing the default export.
19-27
:
Improve bundle configuration handling.
Several issues need to be addressed:
- Hardcoded development path is environment-specific
- Missing error handling for file operations
- No validation of the bundle config structure
-const getBundleConfig = () => {
+const getBundleConfig = (manifestPath = process.env.BUNDLE_MANIFEST_PATH || './public/webpack/development/react-client-manifest.json') => {
try {
const bundleConfig = JSON.parse(fs.readFileSync('./public/webpack/development/react-client-manifest.json', 'utf8'));
+ if (!bundleConfig || typeof bundleConfig !== 'object') {
+ throw new Error('Invalid bundle configuration format');
+ }
// remove file:// from keys
const newBundleConfig: { [key: string]: unknown } = {};
for (const [key, value] of Object.entries(bundleConfig)) {
newBundleConfig[key.replace('file://', '')] = value;
}
return newBundleConfig;
+ } catch (error) {
+ throw new Error(`Failed to load bundle configuration: ${error}`);
}
}
Likely invalid or redundant comment.
58-71
:
Replace recursive stream processing with async iteration.
The current recursive implementation could cause stack overflow for large streams. Additionally, the stream processing is not properly awaited.
- const processStream = async () => {
- const { done, value } = await streamReader.read();
- if (done) {
- renderResult?.push(null);
- // @ts-expect-error value is not typed
- debugConsole.log('value', finalValue);
- return;
- }
-
- finalValue += decoder.decode(value);
- renderResult?.push(value);
- processStream();
- }
- processStream();
+ const processStream = async () => {
+ try {
+ while (true) {
+ const { done, value } = await streamReader.read();
+ if (done) {
+ renderResult?.push(null);
+ break;
+ }
+ finalValue += decoder.decode(value);
+ renderResult?.push(value);
+ }
+ } catch (error) {
+ renderResult?.destroy(error);
+ }
+ };
+ // Ensure the stream processing is properly awaited
+ void processStream();
Likely invalid or redundant comment.
1-2
: Verify the correct server runtime import.
There's a discrepancy between using server.edge
here versus server.node
in PR #1663. Please clarify which runtime should be used and ensure consistency across the codebase.
✅ Verification successful
Using server.edge
is correct for RSC implementation
The current import of react-server-dom-webpack/server.edge
is correct for React Server Components implementation. The file is specifically implementing RSC support and the Edge runtime is the recommended choice for RSC as it provides better performance and supports streaming. There's no actual discrepancy with PR #1663 as that PR was a work in progress ([WIP]) and the current implementation has evolved to use the Edge runtime.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for other RSC-related imports to ensure consistency
rg -l "react-server-dom-webpack/(server\.(edge|node))"
Length of output: 92
Script:
#!/bin/bash
# Let's check the content of PR #1663 to understand the context of server.node usage
gh pr view 1663 --json body,title
# Also check the file content to see the full context
cat node_package/src/ReactOnRailsRSC.ts
Length of output: 3779
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
spec/react_on_rails/test_helper/webpack_assets_status_checker_spec.rb (2)
73-75
: Consider improving the constant handling.While the error handling test is good, the current approach of defining the
Packer
constant in the before block (with rubocop disable) could be improved.Consider these alternatives:
- Move the constant to a shared context or helper
- Use stub_const instead:
- Packer = ReactOnRails::PackerUtils.packer + stub_const("ReactOnRails::PackerUtils::Packer", ReactOnRails::PackerUtils.packer)This would:
- Eliminate the need for rubocop disables
- Prevent potential constant leakage between tests
- Follow RSpec best practices for constant handling
70-75
: Consider adding RSC-specific test cases.While the current changes handle the basic server bundle scenarios, consider adding test cases specifically for RSC bundles:
- RSC bundle with custom name from configuration
- Multiple RSC bundles scenario
- RSC bundle with different file extension
This would ensure robust test coverage for the new RSC support feature. Would you like help drafting these additional test cases?
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: 3
🧹 Nitpick comments (2)
spec/react_on_rails/utils_spec.rb (2)
26-27
: Fix misleading commentThe comment incorrectly states "Mock that shakapacker is not installed, so webpacker will be used instead" when actually mocking that shakapacker is installed.
- # Mock that shakapacker is not installed, so webpacker will be used instead + # Mock that shakapacker is installed and webpacker is not🧰 Tools
🪛 rubocop (1.69.1)
[convention] 27-27: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
9-72
: Consider extracting common mock setupThe shared contexts have some duplicated mock setup logic. Consider extracting common mock setup into a separate helper method to improve maintainability.
def mock_packer_config(packer_public_output_path) allow(ReactOnRails).to receive_message_chain(:configuration, :generated_assets_dir) .and_return("") allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("dev_server.running?") .and_return(false) allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("config.public_output_path") .and_return(packer_public_output_path) end🧰 Tools
🪛 rubocop (1.69.1)
[convention] 27-27: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 28-28: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 45-45: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 46-46: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 63-63: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 64-64: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
spec/react_on_rails/utils_spec.rb
(4 hunks)
🧰 Additional context used
🪛 rubocop (1.69.1)
spec/react_on_rails/utils_spec.rb
[convention] 27-27: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 28-28: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 45-45: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 46-46: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 63-63: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 64-64: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 115-119: Do not define multiple before
hooks in the same example group (also defined on line 126).
(RSpec/ScatteredSetup)
[convention] 126-126: Omit the default :each
argument for RSpec hooks.
(RSpec/HookArgument)
[convention] 127-127: Modifier form of if
makes the line too long.
(Style/IfUnlessModifier)
[convention] 127-127: Line is too long. [168/120]
(Layout/LineLength)
[convention] 128-128: Modifier form of if
makes the line too long.
(Style/IfUnlessModifier)
[convention] 128-128: Line is too long. [164/120]
(Layout/LineLength)
[convention] 198-198: Use %w
or %W
for an array of words.
(Style/WordArray)
[convention] 200-200: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
[convention] 262-262: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
🔇 Additional comments (3)
spec/react_on_rails/utils_spec.rb (3)
74-112
: LGTM! Well-structured helper methods
The helper methods are well-designed with clear responsibilities and good documentation. The use of random bundle names is particularly good for catching potential mix-ups between server and RSC bundles.
Line range hint 1-320
: Overall assessment: Good test coverage with minor improvements needed
The test implementation for RSC support is thorough and well-structured. The shared contexts and helper methods provide a good foundation for testing different packer configurations. Consider the following improvements:
- Address the constant redefinition issues
- Reduce duplication in bundle path tests
- Add error scenario test cases
- Fix RuboCop violations in test setup
The changes align well with the PR objective of adding RSC support.
🧰 Tools
🪛 rubocop (1.69.1)
[convention] 27-27: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 28-28: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 45-45: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 46-46: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 63-63: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 64-64: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 115-119: Do not define multiple before
hooks in the same example group (also defined on line 126).
(RSpec/ScatteredSetup)
[convention] 126-126: Omit the default :each
argument for RSpec hooks.
(RSpec/HookArgument)
[convention] 126-129: Do not define multiple before
hooks in the same example group (also defined on line 115).
(RSpec/ScatteredSetup)
[convention] 127-127: Modifier form of if
makes the line too long.
(Style/IfUnlessModifier)
[convention] 127-127: Line is too long. [168/120]
(Layout/LineLength)
[convention] 128-128: Modifier form of if
makes the line too long.
(Style/IfUnlessModifier)
[convention] 128-128: Line is too long. [164/120]
(Layout/LineLength)
198-320
: Add test cases for error scenarios
The tests cover the happy path but are missing cases for error scenarios such as:
- Invalid bundle names
- Malformed manifest entries
- Network errors when dev server is running
🧰 Tools
🪛 rubocop (1.69.1)
[convention] 198-198: Use %w
or %W
for an array of words.
(Style/WordArray)
[convention] 200-200: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
[convention] 262-262: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
spec/react_on_rails/utils_spec.rb (2)
9-72
: Well-structured shared contexts for different packer configurations!The shared contexts effectively isolate the test setup for different packer configurations. However, there are some improvements we can make to follow RSpec best practices:
- Use
described_class
instead of direct class references for better maintainability:- allow(ReactOnRails::Utils).to receive(:gem_available?).with("shakapacker").and_return(true) + allow(described_class).to receive(:gem_available?).with("shakapacker").and_return(true)
- Consider extracting the common gem availability mocks into a helper method to reduce duplication across contexts.
🧰 Tools
🪛 rubocop (1.69.1)
[convention] 27-27: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 28-28: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 45-45: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 46-46: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 63-63: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
[convention] 64-64: Use
described_class
instead ofReactOnRails::Utils
.(RSpec/DescribedClass)
126-129
: Consolidate setup hooks and remove redundant:each
argument- before :each do + before do ReactOnRails::PackerUtils.instance_variables.each do |instance_variable| ReactOnRails::PackerUtils.remove_instance_variable(instance_variable) end end🧰 Tools
🪛 rubocop (1.69.1)
[convention] 126-126: Omit the default
:each
argument for RSpec hooks.(RSpec/HookArgument)
[convention] 126-130: Do not define multiple
before
hooks in the same example group (also defined on line 115).(RSpec/ScatteredSetup)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
spec/react_on_rails/utils_spec.rb
(4 hunks)
🧰 Additional context used
🪛 rubocop (1.69.1)
spec/react_on_rails/utils_spec.rb
[convention] 27-27: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 28-28: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 45-45: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 46-46: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 63-63: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 64-64: Use described_class
instead of ReactOnRails::Utils
.
(RSpec/DescribedClass)
[convention] 115-119: Do not define multiple before
hooks in the same example group (also defined on line 126).
(RSpec/ScatteredSetup)
[convention] 126-126: Omit the default :each
argument for RSpec hooks.
(RSpec/HookArgument)
[convention] 199-199: Use %w
or %W
for an array of words.
(Style/WordArray)
[convention] 201-201: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
[convention] 263-263: Add an empty line after the last let
.
(RSpec/EmptyLineAfterFinalLet)
🔇 Additional comments (2)
spec/react_on_rails/utils_spec.rb (2)
74-112
: Excellent helper methods for test setup!
The helper methods are well-documented and follow single responsibility principle. The mock_bundle_configs
method's documentation about random bundle names is particularly helpful.
218-218
: Remove constant redefinition in tests
The Packer
constant is redefined multiple times, which violates Ruby best practices and triggers RuboCop warnings. Consider moving this to a let
block or before hook.
- Packer = ReactOnRails::PackerUtils.packer # rubocop:disable Lint/ConstantDefinitionInBlock, RSpec/LeakyConstantDeclaration
+ let(:packer) { ReactOnRails::PackerUtils.packer }
Also applies to: 280-280
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 (6)
node_package/tests/RSCClientRoot.test.jsx (6)
7-9
: Consider moving webpack mocks to a separate file.For better organization and reusability, consider moving the webpack require system mocks to a separate test utilities file, similar to how
createNodeReadableStream
is imported fromtestUtils
.
25-27
: Enhance version compatibility documentation.The comment about React version compatibility could be more specific. Consider documenting:
- The exact React versions tested
- Why Node 18+ is required
- Any known issues with other versions
35-45
: Add more React.use compatibility tests.Consider adding test cases for:
- Different React versions
- Various React.use implementations
- Error message format validation
76-102
: Add edge cases for component data fetching.Consider testing:
- Empty response handling
- Partial data scenarios
- Cache invalidation cases
- Multiple concurrent requests
104-132
: Enhance console logs testing.Consider:
- Testing different console methods (warn, error, etc.)
- Verifying log order
- Testing log formatting
- Adding cleanup for console spy
134-148
: Expand URL path handling tests.Consider adding test cases for:
- Multiple consecutive slashes
- URL-encoded characters
- Query parameters
- Different base URL patterns
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (6)
jest.config.js
(1 hunks)knip.ts
(2 hunks)node_package/tests/RSCClientRoot.test.jsx
(1 hunks)node_package/tests/fixtures/rsc-payloads/simple-shell-with-async-component/chunk1.json
(1 hunks)node_package/tests/fixtures/rsc-payloads/simple-shell-with-async-component/chunk2.json
(1 hunks)package.json
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- node_package/tests/fixtures/rsc-payloads/simple-shell-with-async-component/chunk2.json
- jest.config.js
- knip.ts
- node_package/tests/fixtures/rsc-payloads/simple-shell-with-async-component/chunk1.json
- package.json
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: dummy-app-integration-tests (newest)
- GitHub Check: dummy-app-integration-tests (oldest)
- GitHub Check: rspec-package-tests (newest)
- GitHub Check: rspec-package-tests (oldest)
- GitHub Check: build
🔇 Additional comments (1)
node_package/tests/RSCClientRoot.test.jsx (1)
47-74
: Add error path testing for component data fetching.Consider adding test cases for:
- Network failures
- Malformed server responses
- Timeout scenarios
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)
node_package/tests/testUtils.js (2)
3-10
: Fix typo in JSDoc comment.There's a typo in the documentation: "Pusing" should be "Pushing".
- * Pusing a null or undefined chunk will end the stream. + * Pushing a null or undefined chunk will end the stream.
34-34
: Consider enhancing version parsing robustness.While the current implementation works for basic cases, consider these improvements:
- Add error handling for invalid version strings
- Consider returning minor/patch versions if needed
- Add JSDoc documentation
+/** + * Returns the major version number of the current Node.js runtime. + * @returns {number} The major version number + * @throws {Error} If the version string is invalid + */ export const getNodeVersion = () => { - return parseInt(process.version.slice(1), 10); + const version = process.version.slice(1); + const majorVersion = parseInt(version, 10); + if (isNaN(majorVersion)) { + throw new Error(`Invalid Node.js version string: ${process.version}`); + } + return majorVersion; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
node_package/tests/RSCClientRoot.test.jsx
(1 hunks)node_package/tests/testUtils.js
(1 hunks)node_package/tests/utils.test.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- node_package/tests/utils.test.js
- node_package/tests/RSCClientRoot.test.jsx
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: dummy-app-integration-tests (newest)
- GitHub Check: dummy-app-integration-tests (oldest)
- GitHub Check: rspec-package-tests (newest)
- GitHub Check: build
- GitHub Check: rspec-package-tests (oldest)
🔇 Additional comments (2)
node_package/tests/testUtils.js (2)
1-1
: LGTM!The import statement correctly imports the
Readable
class from Node.js built-in 'stream' module.
11-32
: LGTM! Well-implemented stream creation utility.The implementation is robust and handles both immediate and queued data pushing scenarios. It correctly:
- Manages a queue for chunks when the stream isn't ready
- Properly binds the push function when the stream is ready to read
- Returns both the stream and push function for external control
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
node_package/src/RSCClientRoot.ts (1)
32-36
: Consider improving URL construction and props handling.A few suggestions for the
fetchRSC
function:
- The URL construction could benefit from using URL API for proper encoding
- Add error handling for props serialization
- Consider URL-encoding the props string
Here's a suggested improvement:
const fetchRSC = ({ componentName, rscPayloadGenerationUrlPath, componentProps }: RSCClientRootProps) => { - const propsString = JSON.stringify(componentProps); + let propsString; + try { + propsString = encodeURIComponent(JSON.stringify(componentProps)); + } catch (error) { + throw new Error(`Failed to serialize component props: ${error.message}`); + } const strippedUrlPath = rscPayloadGenerationUrlPath.replace(/^\/|\/$/g, ''); - return createFromFetch(fetch(`/${strippedUrlPath}/${componentName}?props=${propsString}`)) as Promise<React.ReactNode>; + const url = new URL(`${window.location.origin}/${strippedUrlPath}/${componentName}`); + url.searchParams.set('props', propsString); + return createFromFetch(fetch(url.toString())) as Promise<React.ReactNode>; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
jest.config.js
(1 hunks)node_package/src/RSCClientRoot.ts
(1 hunks)node_package/src/registerServerComponent.ts
(1 hunks)node_package/tests/RSCClientRoot.test.jsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- jest.config.js
- node_package/tests/RSCClientRoot.test.jsx
- node_package/src/registerServerComponent.ts
🧰 Additional context used
🧠 Learnings (1)
node_package/src/RSCClientRoot.ts (1)
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1644
File: node_package/src/RSCClientRoot.ts:14-17
Timestamp: 2025-02-13T14:30:58.040Z
Learning: Global caches in client-side JavaScript are safe from concurrent access issues due to JavaScript's single-threaded nature, even with async operations, as the event loop ensures sequential execution.
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: rspec-package-tests (newest)
- GitHub Check: examples (oldest)
- GitHub Check: build
- GitHub Check: rspec-package-tests (oldest)
🔇 Additional comments (5)
node_package/src/RSCClientRoot.ts (5)
6-6
: Verify the need for custom fetch utility.A custom fetch utility is imported instead of using the native fetch API.
Based on the past review comment, could you explain what future changes are anticipated that prevent using the native fetch API here?
10-14
: LGTM! Good error handling for React version compatibility.The early validation of React.use availability ensures clear error messages when attempting to use RSC with incompatible React versions.
16-20
: LGTM! Clear and well-structured type definitions.The RSCClientRootProps type is well-defined with descriptive property names and appropriate optionality.
51-73
: LGTM! Well-implemented RSC client root with proper error handling.The component correctly handles both hydration and fresh render cases with appropriate error checks.
69-72
: Address the TODO regarding RenderFunction return type.The empty string return appears to be a workaround for a type mismatch.
Could you create an issue to track fixing the RenderFunction type definition to better match the RSC use case? This would help eliminate the need for the empty string workaround.
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 (9)
knip.ts (1)
37-37
: Add an explanation comment for the jsdom entry.Other ignored dependencies have explanatory comments. Please add a comment explaining why jsdom needs to be ignored.
node_package/src/ClientSideRenderer.ts (2)
19-41
: Add type predicate for better type safety.Consider using a type predicate to improve type safety in the
delegateToRenderer
function.-function delegateToRenderer( +function delegateToRenderer( componentObj: RegisteredComponent, props: Record<string, string>, railsContext: RailsContext, domNodeId: string, trace: boolean, -): boolean { +): componentObj is RegisteredComponent & { isRenderer: true } {
119-124
: Improve error handling to preserve stack trace.The current error handling loses the original error's stack trace. Consider using the
cause
property to preserve it.- const error = e instanceof Error ? e : new Error(e?.toString() ?? 'Unknown error'); - console.error(error.message); - error.message = `ReactOnRails encountered an error while rendering component: ${name}. See above error message.` - throw error; + throw new Error( + `ReactOnRails encountered an error while rendering component: ${name}`, + { cause: e instanceof Error ? e : new Error(e?.toString() ?? 'Unknown error') } + );lib/react_on_rails/configuration.rb (3)
12-13
: Document the rationale for the default timeout value.Consider adding a comment explaining why 5000ms was chosen as the default timeout value for component registry. This would help future maintainers understand if this value needs adjustment based on their specific use cases.
67-68
: Consider splitting attr_accessor declarations for better readability.The line length is approaching the limit. Consider grouping related attributes and splitting them into multiple
attr_accessor
declarations for better maintainability.- :defer_generated_component_packs, :force_load, :rsc_bundle_js_file, - :react_client_manifest_file, :component_registry_timeout + :defer_generated_component_packs, :force_load + + # RSC-related configuration + attr_accessor :rsc_bundle_js_file, :react_client_manifest_file, + :component_registry_timeout
83-84
: Consider refactoring initialize to reduce complexity.The initialize method is growing in complexity with each new configuration option. Consider grouping related options into configuration objects to make the code more maintainable.
Example approach:
class RSCConfiguration attr_accessor :bundle_js_file, :client_manifest_file, :registry_timeout def initialize(bundle_js_file: nil, client_manifest_file: nil, registry_timeout: nil) @bundle_js_file = bundle_js_file @client_manifest_file = client_manifest_file @registry_timeout = registry_timeout end end # Usage in Configuration class attr_accessor :rsc_config def initialize(rsc_config: RSCConfiguration.new, ...)node_package/tests/RSCClientRoot.test.jsx (3)
25-33
: Add error handling for DOM setup.Consider handling potential DOM manipulation errors in the setup phase.
beforeEach(() => { // Setup DOM element container = document.createElement('div'); container.id = mockDomNodeId; + if (!container) { + throw new Error('Failed to create test container'); + } document.body.appendChild(container); jest.clearAllMocks(); jest.resetModules(); });
51-82
: Add TypeScript types for better maintainability.Consider adding type definitions to improve code maintainability and catch potential issues early.
+interface MockRSCRequestResult { + render: () => Promise<void>; + pushFirstChunk: () => void; + pushSecondChunk: () => void; + pushCustomChunk: (chunk: string) => void; + endStream: () => void; +} -const mockRSCRequest = async (rscPayloadGenerationUrlPath = 'rsc-render') => { +const mockRSCRequest = async (rscPayloadGenerationUrlPath = 'rsc-render'): Promise<MockRSCRequestResult> => {
107-136
: Add spy cleanup.Consider cleaning up the console spy after the test to prevent potential interference with other tests.
it('replays console logs', async () => { const consoleSpy = jest.spyOn(console, 'log'); + afterAll(() => { + consoleSpy.mockRestore(); + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (8)
knip.ts
(2 hunks)lib/react_on_rails/configuration.rb
(8 hunks)node_package/src/ClientSideRenderer.ts
(1 hunks)node_package/src/RSCClientRoot.ts
(1 hunks)node_package/src/utils.ts
(1 hunks)node_package/tests/RSCClientRoot.test.jsx
(1 hunks)node_package/types/react-server-dom-webpack.d.ts
(1 hunks)package.json
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- node_package/src/utils.ts
- node_package/src/RSCClientRoot.ts
- node_package/types/react-server-dom-webpack.d.ts
- package.json
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: dummy-app-integration-tests (newest)
- GitHub Check: dummy-app-integration-tests (oldest)
- GitHub Check: rspec-package-tests (newest)
- GitHub Check: build
- GitHub Check: rspec-package-tests (oldest)
🔇 Additional comments (18)
knip.ts (3)
7-14
: Fix the RSCWebpackLoader entry point extension.Based on past review comments, the RSCWebpackLoader is maintained as a JavaScript file and should be referenced with the
.js
extension.Apply this diff to fix the extension:
- 'node_package/src/RSCWebpackLoader.ts!', + 'node_package/src/RSCWebpackLoader.js!',
15-15
: LGTM! Project pattern correctly includes all necessary file extensions.The pattern now properly includes
.jsx
and.tsx
files, which is required for RSC-related test files.
19-21
: LGTM! Ignore configuration is properly set up.The ignore configuration correctly excludes the test-specific file from Knip's analysis.
node_package/src/ClientSideRenderer.ts (7)
1-18
: LGTM! Well-organized imports and constants.The imports are properly structured, and the constant is appropriately defined.
42-43
: Consider moving class to a separate file.Moving the
ComponentRenderer
class to its own file would improve code organization and maintainability.
143-149
: Use appropriate console method for errors.Using
console.info
for error logging is not ideal. Consider usingconsole.error
orconsole.warn
for better error visibility.
177-186
: Add error handling for store hydration.The store hydration process lacks proper error handling for store generation failures.
200-227
: LGTM! Well-implemented component rendering functions.The functions properly handle rendering, hydration, and cleanup of components.
229-259
: LGTM! Well-implemented store rendering functions.The functions properly handle hydration and cleanup of stores.
261-264
: LGTM! Clean unmount implementation.The function properly handles cleanup of both components and stores.
lib/react_on_rails/configuration.rb (3)
22-23
: LGTM! Clear configuration defaults with good documentation.The new RSC-related configuration options are well-integrated with clear defaults and helpful comments explaining their purpose.
Also applies to: 48-52
146-152
: LGTM! Robust validation for component registry timeout.The validation logic is thorough, ensuring the timeout is a positive integer and providing a clear error message.
265-270
: LGTM! Clean implementation of webpack files handling.The implementation follows Ruby best practices by using
compact_blank
to filter out empty values, and the RSC files are properly integrated into the list of webpack-generated files.node_package/tests/RSCClientRoot.test.jsx (5)
1-18
: LGTM! Comprehensive test setup.The test setup includes all necessary mocks and imports for testing RSC functionality.
19-21
: LGTM! Well-handled version compatibility.Good practice to conditionally run RSC tests based on Node.js version compatibility.
39-49
: Add more error scenarios.Consider adding more error cases to improve test coverage.
Add test cases for:
- Network failures
- Malformed server responses
- Timeout scenarios
84-105
: LGTM! Thorough progressive rendering test.The test effectively verifies all stages of component rendering and state transitions.
138-153
: LGTM! Good URL path handling test.The test effectively verifies URL path normalization and fetch behavior.
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
Outdated
Show resolved
Hide resolved
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
🔭 Outside diff range comments (1)
node_package/src/streamServerRenderedReactComponent.ts (1)
180-217
: 🛠️ Refactor suggestionImprove type safety in error handling.
While the generic types improve flexibility, the type casting in error handling could be unsafe.
Consider making the error case type-safe:
-return stringToStream(jsonResult) as T; +return renderStrategy( + // Create an error boundary component or similar + createErrorElement(htmlResult), + options +);
🧹 Nitpick comments (1)
node_package/src/streamServerRenderedReactComponent.ts (1)
20-91
: LGTM! Well-designed stream buffering implementation.The implementation effectively solves error handling and event ordering issues. The comprehensive JSDoc clearly explains the purpose and benefits.
Fix typo in type name:
-type BufferdEvent = { +type BufferedEvent = {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
node_package/src/streamServerRenderedReactComponent.ts
(5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: dummy-app-integration-tests (newest)
- GitHub Check: dummy-app-integration-tests (oldest)
🔇 Additional comments (2)
node_package/src/streamServerRenderedReactComponent.ts (2)
93-128
: LGTM! Improved error handling with bufferStream.The changes enhance error handling while maintaining the core transformation logic. Making the function exportable improves reusability.
220-222
: LGTM! Clean backward compatibility wrapper.The wrapper function effectively maintains the existing API while leveraging the new flexible rendering strategy approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
node_package/src/streamServerRenderedReactComponent.ts (1)
93-128
: 🛠️ Refactor suggestionPrevent potential memory leaks in stream transformation.
The stream transformation logic should ensure proper cleanup of resources:
- The
pipedStream
reference should be cleared after aborting- Event listeners should be removed in error cases
const endStream = () => { transformStream.end(); - pipedStream?.abort(); + if (pipedStream) { + pipedStream.abort(); + pipedStream = null; + } + transformStream.removeAllListeners(); }
🧹 Nitpick comments (2)
node_package/src/streamServerRenderedReactComponent.ts (2)
20-23
: Fix typo in type name.The type name has a typo: "BufferdEvent" should be "BufferedEvent".
-type BufferdEvent = { +type BufferedEvent = { event: 'data' | 'error' | 'end'; data: unknown; }
40-91
: Consider improving type safety of the buffer stream implementation.The implementation is robust and well-documented. However, the
data
field could be more strongly typed based on the event type to prevent potential type-related issues.-type BufferdEvent = { - event: 'data' | 'error' | 'end'; - data: unknown; -} +type BufferedEvent = + | { event: 'data'; data: Buffer | string } + | { event: 'error'; data: Error } + | { event: 'end'; data: undefined };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
(3 hunks)node_package/src/streamServerRenderedReactComponent.ts
(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: rspec-package-tests (newest)
- GitHub Check: examples (newest)
- GitHub Check: build
- GitHub Check: build-dummy-app-webpack-test-bundles (oldest)
- GitHub Check: rspec-package-tests (oldest)
🔇 Additional comments (2)
node_package/src/streamServerRenderedReactComponent.ts (2)
180-184
: LGTM! Well-defined generic type for stream renderer.The
StreamRenderer
type is well-defined and provides good type safety for different rendering strategies.
220-222
: LGTM! Good backward compatibility.The wrapper function maintains the original interface while leveraging the new generic implementation.
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)
docs/guides/streaming-server-rendering.md (2)
1-3
: Ensure Consistent React Version Referencing in Title and Content.
The document title and introductory paragraph still reference React 18, while the prerequisites and later sections have been updated to React 19. It is recommended to update the title (and any introductory references) to reflect React 19 consistently across the document.
7-9
: Confirm Prerequisites Update for React Version.
The prerequisites section now lists "React 19" (line 8). Please verify that all related documentation and setup instructions throughout the guide reflect this new requirement and that there is no conflicting reference to React 18 elsewhere in the document.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (4)
docs/guides/streaming-server-rendering.md
(2 hunks)jest.config.js
(1 hunks)node_package/src/RSCClientRoot.ts
(1 hunks)node_package/tests/RSCClientRoot.test.jsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- node_package/src/RSCClientRoot.ts
- node_package/tests/RSCClientRoot.test.jsx
- jest.config.js
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: dummy-app-integration-tests (newest)
- GitHub Check: dummy-app-integration-tests (oldest)
- GitHub Check: rspec-package-tests (newest)
- GitHub Check: rspec-package-tests (oldest)
- GitHub Check: build
🔇 Additional comments (2)
docs/guides/streaming-server-rendering.md (2)
22-25
: Validate Updated Guidance on React Version Usage.
The added steps ("1. Use React 19 Version" and the instruction to update package.json, lines 22–25) clearly promote the usage of React 19. Please ensure that downstream documentation and example projects are updated accordingly and tested with React 19.
27-31
: Check Dependency Versions in the Example.
The JSON code snippet now specifies"react": "19.0.0"
and"react-dom": "19.0.0"
. Confirm that these versions are stable releases for your use case and that any potential migration issues are addressed in your release notes or upgrade documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
knip.ts (1)
11-11
:⚠️ Potential issueFix RSCWebpackLoader extension.
The RSCWebpackLoader should be referenced with
.js
extension as it's maintained as a JavaScript file.- 'node_package/src/RSCWebpackLoader.ts!', + 'node_package/src/RSCWebpackLoader.js!',
🧹 Nitpick comments (2)
node_package/src/registerServerComponent/server.ts (1)
33-35
: Consider adding validation for component implementations.While the current implementation is correct, consider adding validation to ensure that the provided components are valid RSC implementations.
const registerServerComponent = (components: { [id: string]: ReactComponent }) => { + // Validate that components are valid RSC implementations + Object.entries(components).forEach(([name, component]) => { + if (typeof component !== 'function') { + throw new Error(`Invalid server component "${name}". Expected a function, got ${typeof component}`); + } + }); ReactOnRails.register(components); };knip.ts (1)
38-38
: Add explanation for ignoring jsdom dependency.Following the pattern of other ignored dependencies, add a comment explaining why jsdom is being ignored.
'eslint-plugin-jsx-a11y', 'eslint-plugin-react', - 'jsdom', + // jsdom is only used in test files and not directly imported in source + 'jsdom',
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
knip.ts
(2 hunks)lib/react_on_rails/packs_generator.rb
(2 hunks)node_package/src/registerServerComponent/client.ts
(1 hunks)node_package/src/registerServerComponent/server.ts
(1 hunks)package.json
(2 hunks)spec/dummy/spec/packs_generator_spec.rb
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
🔇 Additional comments (8)
lib/react_on_rails/packs_generator.rb (4)
47-82
: LGTM! Robust implementation for parsing JavaScript content.The function correctly handles various edge cases including empty content, different comment types, whitespace, and unclosed comments. The complexity is justified by the nature of the task, and the implementation is well-tested.
84-88
: LGTM! Clean implementation for detecting client entry points.The function correctly identifies client entry points by checking for the "use client" directive, handling both single and double quotes, and properly managing comments through
first_js_statement_in_code
.
90-115
: LGTM! Well-structured implementation for RSC support.The function correctly handles both server and client components based on configuration and entry point status. The implementation aligns with React Server Components requirements.
124-139
: LGTM! Clean implementation for server pack content generation.The function correctly handles component registration for both server and client components, with proper separation of concerns.
spec/dummy/spec/packs_generator_spec.rb (2)
450-662
: LGTM! Comprehensive test coverage for JavaScript content parsing.The test suite thoroughly covers all edge cases including:
- Simple content
- Single-line comments
- Multi-line comments
- Mixed comments
- Whitespace handling
- Empty content
- Comment-like strings
- Unclosed comments
- Nested comments
- Directives
664-746
: LGTM! Thorough test coverage for client entry point detection.The test suite comprehensively covers:
- Double and single quoted directives
- Directives with/without semicolons
- Directives with trailing whitespace
- Directives with preceding comments
- Various negative cases
node_package/src/registerServerComponent/server.ts (1)
4-32
: LGTM! Well-documented with clear future plans.The documentation clearly explains the current behavior and future plans for RSC-specific functionality, making it easier for developers to understand and adapt to future changes.
node_package/src/registerServerComponent/client.ts (1)
9-40
: LGTM! Comprehensive documentation with clear examples.The documentation effectively explains the RSC payload fetching process and the benefits of this approach.
const registerServerComponent = (options: RegisterServerComponentOptions, ...componentNames: string[]) => { | ||
const componentsWrappedInRSCClientRoot: Record<string, ReactComponentOrRenderFunction> = {}; | ||
for (const name of componentNames) { | ||
componentsWrappedInRSCClientRoot[name] = (componentProps?: unknown, _railsContext?: RailsContext, domNodeId?: string) => RSCClientRoot({ | ||
componentName: name, | ||
rscPayloadGenerationUrlPath: options.rscPayloadGenerationUrlPath, | ||
componentProps, | ||
}, _railsContext, domNodeId); | ||
} | ||
ReactOnRails.register(componentsWrappedInRSCClientRoot); | ||
}; |
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.
Add URL path validation to prevent path traversal.
The current implementation might be vulnerable to path traversal attacks if component names contain malicious characters.
const registerServerComponent = (options: RegisterServerComponentOptions, ...componentNames: string[]) => {
+ // Validate URL path to prevent path traversal
+ if (!options.rscPayloadGenerationUrlPath.startsWith('/')) {
+ throw new Error('rscPayloadGenerationUrlPath must start with "/"');
+ }
+
const componentsWrappedInRSCClientRoot: Record<string, ReactComponentOrRenderFunction> = {};
for (const name of componentNames) {
+ // Validate component name to prevent path traversal
+ if (!/^[\w-]+$/.test(name)) {
+ throw new Error(`Invalid component name "${name}". Only alphanumeric characters, underscores, and hyphens are allowed.`);
+ }
+
componentsWrappedInRSCClientRoot[name] = (componentProps?: unknown, _railsContext?: RailsContext, domNodeId?: string) => RSCClientRoot({
componentName: name,
rscPayloadGenerationUrlPath: options.rscPayloadGenerationUrlPath,
componentProps,
}, _railsContext, domNodeId);
}
ReactOnRails.register(componentsWrappedInRSCClientRoot);
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const registerServerComponent = (options: RegisterServerComponentOptions, ...componentNames: string[]) => { | |
const componentsWrappedInRSCClientRoot: Record<string, ReactComponentOrRenderFunction> = {}; | |
for (const name of componentNames) { | |
componentsWrappedInRSCClientRoot[name] = (componentProps?: unknown, _railsContext?: RailsContext, domNodeId?: string) => RSCClientRoot({ | |
componentName: name, | |
rscPayloadGenerationUrlPath: options.rscPayloadGenerationUrlPath, | |
componentProps, | |
}, _railsContext, domNodeId); | |
} | |
ReactOnRails.register(componentsWrappedInRSCClientRoot); | |
}; | |
const registerServerComponent = (options: RegisterServerComponentOptions, ...componentNames: string[]) => { | |
// Validate URL path to prevent path traversal | |
if (!options.rscPayloadGenerationUrlPath.startsWith('/')) { | |
throw new Error('rscPayloadGenerationUrlPath must start with "/"'); | |
} | |
const componentsWrappedInRSCClientRoot: Record<string, ReactComponentOrRenderFunction> = {}; | |
for (const name of componentNames) { | |
// Validate component name to prevent path traversal | |
if (!/^[\w-]+$/.test(name)) { | |
throw new Error(`Invalid component name "${name}". Only alphanumeric characters, underscores, and hyphens are allowed.`); | |
} | |
componentsWrappedInRSCClientRoot[name] = (componentProps?: unknown, _railsContext?: RailsContext, domNodeId?: string) => | |
RSCClientRoot({ | |
componentName: name, | |
rscPayloadGenerationUrlPath: options.rscPayloadGenerationUrlPath, | |
componentProps, | |
}, _railsContext, domNodeId); | |
} | |
ReactOnRails.register(componentsWrappedInRSCClientRoot); | |
}; |
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 (6)
node_package/src/RSCWebpackPlugin.ts (2)
13-19
: Add JSDoc comments to document the Options type.While the field names are self-explanatory, adding JSDoc comments would improve documentation and help users understand the purpose of each option.
export type Options = { + /** Whether the plugin is running in server mode */ isServer: boolean, + /** Client reference paths for RSC */ clientReferences?: ClientReferencePath | ReadonlyArray<ClientReferencePath>, + /** Name of the chunk for client references */ chunkName?: string, + /** Filename for the client manifest */ clientManifestFilename?: string, + /** Filename for the server consumer manifest */ serverConsumerManifestFilename?: string, };
21-33
: Add error handling for invalid options.While the implementation is correct, consider adding validation for required options and error handling:
export class RSCWebpackPlugin { private plugin?: RSCWebpackPluginLib; constructor(options: Options) { + if (!options) { + throw new Error('RSCWebpackPlugin: options are required'); + } + if (!options.isServer) { + if (!options.clientReferences) { + throw new Error('RSCWebpackPlugin: clientReferences is required in client mode'); + } this.plugin = new RSCWebpackPluginLib(options); } } apply(compiler: Compiler) { this.plugin?.apply(compiler); } }knip.ts (1)
39-39
: Add explanation comment for jsdom.Following the pattern of other entries, add a comment explaining why jsdom is being ignored.
+ // Used only in test environment 'jsdom',
node_package/types/react-server-dom-webpack.d.ts (3)
18-39
: Consider adding type parameters for the RSC modelEnriching
renderToPipeableStream
with a generic type parameter for themodel
argument can improve type safety and reduce the need for casting. This aligns with the approach in upstream React codebases for React Server Components.
41-46
: Revisit type constraints for the generic parameterCurrently,
createFromFetch<T>
andcreateFromReadableStream<T>
use unconstrained generic types. Clarifying the shape of data returned by the stream or fetch promise can provide better type safety and user guidance.
47-54
: Refine the plugin constructor’s “options” typeDeclaring
options: unknown
provides no compile-time safety. Where possible, create a dedicated interface or type alias reflecting valid plugin configurations.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (4)
knip.ts
(2 hunks)node_package/src/RSCWebpackPlugin.ts
(1 hunks)node_package/types/react-server-dom-webpack.d.ts
(1 hunks)package.json
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: dummy-app-integration-tests (newest)
- GitHub Check: dummy-app-integration-tests (oldest)
🔇 Additional comments (4)
node_package/src/RSCWebpackPlugin.ts (1)
1-11
: LGTM! Well-structured type definitions.The imports are appropriate, and the type definitions provide good type safety for configuring client reference search paths.
knip.ts (2)
11-11
: Use .js extension for RSCWebpackLoader.The RSCWebpackLoader is maintained as a JavaScript file and should be referenced with the .js extension.
- 'node_package/src/RSCWebpackLoader.ts!', + 'node_package/src/RSCWebpackLoader.js!',
17-23
: LGTM! Comprehensive project configuration.The configuration correctly includes both .ts and .tsx files, and appropriately ignores test files.
node_package/types/react-server-dom-webpack.d.ts (1)
1-16
: Ensure type declarations are included in TSConfigThis file may not yet be referenced in your TS configuration, which could cause build or IDE type-checking issues.
Adding"node_package/types/**/*"
to your"include"
array intsconfig.json
(as previously recommended) is essential for ensuring these definitions are properly recognized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (2)
node_package/src/RSCClientRoot.ts (2)
51-73
: Consider improving error handling for component props.While the function handles DOM-related errors well, it might be good to validate
componentProps
before serialization.const RSCClientRoot: RenderFunction = async ({ componentName, rscPayloadGenerationUrlPath, componentProps, }: RSCClientRootProps, _railsContext?: RailsContext, domNodeId?: string) => { + if (componentProps !== undefined && typeof componentProps !== 'object') { + throw new Error('RSCClientRoot: componentProps must be an object if provided'); + } const root = await fetchRSC({ componentName, rscPayloadGenerationUrlPath, componentProps }) if (!domNodeId) { throw new Error('RSCClientRoot: No domNodeId provided'); }
32-36
: Enhance URL construction and props serialization.Consider these improvements:
- URL-encode the props string to handle special characters.
- Use URL constructor for safer path handling.
const fetchRSC = ({ componentName, rscPayloadGenerationUrlPath, componentProps }: RSCClientRootProps) => { - const propsString = JSON.stringify(componentProps); - const strippedUrlPath = rscPayloadGenerationUrlPath.replace(/^\/|\/$/g, ''); - return createFromFetch(fetch(`/${strippedUrlPath}/${componentName}?props=${propsString}`)); + const propsString = encodeURIComponent(JSON.stringify(componentProps)); + const url = new URL(componentName, new URL(rscPayloadGenerationUrlPath, window.location.origin)); + url.searchParams.set('props', propsString); + return createFromFetch(fetch(url)); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (6)
jest.config.js
(1 hunks)knip.ts
(2 hunks)node_package/src/RSCClientRoot.ts
(1 hunks)node_package/src/ReactOnRailsRSC.ts
(1 hunks)package.json
(4 hunks)tsconfig.json
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- jest.config.js
🧰 Additional context used
🧠 Learnings (2)
node_package/src/RSCClientRoot.ts (1)
Learnt from: AbanoubGhadban
PR: shakacode/react_on_rails#1644
File: node_package/src/RSCClientRoot.ts:14-17
Timestamp: 2025-02-13T14:30:58.040Z
Learning: Global caches in client-side JavaScript are safe from concurrent access issues due to JavaScript's single-threaded nature, even with async operations, as the event loop ensures sequential execution.
node_package/src/ReactOnRailsRSC.ts (1)
Learnt from: alexeyr-ci
PR: shakacode/react_on_rails#1644
File: node_package/src/ReactOnRailsRSC.ts:87-87
Timestamp: 2024-12-12T13:07:09.929Z
Learning: When handling errors in 'node_package/src/ReactOnRailsRSC.ts', include the error stack in error messages in development and test environments to aid debugging.
🪛 GitHub Actions: Lint JS and Ruby
package.json
[warning] 1-1: Unused devDependencies: webpack
[warning] 1-1: Unused item in ignoreBinaries: nps
[warning] 1-1: Unused item in ignoreDependencies: @babel/runtime
🔇 Additional comments (20)
tsconfig.json (4)
6-8
: Updated Compiler Options for Modern ECMAScript Support
The changes to"lib"
,"module"
, and the addition of"moduleResolution": "bundler"
show a clear move to leverage ES2020 features, aligning with the new React Server Components support. Ensure that your build pipeline and any third‑party tooling are compatible with these options.
13-13
: Upgradetarget
Option to ES2020
Changing the"target"
from"es5"
to"es2020"
allows use of modern JavaScript syntax and optimizations. Make sure that downstream environments and dependencies are compatible with ES2020 outputs.
14-18
: Addition oftypeRoots
for Enhanced Type Resolution
Introducing the"typeRoots"
array, which now includes paths for both the external RSC types and local types, is a robust approach for managing type definitions. Verify that these paths are accurate relative to the project root and that all necessary type definitions are placed there.
20-24
: Expandedinclude
Paths for Comprehensive Compilation
The expansion of the"include"
property to capture additional directories with type definitions (especially related to RSC) ensures that all pertinent source and type files are compiled. This integration is vital for consolidated type checking and maintenance across the project.knip.ts (2)
7-14
: LGTM! Entry points for RSC support look correct.The new entry points for RSC support are properly configured, including the server component registration paths.
15-15
: LGTM! Project patterns now correctly include JSX/TSX files.The project patterns have been updated to include JSX/TSX files, which is necessary for RSC tests.
node_package/src/RSCClientRoot.ts (8)
10-14
: LGTM! React version check is properly implemented.The code correctly verifies React 19's availability by checking for the
use
function.
16-20
: LGTM! Props interface is well-defined.The
RSCClientRootProps
type properly defines the required properties for RSC rendering.
22-30
: LGTM! Stream handling is robust.The
createFromFetch
function properly handles stream creation and error cases.
32-36
: LGTM! URL construction is secure.The
fetchRSC
function safely constructs the URL path and handles props serialization.
10-14
: LGTM! Early React version check.The check for React.use availability ensures early failure with a clear error message if React 19 is not used.
22-30
: LGTM! Robust stream handling.The function includes proper error handling and stream transformation for console log replay.
70-72
: Address TODO regarding RenderFunction return type.The TODO indicates a mismatch between the component's actual behavior (returning void) and the RenderFunction type (expecting string).
Consider:
- Updating the RenderFunction type to allow void returns
- Document why string returns aren't needed for RSC components
51-73
: LGTM! Comprehensive RSC rendering implementation.The component correctly handles:
- DOM node validation
- Hydration vs fresh render scenarios
- Error cases
node_package/src/ReactOnRailsRSC.ts (5)
41-49
: Include error stack in development/test environments.Based on past learnings, include the error stack in non-production environments to aid debugging.
onError: (err) => { const error = convertToError(err); - console.error("Error in RSC stream", error); + const isDevOrTest = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test'; + console.error("Error in RSC stream", isDevOrTest ? error.stack : error); if (throwJsErrors) { emitError(error); } renderState.hasErrors = true; renderState.error = error; }
64-70
: LGTM! Console history cleanup is properly handled.The function ensures console history is cleared in the finally block, preventing memory leaks.
20-25
: LGTM! Simple and effective stream creation.The function correctly uses PassThrough stream for string conversion.
41-44
: Include error stack in development environments.Based on past learnings, include the error stack in development and test environments to aid debugging.
onError: (err) => { const error = convertToError(err); - console.error("Error in RSC stream", error); + const isDevOrTest = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test'; + console.error("Error in RSC stream", isDevOrTest ? error.stack : error); if (throwJsErrors) {
64-70
: LGTM! Proper cleanup in finally block.The function ensures console history is cleared regardless of success or failure.
package.json (1)
47-48
:❓ Verification inconclusive
Verify React 19 compatibility.
The package now depends on React 19, which is required for RSC support. However, ensure all components and tests are compatible with this version.
🌐 Web query:
What is the current status of React 19? Is it stable for production use?
💡 Result:
React 19 has been officially stable since its release in December 2024[2][5][10], with production-ready features and improved backward compatibility compared to previous versions. Here's what developers need to know:
Stability Status
- Officially released on npm with full production support[2][8][10]
- Server Components moved from Canary to stable "Latest" channel[2][6]
- Framework APIs for Server Components remain unstable (may break between minors)[2]
Key Stable Features
Actions API
Simplifies async operations with automatic pending states/error handling[4][7][8]async function submitForm(formData) { 'use action'; await saveFormData(formData); }Enhanced Hooks
useActionState
for form status tracking[4][5]useOptimistic
for UI updates during async ops[4][7]use
hook for promise/context resolution[4]Performance Improvements
- Automatic compiler optimizations[1][5]
- Suspense improvements with pre-warmed trees[10]
- Async script loading support[10]
Migration Considerations
- Breaking changes from React 18 require code updates:
- Removed legacy APIs like
propTypes
[4]- New ref handling without
forwardRef
[4][5]- Recommended upgrade path via official migration guide[10]
Production Recommendations
✔️ Safe for new projects with modern tooling
✔️ Enterprise-ready with major companies adopting
⚠️ Framework users (Next.js etc.) should verify compatibility
⚠️ Legacy codebases may require significant refactoringThe React team emphasizes using frameworks rather than raw React for complex apps[2], but core library stability is confirmed through extensive testing and real-world adoption since December 2024[5][8].
Citations:
- 1: https://dev.to/sovannaro/react-18-vs-react-19-key-differences-to-know-for-2025-1614
- 2: https://devclass.com/2024/12/10/react-19-is-stable-team-directs-devs-towards-frameworks-especially-next-js/
- 3: https://dev.to/manojspace/react-18-vs-react-19-key-differences-and-migration-tips-18op
- 4: https://reactnative.dev/blog/2025/02/19/react-native-0.78
- 5: https://dev.to/sahilshityalkar/9-is-react-19-stable-or-is-the-next-big-update-coming-soon-3da4
- 6: https://www.epicweb.dev/tips/whats-coming-in-react-19-beta
- 7: https://blog.alexcloudstar.com/a-deep-dive-into-react-19-new-features-improvements-and-best-practices
- 8: https://www.youtube.com/watch?v=hTxQU2hE0pc
- 9: https://www.youtube.com/watch?v=rwC7HY8_U_g
- 10: https://react.dev/blog/2024/12/05/react-19
Confirm React 19 Stability & Verify Compatibility
React 19 has been production-ready and stable since its December 2024 release. Since the upgrade to React 19 (and corresponding react-dom version) is primarily to support RSC, please ensure that:
- Component Compatibility: All UI components are tested for compatibility with React 19, especially those leveraging Server Components.
- Test Coverage: Verify that existing tests account for any breaking changes (e.g., removed legacy APIs) introduced with React 19.
- Framework APIs: While core React is stable, double-check any framework API usage that might still be in flux.
package.json
Outdated
"typescript": "^5.6.2", | ||
"webpack": "^5.97.1" |
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.
🛠️ Refactor suggestion
Remove unused webpack dependency.
The pipeline indicates that the webpack dependency is unused. Consider removing it if it's not directly required.
- "webpack": "^5.97.1"
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"typescript": "^5.6.2", | |
"webpack": "^5.97.1" | |
"typescript": "^5.6.2" |
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" | ||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e", | ||
"dependencies": { | ||
"@shakacode-tools/react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#main" |
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.
🛠️ Refactor suggestion
Consider using a specific version instead of main branch.
Using the main branch of react-on-rails-rsc
could lead to unexpected breaking changes. Consider using a specific version or commit hash.
- "@shakacode-tools/react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#main"
+ "@shakacode-tools/react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#v1.0.0"
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"@shakacode-tools/react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#main" | |
"@shakacode-tools/react-on-rails-rsc": "git+https://github.com/shakacode/react_on_rails_rsc.git#v1.0.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
node_package/src/ReactOnRailsRSC.ts (2)
41-49
: 🛠️ Refactor suggestionEnhance error logging in development/test environments.
Based on past learnings, include the error stack in development and test environments to aid debugging.
onError: (err) => { const error = convertToError(err); - console.error("Error in RSC stream", error); + const isDevOrTest = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test'; + console.error("Error in RSC stream", isDevOrTest ? error.stack : error); if (throwJsErrors) { emitError(error); } renderState.hasErrors = true; renderState.error = error; }
53-60
: 🛠️ Refactor suggestionEnhance error handling in manifest loading.
Apply consistent error handling improvements to manifest loading errors.
}).catch((e) => { const error = convertToError(e); + const isDevOrTest = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test'; + console.error("Error loading manifest", isDevOrTest ? error.stack : error); renderState.hasErrors = true; renderState.error = error; const htmlResult = handleError({ e: error, name: options.name, serverSide: true }); const jsonResult = JSON.stringify(createResultObject(htmlResult, buildConsoleReplay(), renderState)); return stringToStream(jsonResult); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (4)
jest.config.js
(1 hunks)node_package/src/RSCClientRoot.ts
(1 hunks)node_package/src/ReactOnRailsRSC.ts
(1 hunks)package.json
(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- jest.config.js
- node_package/src/RSCClientRoot.ts
- package.json
🧰 Additional context used
🧠 Learnings (1)
node_package/src/ReactOnRailsRSC.ts (1)
Learnt from: alexeyr-ci
PR: shakacode/react_on_rails#1644
File: node_package/src/ReactOnRailsRSC.ts:87-87
Timestamp: 2024-12-12T13:07:09.929Z
Learning: When handling errors in 'node_package/src/ReactOnRailsRSC.ts', include the error stack in error messages in development and test environments to aid debugging.
⏰ Context from checks skipped due to timeout of 90000ms (7)
- GitHub Check: examples (newest)
- GitHub Check: build-dummy-app-webpack-test-bundles (newest)
- GitHub Check: rspec-package-tests (newest)
- GitHub Check: build-dummy-app-webpack-test-bundles (oldest)
- GitHub Check: rspec-package-tests (oldest)
- GitHub Check: build
- GitHub Check: examples (oldest)
🔇 Additional comments (5)
node_package/src/ReactOnRailsRSC.ts (5)
20-25
: Utility function for string to stream conversion looks good.The
stringToStream
utility correctly converts a string to a readable stream using PassThrough.
27-33
: RSC component streaming implementation looks well structured.The function signature and initial setup for the RSC rendering is clear with proper typing. The renderState object is appropriately initialized with the necessary properties for tracking the rendering process.
35-35
: Good use of existing transform utility for stream processing.Leveraging the existing
transformRenderStreamChunksToResultObject
utility shows good code reuse.
64-70
:serverRenderRSCReactComponent
function looks good.The function performs server-side rendering for React components and includes proper cleanup of the console history in a finally block, ensuring it runs regardless of success or failure.
72-73
: Well-organized exports.The file correctly exports all types and the updated ReactOnRails object, maintaining a clean module interface.
node_package/src/ReactOnRailsRSC.ts
Outdated
@@ -0,0 +1,73 @@ | |||
import { renderToPipeableStream } from 'temproal-package-no-one-cares-about1/server.node'; |
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.
Suspicious package name in import statement.
The package name temproal-package-no-one-cares-about1/server.node
appears to be a placeholder or temporary name that shouldn't be in production code. Consider replacing it with the actual package name for RSC rendering.
-import { renderToPipeableStream } from 'temproal-package-no-one-cares-about1/server.node';
+import { renderToPipeableStream } from 'react-dom/server.node';
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
import { renderToPipeableStream } from 'temproal-package-no-one-cares-about1/server.node'; | |
import { renderToPipeableStream } from 'react-dom/server.node'; |
f63d8a8
to
713d33b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
node_package/src/clientStartup.ts (1)
25-47
: Add JSDoc comments for the clientStartup function.The function has been properly updated to be async and the implementation looks good. Consider adding JSDoc comments to explain the purpose and behavior of the function, especially since it's a key entry point.
+/** + * Sets up React on Rails client-side rendering and hydration. + * - Immediately renders and hydrates force-loaded components and stores + * - Sets up listeners for page lifecycle events to handle other components + * @param context The global context (window in browser environments) + * @returns Promise that resolves when setup is complete + */ export async function clientStartup(context: Context): Promise<void> {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
node_package/src/ReactOnRails.ts
(5 hunks)node_package/src/clientStartup.ts
(2 hunks)node_package/src/types/index.ts
(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- node_package/src/ReactOnRails.ts
🧰 Additional context used
🧠 Learnings (1)
node_package/src/clientStartup.ts (1)
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`.
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: rspec-package-tests (newest)
- GitHub Check: rspec-package-tests (oldest)
🔇 Additional comments (15)
node_package/src/clientStartup.ts (5)
1-11
: Good modularization of imports.The updated imports reflect a well-structured architecture with clear separation of concerns. Moving rendering and lifecycle management to dedicated modules improves maintainability.
12-18
: Excellent use of Promise.all for concurrent operations.Converting
reactOnRailsPageLoaded
to an async function with Promise.all for concurrent hydration and rendering is a performance improvement. This approach allows parallel execution of these operations, reducing page load time.
20-23
: Simplified unmounting logic.The function has been appropriately simplified to use the consolidated
unmountAll()
function. Keeping this function private is the right approach as it's only used internally as a callback.
40-43
: Great separation of immediate vs. deferred rendering.This is a good architectural decision to render force-loaded components immediately while deferring others until the page is fully loaded.
44-46
: Don't forget to call debugTurbolinks in renderOrHydrateComponent.While the page lifecycle has been properly set up, ensure the
debugTurbolinks
call is included in the newrenderOrHydrateComponent
equivalent as noted in previous reviews.node_package/src/types/index.ts (10)
2-2
: Clarify the usage of experimental React types.Using experimental React types may potentially introduce instability since these APIs can change in future React versions. Consider adding a comment explaining which specific experimental types are needed for RSC support and why.
I see this was addressed in a previous comment where you explained this adds experimental types needed for React. To further validate, please run:
#!/bin/bash # Check which experimental React types are used in the codebase rg --type=ts "React\.[A-Za-z]+" node_package/src | grep -i experimental
17-17
: Provides timeout control for component registry operations.This new property allows controlling the timeout for component registry operations, which is important for asynchronous RSC component loading.
Ensure this value is properly documented in the Ruby side configuration options and has a reasonable default value.
111-113
: Good implementation of RSC options interface.The
RegisterServerComponentOptions
interface appropriately encapsulates configuration needed for RSC rendering with a clear path parameter for payload generation.
115-115
: Generic callback type enhances component registration flexibility.The
ItemRegistrationCallback<T>
generic type provides a reusable pattern for component and store registration callbacks, promoting consistency across the codebase.
130-132
: RSC params correctly extend render params.The
RSCRenderParams
interface properly extends the baseRenderParams
with the additional client manifest property needed for RSC rendering.
178-178
: Added method for store loading notification.This method allows components to signal when stores are loaded, which complements the asynchronous store retrieval methods added above.
192-192
:✅ Verification successful
Core RSC rendering method with stream support.
This method is essential for streaming RSC rendering results and is properly typed with the specialized RSC params.
Verify test coverage with:
🏁 Script executed:
#!/bin/bash # Check test coverage for serverRenderRSCReactComponent rg "serverRenderRSCReactComponent" "spec/" -A 5 # Look for RSC implementation rg "serverRenderRSCReactComponent" "node_package/src/ReactOnRailsRSC.ts" -A 10Length of output: 386
Core RSC rendering method confirmed and test coverage verified
The
serverRenderRSCReactComponent
method innode_package/src/types/index.ts
is correctly typed using the specializedRSCRenderParams
. Its implementation innode_package/src/ReactOnRailsRSC.ts
—which returns a stream viastreamServerRenderedComponent
—aligns with the expectations. The grep tests confirm the method is present in both the spec files and its concrete implementation.
- Confirmed proper use of
RSCRenderParams
in the type definition.- Verified implementation in
ReactOnRailsRSC.ts
using the provided shell script output.- Test coverage in the spec folder appears adequate.
Approved.
172-173
:✅ Verification successful
Enhanced asynchronous store management APIs.
These methods provide Promise-based store access, which is essential for React Server Components where stores might not be immediately available during rendering.
Run the following to check implementation of these methods:
🏁 Script executed:
#!/bin/bash # Check implementation of store retrieval methods rg "getOrWaitForStore|getOrWaitForStoreGenerator" "node_package/src/ReactOnRails.ts" -A 10Length of output: 864
Asynchronous Store Management API Implementation Verified
The implementations of
getOrWaitForStore
andgetOrWaitForStoreGenerator
innode_package/src/ReactOnRails.ts
correctly delegate to their corresponding methods in theStoreRegistry
, ensuring proper Promise-based asynchronous store access for React Server Components. The code conforms to the expected behavior, and no further changes are necessary.
189-189
:✅ Verification successful
Component retrieval with Promise support.
This asynchronous component retrieval method is crucial for RSC where components might be loaded dynamically or on-demand.
Verify the implementation with:
🏁 Script executed:
#!/bin/bash # Check implementation of getOrWaitForComponent rg "getOrWaitForComponent" "node_package/src/ReactOnRails.ts" -A 10Length of output: 417
Action: Confirm Asynchronous Component Retrieval
The interface definition in
node_package/src/types/index.ts
forgetOrWaitForComponent
remains correct, and the corresponding implementation innode_package/src/ReactOnRails.ts
properly delegates toComponentRegistry.getOrWaitForComponent
, returning aPromise<RegisteredComponent>
as expected. This approach supports dynamic (on-demand) component loading for RSC as intended.
- File:
node_package/src/types/index.ts
(line 189) – Interface is correctly defined.- File:
node_package/src/ReactOnRails.ts
– Implementation properly returns a Promise by callingComponentRegistry.getOrWaitForComponent(name)
.
176-176
:❓ Verification inconclusive
Updated method signature to reflect asynchronous behavior.
Changing the return type from
void
toPromise<void>
correctly reflects that page loading now includes asynchronous operations for RSC support.Verify the implementation with:
🏁 Script executed:
#!/bin/bash # Check implementation of reactOnRailsPageLoaded rg "reactOnRailsPageLoaded.*Promise" "node_package/src/ReactOnRails.ts" -A 10 -B 2Length of output: 82
Verify that the asynchronous update in
reactOnRailsPageLoaded
is correctly implemented
- The type definition was updated in
node_package/src/types/index.ts
toreactOnRailsPageLoaded(): Promise<void>;
, indicating that the function should now perform asynchronous operations.- However, the verification command (
rg "reactOnRailsPageLoaded.*Promise" node_package/src/ReactOnRails.ts -A 10 -B 2
) produced no output. This means we couldn’t automatically confirm that the implementation innode_package/src/ReactOnRails.ts
reflects this change.- Action Required: Please manually inspect or run a more general grep (e.g.,
rg -n "reactOnRailsPageLoaded" node_package/src/ReactOnRails.ts -C 5
) to ensure that the method truly returns a promise and that any asynchronous logic is in place.
Summary
RSC_in_RORP.mp4
Remove this paragraph and provide a general description of the code changes in your pull
request... were there any bugs you had fixed? If so, mention them. If
these bugs have open GitHub issues, be sure to tag them here as well,
to keep the conversation linked together.
Pull Request checklist
Remove this line after checking all the items here. If the item is not applicable to the PR, both check it out and wrap it by
~
.Add the CHANGELOG entry at the top of the file.
Other Information
Remove this paragraph and mention any other important and relevant information such as benchmarks.
This change is
Summary by CodeRabbit
reactHydrateOrRender
method for accuracy in naming conventions.