Skip to content
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

Handle errors happen during streaming components #1648

Open
wants to merge 4 commits into
base: abanoubghadban/pro426-add-support-for-console-replay-while-streaming-component
Choose a base branch
from

Conversation

AbanoubGhadban
Copy link
Collaborator

@AbanoubGhadban AbanoubGhadban commented Aug 26, 2024

Summary

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/update test to cover these changes
  • Update documentation
  • Update CHANGELOG file
    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 Reviewable

Summary by CodeRabbit

  • New Features

    • Introduced streaming capabilities for server-rendered React components.
    • Added functionality to skip initial console messages during replay.
  • Bug Fixes

    • Enhanced error handling during server rendering processes.
  • Documentation

    • Updated test cases to focus on rendered output rather than internal component structure.
  • Chores

    • Upgraded React and its type definitions to the latest version for improved performance and compatibility.
    • Updated Webpack configuration for better browser compatibility with Node.js features.

@AbanoubGhadban AbanoubGhadban changed the base branch from master to abanoubghadban/pro426-add-support-for-console-replay-while-streaming-component August 26, 2024 14:32
Copy link

coderabbitai bot commented Aug 26, 2024

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The changes encompass updates to various configuration files, enhancements to the ReactOnRails helper functionality, and modifications to the testing setup. Key additions include support for streaming React components, improved error handling in server-side rendering, and updates to package dependencies. The adjustments promote a more robust architecture for rendering React components in a Rails environment, alongside enhancements to the testing framework setup.

Changes

File Change Summary
.gitignore Added .idea/ directory to ignore list.
jest.config.js Added setupFiles entry for pre-test setup.
lib/react_on_rails/helper.rb Introduced methods for streaming React components and improved error handling.
lib/react_on_rails/react_component/render_options.rb Added methods for error handling and configuration retrieval.
lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb Enhanced JavaScript execution handling based on streaming options.
node_package/src/ReactOnRails.ts Added streamServerRenderedReactComponent method for server-side rendering.
node_package/src/buildConsoleReplay.ts Modified functions to skip initial messages in console replay.
node_package/src/serverRenderReactComponent.ts Added streamServerRenderedReactComponent function to facilitate streaming.
node_package/src/types/index.ts Updated ReactOnRails interface to include streamServerRenderedReactComponent.
node_package/tests/ReactOnRails.test.js Updated test setup for dynamic HTML structure verification.
node_package/tests/jest.setup.js Established polyfill for TextEncoder and TextDecoder in jsdom environment.
package.json Upgraded React and related type definitions to version 18.2.0.
spec/dummy/config/webpack/alias.js Added alias mapping for stream to stream-browserify.
spec/dummy/config/webpack/commonWebpackConfig.js Added process polyfill for browser compatibility.
spec/dummy/config/webpack/webpackConfig.js Set fallback for stream to stream-browserify in client configuration.
spec/dummy/spec/helpers/react_on_rails_helper_spec.rb Added tests for rails_context_if_not_already_rendered method and included ActionView::Helpers::TagHelper.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Server
    participant ReactComponent

    User->>Server: Request for React Component
    Server->>ReactComponent: Stream React Component
    ReactComponent-->>Server: Return Streamed Output
    Server-->>User: Deliver Streamed HTML
Loading

🐇 In the garden, hopping about,
New features sprout, without a doubt.
Streams of React, flowing with grace,
Errors handled, in their place.
With tests now set, all is bright,
A joyful code, in morning light! 🌼


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?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post

Actionable comments posted: 1

Outside diff range, codebase verification and nitpick comments (2)
lib/react_on_rails/helper.rb (2)

539-543: Remove trailing whitespace.

The new method should_raise_streaming_prerender_error is correctly implemented and integrates well with the existing structure. However, there is trailing whitespace on lines 540, 541, and 605.

Apply this diff to remove the trailing whitespace:

-      chunk_json_result["hasErrors"] && 
+      chunk_json_result["hasErrors"] &&
-        ((render_options.raise_on_prerender_error && !chunk_json_result["isShellReady"]) || 
+        ((render_options.raise_on_prerender_error && !chunk_json_result["isShellReady"]) ||
-      
+
Tools
rubocop

[convention] 540-540: Trailing whitespace detected.

(Layout/TrailingWhitespace)


[convention] 541-541: Trailing whitespace detected.

(Layout/TrailingWhitespace)


601-603: Refactor nested if statement.

Convert if nested inside else to elsif for better readability.

Apply this diff to refactor the nested if statement:

-      else
-        if result["hasErrors"] && render_options.raise_on_prerender_error
+      elsif result["hasErrors"] && render_options.raise_on_prerender_error
Tools
rubocop

[convention] 601-601: Convert if nested inside else to elsif.

(Style/IfInsideElse)

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between bb9a8a2 and 4829dcd.

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 (6 hunks)
  • lib/react_on_rails/react_component/render_options.rb (3 hunks)
  • lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (4 hunks)
  • node_package/src/ReactOnRails.ts (2 hunks)
  • node_package/src/buildConsoleReplay.ts (2 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 (2 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)
  • spec/dummy/spec/helpers/react_on_rails_helper_spec.rb (2 hunks)
Files skipped from review due to trivial changes (1)
  • .gitignore
Additional context used
Biome
node_package/src/buildConsoleReplay.ts

[error] 17-17: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

rubocop
lib/react_on_rails/react_component/render_options.rb

[convention] 134-134: Add empty line after guard clause.

(Layout/EmptyLineAfterGuardClause)

lib/react_on_rails/helper.rb

[convention] 540-540: Trailing whitespace detected.

(Layout/TrailingWhitespace)


[convention] 541-541: Trailing whitespace detected.

(Layout/TrailingWhitespace)


[convention] 601-601: Convert if nested inside else to elsif.

(Style/IfInsideElse)


[convention] 605-605: Trailing whitespace detected.

(Layout/TrailingWhitespace)

Additional comments not posted (30)
jest.config.js (1)

4-4: LGTM!

The addition of the setupFiles array is correctly implemented and enhances the testing environment by allowing pre-test setup tasks.

The code changes are approved.

spec/dummy/config/webpack/alias.js (1)

7-7: LGTM!

The addition of the alias mapping for stream to stream-browserify is correctly implemented and enhances compatibility with browser environments.

The code changes are approved.

node_package/tests/jest.setup.js (1)

1-13: LGTM!

The polyfill setup for TextEncoder and TextDecoder is correctly implemented and ensures compatibility with the jsdom environment.

The code changes are approved.

spec/dummy/config/webpack/webpackConfig.js (1)

7-7: LGTM!

The addition of the fallback for stream to use stream-browserify is correctly implemented to ensure compatibility with certain libraries that expect Node.js-style streams.

The code changes are approved.

node_package/src/buildConsoleReplay.ts (1)

42-43: LGTM!

The function is correctly implemented to accept the new parameter and pass it to consoleReplay.

The code changes are approved.

spec/dummy/config/webpack/commonWebpackConfig.js (1)

44-44: LGTM!

The addition of process: 'process/browser' to the ProvidePlugin is correctly implemented to ensure compatibility with certain libraries that expect the process object to be defined.

The code changes are approved.

package.json (4)

19-19: Verify compatibility with ReactDOM 18.

The upgrade to @types/react-dom version ^18.2.0 may introduce breaking changes and new features. Ensure that the codebase is compatible with ReactDOM 18.

Run the following script to verify the usage of ReactDOM 18 features:


18-18: Verify compatibility with React 18.

The upgrade to @types/react version ^18.2.0 may introduce breaking changes and new features. Ensure that the codebase is compatible with React 18.

Run the following script to verify the usage of React 18 features:


42-42: Verify compatibility with React 18.

The upgrade to react version ^18.2.0 may introduce breaking changes and new features. Ensure that the codebase is compatible with React 18.

Run the following script to verify the usage of React 18 features:

Verification successful

React 18 Compatibility Verified

The codebase does not appear to use any React 18 specific features or deprecated lifecycle methods that could cause compatibility issues. The upgrade to react version ^18.2.0 is likely safe.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of React 18 features.

# Test: Search for React 18 specific features. Expect: No breaking changes.
rg --type js --type ts 'ReactDOM.createRoot'

Length of output: 44


Script:

#!/bin/bash
# Description: Verify compatibility with React 18 by searching for other React 18 features and changes.

# Search for the use of other React 18 specific features.
rg --type js --type ts 'useTransition|useDeferredValue|SuspenseList|startTransition'

# Check for deprecated lifecycle methods that might have been affected by the upgrade.
rg --type js --type ts 'componentWillMount|componentWillReceiveProps|componentWillUpdate'

Length of output: 178


43-43: Verify compatibility with ReactDOM 18.

The upgrade to react-dom version ^18.2.0 may introduce breaking changes and new features. Ensure that the codebase is compatible with ReactDOM 18.

Run the following script to verify the usage of ReactDOM 18 features:

Verification successful

ReactDOM 18 Compatibility Verified with Caution

The codebase uses ReactDOM.hydrateRoot, a React 18 feature, indicating compatibility with React 18. However, ensure that its implementation is correct and does not introduce any issues.

  • node_package/src/clientStartup.ts: Usage of ReactDOM.hydrateRoot.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of ReactDOM 18 features.

# Test: Search for ReactDOM 18 specific features. Expect: No breaking changes.
rg --type js --type ts 'ReactDOM.createRoot'

Length of output: 44


Script:

#!/bin/bash
# Description: Verify the usage of other ReactDOM 18 features and potential breaking changes.

# Test: Search for other ReactDOM 18 specific features and changes.
rg --type js --type ts 'ReactDOM.unstable_' # Check for any usage of unstable features.
rg --type js --type ts 'ReactDOM.flushSync' # Check for usage of flushSync, a new API in React 18.
rg --type js --type ts 'ReactDOM.hydrateRoot' # Check for usage of hydrateRoot, another new API in React 18.

Length of output: 264

lib/react_on_rails/react_component/render_options.rb (3)

90-92: Verify configuration value for non-shell server rendering errors.

The method retrieves a configuration value for non-shell server rendering errors. Ensure that the configuration value is correctly set in the configuration files.

Run the following script to verify the configuration value:


110-112: Verify streaming option.

The method checks the streaming option from the options hash. Ensure that the streaming option is correctly set in the configuration files.

Run the following script to verify the streaming option:


132-137: Verify Pro-specific settings.

The method attempts to fetch configuration values from the options hash and falls back to the ReactOnRailsPro configuration if the react_on_rails_pro? condition is met. Ensure that the Pro-specific settings are accessible when applicable.

Run the following script to verify the Pro-specific settings:

Tools
rubocop

[convention] 134-134: Add empty line after guard clause.

(Layout/EmptyLineAfterGuardClause)

node_package/tests/ReactOnRails.test.js (1)

22-30: Verify impact on other test cases.

The test case has been modified to programmatically create the root div element and validate the text content of the root div instead of the component type. Ensure that the changes do not affect other test cases.

Run the following script to verify the impact on other test cases:

Verification successful

No impact on other test cases.

The changes in ReactOnRails.test.js are isolated to creating a div element and do not affect the test cases in Authenticity.test.js, which involve creating a meta tag for CSRF tokens. There is no shared state or dependency between these test cases.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the impact on other test cases.

# Test: Search for the test cases. Expect: No breaking changes.
rg --type js --type ts 'document.createElement'

Length of output: 220


Script:

#!/bin/bash
# Extract relevant lines from Authenticity.test.js to analyze the usage of document.createElement
rg --type js --type ts -A 5 'document.createElement' node_package/tests/Authenticity.test.js

Length of output: 261

node_package/src/types/index.ts (2)

2-2: LGTM!

The import statement for Readable from the stream module is correctly added.

The code changes are approved.


141-141: LGTM!

The method streamServerRenderedReactComponent is correctly added to the ReactOnRails interface.

The code changes are approved.

node_package/src/serverRenderReactComponent.ts (3)

170-175: LGTM!

The helper function stringToStream is correctly implemented to convert a string to a readable stream using PassThrough.

The code changes are approved.


177-265: LGTM!

The function streamServerRenderedReactComponent is correctly implemented to handle streaming server-rendered React components with proper error handling and logging mechanisms.

The code changes are approved.


267-267: LGTM!

The default export remains unchanged and there are no issues.

The code changes are approved.

lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb (3)

59-63: LGTM!

The conditional logic correctly switches between eval_streaming_js and eval_js based on the stream flag.

The code changes are approved.


79-83: LGTM!

The refactoring to encapsulate the parsing logic in a separate method parse_result_and_replay_console_messages improves code clarity and maintainability.

The code changes are approved.


229-247: LGTM!

The method parse_result_and_replay_console_messages is correctly implemented to handle result parsing and console message replaying.

The code changes are approved.

node_package/src/ReactOnRails.ts (2)

2-2: LGTM!

The import statement has been correctly updated to include streamServerRenderedReactComponent.

The code changes are approved.

Also applies to: 8-8


245-251: LGTM!

The new method streamServerRenderedReactComponent is correctly implemented and integrates well with the existing structure.

The code changes are approved.

spec/dummy/spec/helpers/react_on_rails_helper_spec.rb (2)

10-10: LGTM!

The inclusion of ActionView::Helpers::TagHelper is correctly done.

The code changes are approved.


350-373: LGTM!

The new method rails_context_if_not_already_rendered is correctly implemented and the tests ensure its correct behavior.

The code changes are approved.

lib/react_on_rails/helper.rb (4)

94-114: LGTM!

The new method stream_react_component is correctly implemented and integrates well with the existing structure.

The code changes are approved.


355-363: LGTM!

The new method internal_stream_react_component is correctly implemented and integrates well with the existing structure.

The code changes are approved.


396-420: LGTM!

The new method build_react_component_result_for_server_streamed_content is correctly implemented and integrates well with the existing structure.

The code changes are approved.


529-537: LGTM!

The new method raise_prerender_error is correctly implemented and integrates well with the existing structure.

The code changes are approved.

Comments failed to post (1)
node_package/src/buildConsoleReplay.ts (1)

14-21: Use Array.isArray instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts. Use Array.isArray instead for better compatibility and reliability.

Apply this diff to fix the issue:

-  if (!(console.history instanceof Array)) {
+  if (!Array.isArray(console.history)) {
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.

export function consoleReplay(skipFirstNumberOfMessages: number = 0): string {
  // console.history is a global polyfill used in server rendering.
  // $FlowFixMe
  if (!Array.isArray(console.history)) {
    return '';
  }

  const lines = console.history.slice(skipFirstNumberOfMessages).map(msg => {
Tools
Biome

[error] 17-17: Use Array.isArray() instead of instanceof Array.

instanceof Array returns false for array-like objects and arrays from other execution contexts.
Unsafe fix: Use Array.isArray() instead.

(lint/suspicious/useIsArray)

Copy link
Member

@justin808 justin808 left a comment

Choose a reason for hiding this comment

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

@alexeyr-ci @AbanoubGhadban merge if you guys are confident.

Should I do a release after?

if should_raise_streaming_prerender_error?(chunk_json_result, render_options)
raise_prerender_error(chunk_json_result, react_component_name, props, js_code)
end
# It doesn't make any transformation, it listens to the streamed chunks and raise error if it has errors
Copy link
Collaborator

Choose a reason for hiding this comment

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

"listens and raise_s_ error if one (or 'a chunk') has errors", then.

Comment on lines +225 to +226
// Can't through error here if throwJsErrors is true because the error will happen inside the stream
// And will not be handled by any catch clause
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// Can't through error here if throwJsErrors is true because the error will happen inside the stream
// And will not be handled by any catch clause
// Can't throw an error here if throwJsErrors is true because the error will happen inside the stream
// and will not be handled by any catch clause

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not certain about either, but seems most likely.

// And will not be handled by any catch clause
hasErrors = true;
transformStream.write(handleError({
e: error as any,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why any? Can be FileError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants