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

Add Support for Async Render Functions Returning React Components #1720

Conversation

AbanoubGhadban
Copy link
Collaborator

@AbanoubGhadban AbanoubGhadban commented Mar 31, 2025

Enhanced Support for Async Render Functions Returning React Components

Summary

This PR enhances React on Rails to support async render functions that return React components. This completes the support for all major render function return types in both synchronous and asynchronous contexts.

Feature Details

Async render functions can now return React components directly, enabling a cleaner pattern for components that need to fetch data before rendering:

const MyComponent = async (props, _railsContext) => {
  // Fetch data asynchronously
  const data = await fetchData();
  
  // Return a React component (not an element)
  return () => <div>Hello {data.name}</div>;
};

MyComponent.renderFunction = true;
ReactOnRails.register({ MyComponent });

Then, render it in your Rails view:

<%= react_component("MyComponent", props: { someProps: "value" }) %>

Architectural Advantages

Instead of requiring developers to handle string rendering themselves (by calling renderToString inside their async functions), this approach provides significant flexibility and future-proofing:

  • Rendering Flexibility: Users can decide to render the component in a single shot by calling react_component helper function or stream it by calling stream_react_component without creating different implementations for each component
  • Rendering Control: React on Rails can apply optimized rendering strategies uniformly across all components
  • Future Compatibility: This approach is crucial for completing React Server Components integration with React on Rails, as it maintains a clean separation between component definition and rendering strategy

Related Documentation

This feature completes the "Return Type 6: Promises of React Components" pattern described in our documentation.

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

  • Documentation

    • Introduced a comprehensive guide on using render functions with detailed explanations, examples, and clear usage instructions.
  • New Features

    • Enabled asynchronous render functions to return React components, enhancing rendering flexibility.
    • Improved streaming support to better handle various render outputs for a smoother experience.
  • Bug Fixes

    • Streamlined error handling to produce clearer error messages and removed deprecated configuration options for enhanced reliability.

Copy link
Contributor

coderabbitai bot commented Mar 31, 2025

Walkthrough

The update introduces a new documentation guide on render functions in React on Rails and adjusts multiple source modules to improve type flexibility, error handling, and asynchronous processing during server rendering. Changes include updates to method signatures, new helper functions, refined type definitions, and expanded tests. Additionally, modifications to streaming error reporting and ESLint configuration help streamline rendering workflows.

Changes

File(s) Change Summary
docs/javascript/render-functions.md Added new documentation detailing render function usage, parameters, return types, and integration with Rails helper methods.
node_package/src/ReactOnRailsRSC.ts
node_package/src/streamServerRenderedReactComponent.ts
Updated method signatures to accept StreamableComponentResult instead of ReactElement, and improved async handling using Promise.all and refined error reporting via new helper functions.
node_package/src/createReactOutput.ts Introduced createReactElementFromRenderFunctionResult to streamline handling render function results and simplified promise handling in createReactOutput.
node_package/src/handleError.ts Added a conditional check to ensure renderToString exists before usage, preventing runtime errors.
node_package/src/isServerRenderResult.ts Broadened parameter types for isServerRenderHash and isPromise to include RenderFunctionResult and related types.
node_package/src/serverRenderReactComponent.ts Modified type inference in processServerRenderHash, added processReactElement, and updated processPromise to handle asynchronous React elements.
node_package/src/types/index.ts Introduced new types (ServerRenderHashRenderedHtml, FinalHtmlResult, RSCPayloadChunk, RenderStateHtml) and restructured output types for better clarity.
node_package/src/serverRenderUtils.ts
node_package/src/transformRSCStreamAndReplayConsoleLogs.ts
Refined type usage in utility functions by incorporating FinalHtmlResult and RSCPayloadChunk.
node_package/tests/serverRenderReactComponent.test.ts
node_package/tests/streamServerRenderedReactComponent.test.jsx
Expanded tests with additional type assertions, new test cases for varied rendering scenarios, and enhanced error message checks.
eslint.config.ts Extended the allowDefaultProject array to include test files for improved TypeScript parsing.
CHANGELOG.md Documented the new async React component support and the deprecation of outdated configuration options.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant S as Streaming Renderer
    participant P as Promise Resolver
    participant R as ReactDOMServer
    participant E as Error Handler

    C->>S: Request streaming render
    S->>P: Resolve reactRenderingResult
    P-->>S: Return resolved value (React element or string)
    alt Resolved value is a valid React element
        S->>R: Render element via processReactElement
        R-->>S: Return rendered HTML
        S-->>C: Stream rendered HTML
    else Resolved value is an error or string
        S->>E: Invoke reportError/sendErrorHtml
        E-->>S: Provide error HTML response
        S-->>C: Stream error HTML
    end
Loading

Possibly related PRs

  • Add support for RSC #1644: Adds React Server Components support with changes relevant to handling render functions and component management within the framework.

Suggested reviewers

  • Judahmeek

Poem

I'm a little rabbit, hopping through the code,
Skipping through async streams on a bright new road.
With render functions and error checks in sight,
I nibble on logic from morning 'til night.
Happy hops, dear coders, in our React on Rails delight!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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>, please review it.
    • 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 gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @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 generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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.

@AbanoubGhadban AbanoubGhadban marked this pull request as ready for review March 31, 2025 15:51
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
docs/javascript/render-functions.md (2)

101-110: Remove trailing colons in headings

The headings "When to use:" and similar headings throughout the document have trailing punctuation which should be removed according to markdown best practices.

-#### When to use:
+#### When to use
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

101-101: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


107-107: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


147-149: Consider using consistent formatting for requirements

The requirements section uses hyphens that could be misinterpreted as "and" vs "or". Consider using consistent formatting or explicit conjunctions.

-#### Requirements:
+#### Requirements

-The render function MUST return an object
-The object MUST include a `componentHtml` key
-All other keys are optional and can be accessed in your Rails view
+The render function MUST return an object.
+The object MUST include a `componentHtml` key.
+All other keys are optional and can be accessed in your Rails view.
🧰 Tools
🪛 LanguageTool

[misspelling] ~147-~147: Did you mean “and”?
Context: ...nts: - The render function MUST return an object - The object MUST include a `com...

(AN_AND)

node_package/src/serverRenderReactComponent.ts (1)

47-56: Log the original error details for better debugging.

This block catches rendering errors and logs a message. Logging the error’s stack (or relevant details) can be invaluable for diagnosing issues unrelated to double render calls.

Add the original error details alongside the custom message:

} catch (error) {
  console.error(
    `Invalid call to renderToString. Possibly you have a renderFunction, a function that already
calls renderToString, that takes one parameter. You need to add an extra unused parameter to identify this function
as a renderFunction and not a simple React Function Component.`,
+   error
  );
  throw error;
}
node_package/tests/streamServerRenderedReactComponent.test.jsx (1)

63-97: Use of componentType adds clarity to test coverage.

This switch-based approach for registering different component types effectively tests all sync/async error and success paths. Consider refactoring repeated error-throwing stubs to reduce duplication, but overall functionality looks good.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74dc30b and ffc7653.

📒 Files selected for processing (11)
  • docs/javascript/render-functions.md (1 hunks)
  • node_package/src/ReactOnRailsRSC.ts (2 hunks)
  • node_package/src/createReactOutput.ts (2 hunks)
  • node_package/src/handleError.ts (1 hunks)
  • node_package/src/isServerRenderResult.ts (2 hunks)
  • node_package/src/serverRenderReactComponent.ts (2 hunks)
  • node_package/src/streamServerRenderedReactComponent.ts (4 hunks)
  • node_package/src/types/index.ts (1 hunks)
  • node_package/tests/serverRenderReactComponent.test.js (0 hunks)
  • node_package/tests/serverRenderReactComponent.test.ts (1 hunks)
  • node_package/tests/streamServerRenderedReactComponent.test.jsx (6 hunks)
💤 Files with no reviewable changes (1)
  • node_package/tests/serverRenderReactComponent.test.js
🧰 Additional context used
🧬 Code Definitions (5)
node_package/src/ReactOnRailsRSC.ts (2)
node_package/src/types/index.ts (1)
  • RSCRenderParams (143-145)
node_package/src/loadReactClientManifest.ts (1)
  • loadReactClientManifest (7-24)
node_package/src/isServerRenderResult.ts (1)
node_package/src/types/index.ts (3)
  • CreateReactOutputResult (105-105)
  • RenderFunctionResult (102-102)
  • ServerRenderResult (106-106)
node_package/src/streamServerRenderedReactComponent.ts (3)
node_package/src/types/index.ts (1)
  • RenderParams (137-141)
node_package/src/ReactOnRails.client.ts (1)
  • handleError (302-306)
node_package/src/serverRenderUtils.ts (1)
  • convertToError (20-22)
node_package/src/createReactOutput.ts (1)
node_package/src/isServerRenderResult.ts (2)
  • isServerRenderHash (3-12)
  • isPromise (14-18)
node_package/tests/serverRenderReactComponent.test.ts (1)
node_package/src/types/index.ts (6)
  • RenderParams (137-141)
  • RenderResult (163-169)
  • RenderFunction (101-101)
  • RailsContext (17-35)
  • ServerRenderResult (106-106)
  • RenderFunctionResult (102-102)
🪛 GitHub Actions: Lint JS and Ruby
node_package/tests/serverRenderReactComponent.test.ts

[error] 1-1: Parsing error: /home/runner/work/react_on_rails/react_on_rails/node_package/tests/serverRenderReactComponent.test.ts was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject.

🪛 LanguageTool
docs/javascript/render-functions.md

[uncategorized] ~79-~79: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...bjects without a renderedHtml property and they will still work. ## Ruby Helper F...

(COMMA_COMPOUND_SENTENCE)


[style] ~136-~136: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...le HTML strings in an object - When you need to insert rendered content in different pa...

(REP_NEED_TO_VB)


[misspelling] ~147-~147: Did you mean “and”?
Context: ...nts: - The render function MUST return an object - The object MUST include a `com...

(AN_AND)


[uncategorized] ~155-~155: Loose punctuation mark.
Context: ...es errors - either use JSX or wrap in a { renderedHtml: '...' } object. 3. **Async Functions Work wit...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)
docs/javascript/render-functions.md

101-101: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


107-107: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


133-133: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


140-140: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


145-145: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🔇 Additional comments (49)
node_package/src/handleError.ts (2)

63-66: Good defensive programming to handle undefined renderToString

This change adds a check to ensure ReactDOMServer.renderToString is a function before attempting to call it. This prevents potential runtime errors if renderToString is unavailable in certain environments or scenarios.


63-66: Good defensive programming technique!

This added check ensures the code handles situations where ReactDOMServer.renderToString might not be available as a function, preventing potential runtime errors. This makes the error handling more robust across different environments.

node_package/src/createReactOutput.ts (8)

5-23: Good extraction of render function result handling logic

The new createReactElementFromRenderFunctionResult function cleanly encapsulates the logic for processing render function results. The warning about returning JSX directly helps guide developers toward the proper pattern that will work with React Hooks in v13.


70-74: Clean up of isServerRenderHash handling

The code now cleanly handles the server render hash case without type assertions, improving readability and type safety.


76-89: Enhanced promise handling for render function results

The promise handling now properly differentiates between different result types (strings, functions, or other values) and processes each appropriately. This makes the function more robust when handling asynchronous render function results.


91-91: Simplified code with extracted function

Using the new createReactElementFromRenderFunctionResult function here simplifies the main flow and improves maintainability.


5-23: Well-structured helper function with good warning message

The new createReactElementFromRenderFunctionResult function provides a clean way to handle different return types from render functions. The warning message is especially valuable as it guides developers toward best practices for React Hooks compatibility in future versions.


70-74: Clean type handling

The simplified check for isServerRenderHash improves code readability by removing unnecessary type assertions.


76-89: Enhanced promise handling for async render functions

This improved logic for handling promises correctly processes different types of resolved values:

  • Strings are returned directly
  • Functions are processed using the new helper function
  • Other values are stringified

This enhancement provides robust support for asynchronous render functions, which is the core objective of this PR.


91-91: Consistent use of helper function

Using the new helper function here maintains consistency throughout the codebase.

node_package/src/ReactOnRailsRSC.ts (4)

24-26: Function signature expanded to support async render functions

The function now accepts reactRenderingResult of type ReactElement | Promise<ReactElement | string> instead of just ReactElement. This enhancement allows the component to handle both synchronous and asynchronous rendering results.


37-38: Optimized parallel loading of manifest and rendering result

Using Promise.all to concurrently load the React client manifest and resolve the rendering result is an effective optimization. This approach avoids sequential processing, potentially improving performance.


24-26: Improved function signature for async support

Updating the parameter type from ReactElement to ReactElement | Promise<ReactElement | string> broadens the range of valid inputs, making the function more flexible and aligned with modern React patterns involving async operations.


37-38: Performance optimization with Promise.all

Using Promise.all to concurrently load the React client manifest and resolve the rendering result is more efficient than sequential processing. This enhances performance when dealing with async operations, especially if either operation takes significant time.

docs/javascript/render-functions.md (4)

1-3: Excellent documentation title and introduction

The title clearly indicates this is a usage guide for render functions in React on Rails, which helps users immediately understand the document's purpose.


5-69: Comprehensive coverage of render function return types

The documentation thoroughly covers all possible return types from render functions with clear examples for each case. This is extremely helpful for developers to understand the options available to them.


71-80: Valuable information about limitations

Highlighting the important limitations observed in tests provides crucial information for developers to avoid common pitfalls when using render functions.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~79-~79: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...bjects without a renderedHtml property and they will still work. ## Ruby Helper F...

(COMMA_COMPOUND_SENTENCE)


161-290: Excellent examples with both JavaScript and Ruby code

The comprehensive examples showing both the JavaScript render functions and their corresponding Ruby usage provide a complete picture for developers. This dual-language approach significantly improves the documentation's utility.

node_package/src/serverRenderReactComponent.ts (2)

59-59: Signature update for async returns looks good.

Expanding Promise<string> to Promise<string | ReactElement> aligns with supporting asynchronous React element creation.


71-75:

✅ Verification successful

Confirm promise type assumptions.

This logic assumes promiseResult is always a string or a valid ReactElement. If there’s any scenario where it could return a different type (e.g., null, number, or object), this code would fail. Ensure upstream calls respect this contract.

Check all call sites to confirm only strings or ReactElements are ever returned.


🏁 Script executed:

#!/bin/bash
rg -A 3 'processPromise'

Length of output: 710


Confirmed promise type contract.

After verifying with the call sites and type definitions, it’s clear that the contract enforced by processPromise guarantees that the resolved value is either a string or a valid ReactElement. The upstream code ensures that no other types (e.g., null, number, or object) will be returned, so the logic in these lines is safe.

  • File: node_package/src/serverRenderReactComponent.ts (Lines 71-75)
  • Verification: The function signature for processPromise enforces a return type of Promise<string> | string, ensuring promiseResult is either a string or a ReactElement.
  • Action: No further changes are required unless new types are introduced upstream.
node_package/src/isServerRenderResult.ts (2)

1-5: Broadening function signatures for added flexibility.

Including RenderFunctionResult ensures the type guard can handle all new async/sync return possibilities without regressions.


15-15: Promise type signature update is consistent.

Allowing RenderFunctionResult in isPromise matches the broader support for async returns within render functions.

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

45-48: Introduction of ServerRenderHashRenderedHtml is a clear approach.

This structure is well-defined and helps clarify the presence of a componentHtml field with optional extra keys.


51-51: Union type on renderedHtml broadens support.

Enabling either a string or the new ServerRenderHashRenderedHtml type aligns with supporting complex SSR outputs.


57-57: Extended CreateReactOutputResult type for async React elements.

Including Promise<string | ReactElement> accommodates asynchronous rendering seamlessly.


59-62: RenderFunctionResult now correctly accounts for async/sync returns.

Supporting promises of string, ServerRenderHashRenderedHtml, or ReactComponent unifies multiple SSR return paths into one flexible type.

node_package/tests/streamServerRenderedReactComponent.test.jsx (13)

118-118: Using .once('end') prevents accidental double invocation.

This is a safer way to handle the stream's end event.


137-137: Same change as line 118.


153-153: Same change as line 118.


169-169: Same change as line 118.


173-173: Allowing ≥ 2 chunks ensures both shell and async content.

This assertion confirms that at least two chunks are streamed before completion.


179-179: Error-check for async content is correct.

Testing for the exact error message ensures the fallback logic is triggered properly.


200-200: Similar test logic for error messages.


206-224: Tests for streaming a resolved React component confirm correct shell + content flow.

This scenario effectively validates the approach for both immediate and eventually returned React elements.


226-240: Covers sync errors in render function thoroughly.

Ensures we see the correct fallback path for immediate errors.


242-260: Covers async errors in render function thoroughly.

Successfully tests the fallback for promise-based errors.


262-282: Ensures that errors thrown during render function execution are captured.

This test confirms the user sees a coherent error message.


284-307: Verifies error emission behavior when throwJsErrors is true.

Properly checks that an error event is emitted when the function fails.


309-334: Tests for streaming a plain string from a promise.

Great coverage to confirm that plain strings also work in async rendering contexts.

node_package/tests/serverRenderReactComponent.test.ts (5)

1-2: Include this new test file in the TypeScript project configuration.
The lint failure indicates this file is not recognized by the TypeScript compiler. To fix it, please add or reference it in the appropriate tsconfig.json so that it's included in the project.

Would you like me to generate a script that searches for all references to this file in your repository and queries the tsconfig.json entries to verify inclusion?

🧰 Tools
🪛 GitHub Actions: Lint JS and Ruby

[error] 1-1: Parsing error: /home/runner/work/react_on_rails/react_on_rails/node_package/tests/serverRenderReactComponent.test.ts was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProject.


39-58: Basic rendering test looks good.
This test effectively covers a straightforward scenario of rendering a registered component and verifying the correct html and hasErrors flags.


108-127: Good negative test for invalid rendered object.
Verifies that returning an object without a renderedHtml property triggers an error, which is the intended behavior.


235-250: Confirm coverage for a promise that returns a function.
Here the promise resolves to a function that itself returns a React element. Consider covering edge cases, such as a promise that resolves after a delay or that rejects mid-render, to ensure resilience of streaming.

If you'd like, I can generate an additional test that introduces an artificial delay or rejection path.


252-276: Error-handling test ensures graceful failure.
This test appropriately checks that an invalid scenario triggers a user-facing error message (Exception in rendering!). The coverage for error states seems thorough.

node_package/src/streamServerRenderedReactComponent.ts (5)

7-7: Helper import usage is consistent.
The isServerRenderHash import is properly utilized below to guard against unsupported server render hashes before streaming.


124-127: Enhanced flexibility for async rendering.
Expanding the parameter to ReactElement | Promise<ReactElement | string> correctly accommodates asynchronous or string-based results. Please ensure all upstream calls handle these types without assumptions of synchronicity.


138-152: Centralized error handling approach is good practice.
reportError and sendErrorHtml keep concerns clearly separated, helping maintain clarity for the streaming logic and potential expansions (e.g., logging).


153-185: Promise resolution logic looks robust.
The code properly handles different result types, logging a console error if a string is returned, then writing that string to the stream. This is consistent with your design choice that raw strings aren’t the intended final behavior but can still be captured.


219-233: Fallback error-handling in the catch block.
Wrapping the streaming logic within a try/catch ensures you can handle both runtime and synchronous setup errors gracefully. The final fallback to push error HTML is well-managed.

Copy link
Contributor

@Judahmeek Judahmeek left a comment

Choose a reason for hiding this comment

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

Please also figure out the necessary commit steps to get git to recognize that serverRenderReactComponent.test.js has not been deleted, but has been renamed to serverRenderReactComponent.test.ts.

Try renaming first and then making changes in a separate commit.

Having git recognize renamed files makes code reviews a lot easier for those files.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
node_package/tests/serverRenderReactComponent.test.ts (2)

32-36: Consider adding teardown to clean up after tests.

While the beforeEach clears the ComponentRegistry before each test, there's no corresponding cleanup after the tests complete. Consider adding an afterAll to ensure a clean state after the test suite runs.

  beforeEach(() => {
    ComponentRegistry.components().clear();
  });
+
+  afterAll(() => {
+    ComponentRegistry.components().clear();
+  });

1-279: Add tests for component promise rejection.

While the test suite covers many scenarios, it doesn't test what happens when a Promise is rejected. Consider adding a test case for a render function that returns a rejected Promise to ensure errors are properly handled.

Here's a suggested test implementation:

it('handles rejected promises from render functions', async () => {
  const errorMessage = 'Async error in render function';
  const X9: RenderFunction = (_props: unknown, _railsContext?: RailsContext) => 
    Promise.reject(new Error(errorMessage));

  ComponentRegistry.register({ X9 });

  const renderResult = serverRenderReactComponent({
    name: 'X9',
    domNodeId: 'myDomId',
    trace: false,
    throwJsErrors: false,
    renderingReturnsPromises: true,
  });
  
  assertIsPromise(renderResult);
  const result = await renderResult;
  
  expect(result.hasErrors).toBeTruthy();
  expect(result.html).toContain('Exception in rendering!');
  expect(result.html).toContain(errorMessage);
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1dccfe1 and 98eed42.

📒 Files selected for processing (2)
  • eslint.config.ts (1 hunks)
  • node_package/tests/serverRenderReactComponent.test.ts (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: Lint JS and Ruby
eslint.config.ts

[error] Parsing error: allowDefaultProject glob 'node_package/tests//*.ts' contains a disallowed ''.

node_package/tests/serverRenderReactComponent.test.ts

[error] Parsing error: allowDefaultProject glob 'node_package/tests//*.ts' contains a disallowed ''.

⏰ 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 (12)
eslint.config.ts (1)

148-148:

❓ Verification inconclusive

Fix the glob pattern in allowDefaultProject.

The pipeline is failing because the glob pattern node_package/tests/**/*.ts contains a disallowed double asterisk ('**'). According to ESLint's configuration, double asterisks are not permitted in the allowDefaultProject array.

-  allowDefaultProject: ['eslint.config.ts', 'knip.ts', 'node_package/tests/**/*.ts'],
+  allowDefaultProject: ['eslint.config.ts', 'knip.ts', 'node_package/tests/*.ts'],

If you need to include TypeScript files in subdirectories, consider specifying them individually or using a different configuration approach that allows recursive patterns.


🏁 Script executed:

#!/bin/bash
# Check if there are TypeScript files in subdirectories of node_package/tests
find node_package/tests -name "*.ts" | grep -v "^node_package/tests/[^/]*\.ts$" | head -n 5

Length of output: 93


Update Glob Pattern in ESLint Configuration

The ESLint rules disallow the use of double asterisks (**) in the allowDefaultProject array. The patch replaces the problematic pattern with a single asterisk to match only files directly under node_package/tests, which resolves the pipeline failure.

Before finalizing this change, please verify whether any TypeScript files are intentionally placed in subdirectories of node_package/tests. If such files exist, you may need to list them explicitly or adopt a different configuration approach to avoid inadvertently excluding them.

-  allowDefaultProject: ['eslint.config.ts', 'knip.ts', 'node_package/tests/**/*.ts'],
+  allowDefaultProject: ['eslint.config.ts', 'knip.ts', 'node_package/tests/*.ts'],
node_package/tests/serverRenderReactComponent.test.ts (11)

1-31: Good setup for type safety in tests.

The type assertion functions and helper for matching objects provide strong type safety in the tests. This is especially important for testing TypeScript code that handles promises and different return types.


37-57: LGTM: Effective test for basic component rendering.

This test case properly verifies the core functionality of rendering a registered React component, with appropriate assertions on the HTML output and error state.


59-82: LGTM: Good error handling test.

This test effectively verifies that errors thrown during component rendering are properly caught and reported in the output.


84-106: LGTM: Valid test for renderedHtml property.

This test correctly verifies that objects with a renderedHtml property are processed correctly.


108-127: LGTM: Good test for invalid object returns.

This test properly verifies error handling when a render function returns an object without the required renderedHtml property.


129-161: Well-documented edge case test.

The test is preceded by detailed documentation explaining a subtle behavior when rendering functions return strings directly. This is valuable both for test clarity and as documentation for developers.


163-184: LGTM: Good test for async rendering with string HTML.

This test correctly verifies the handling of promises that resolve to string HTML, which is a key part of the new async rendering support being added.


186-210: LGTM: Well-documented test for async object returns.

The detailed comments explain an important behavior of the component and potential issues. The test effectively validates this behavior.


212-233: LGTM: Good test for react_component_hash helper compatibility.

This test demonstrates how async render functions can be used with the react_component_hash helper, providing a real-world usage pattern.


235-250: LGTM: Good test for async component rendering.

This test correctly verifies that an async function returning a React component works properly, which is a core part of the PR's objective.


252-277: LGTM: Proper error handling test for renderer objects.

This test verifies that attempting to render a renderer object (rather than a component) results in an appropriate error.

@AbanoubGhadban AbanoubGhadban force-pushed the abanoubghadban/ror1719/add-support-for-async-render-function-returns-component branch from 98eed42 to 7c4903d Compare April 3, 2025 10:04
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🔭 Outside diff range comments (1)
node_package/src/serverRenderReactComponent.ts (1)

30-43: 🛠️ Refactor suggestion

Improved handling of renderedHtml with null safety.

The changes improve the handling of renderedHtml by:

  1. Removing the explicit type constraint
  2. Using the nullish coalescing operator (??) to handle undefined values

However, this handling still doesn't fully address the concern from the previous review about explicitly checking for null values.

Consider implementing more explicit handling:

  htmlResult = result.renderedHtml;
+ 
+ // Line 44
+ if (htmlResult === null || htmlResult === undefined) {
+   htmlResult = '';
+ } else if (typeof htmlResult !== 'string') {
+   htmlResult = JSON.stringify(htmlResult);
+ }

This would provide more predictable behavior and prevent potential issues downstream.

Also applies to: 45-46

🧹 Nitpick comments (10)
docs/javascript/render-functions.md (10)

1-4: Introduction Clarity and Test File Link Reference
The introduction is clear and well laid out. Consider adding a hyperlink for the referenced test file (e.g. [serverRenderReactComponent.test.ts](./serverRenderReactComponent.test.ts)) to improve navigability and help readers quickly locate the source tests.


27-37: Example Section for Objects with Multiple HTML Properties
Examples demonstrate multiple HTML parts well. Consider if a brief note should be added to explain when and why one might return multiple keys (such as for SEO purposes).


73-79: Enhance Consistency in Limitation Descriptions
In the "Important Limitations Observed in Tests" section, consider:

  • Consistently capitalizing “HTML” (instead of “html”) for clarity.
  • Revising the phrasing for the async functions limitation by inserting an article (e.g. “a Promise‐returning function…”).
  • Adding a comma before “and they will still work” to properly separate independent clauses.
    These small adjustments will improve the readability of the documentation.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~75-~75: You might be missing the article “the” here.
Context: ...nder function causes an error. The test doesn't render html string returned directly from render function demonstrates this. 2. **Non-...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~79-~79: You might be missing the article “a” here.
Context: ...nt Behavior** - Interestingly, the test returns the object returned by async render function even if it doesn't have renderedHtml property shows that Promise-returning ...

(AI_EN_LECTOR_MISSING_DETERMINER_A)


[uncategorized] ~79-~79: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...bjects without a renderedHtml property and they will still work. ## Ruby Helper F...

(COMMA_COMPOUND_SENTENCE)


101-101: Remove Trailing Punctuation from Heading
The heading #### When to use: ends with a colon. For consistency with common Markdown style guidelines (e.g. MD026), consider removing the trailing punctuation.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

101-101: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


107-107: Remove Trailing Punctuation from Heading
Similarly, the heading #### Not suitable for: contains a trailing colon. Removing it will align with style guidelines.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

107-107: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


133-133: Remove Trailing Punctuation from Heading
Again, the heading #### When to use: in the react_component_hash section should drop the trailing colon for consistency.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

133-133: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


140-140: Remove Trailing Punctuation from Heading
The heading #### Not suitable for: in this section also has a trailing colon. Please remove it to conform with markdown style guidelines.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

140-140: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


145-145: Remove Trailing Punctuation from Heading
The heading #### Requirements: ends with a colon. For consistency, it is recommended to remove the trailing punctuation.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

145-145: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


223-233: Clarify the Purpose of the renderFunction Flag in Async Examples
In the asynchronous examples (Return Types 4 & 5), the renderFunction flag is set to true. Consider adding a brief explanatory note (either inline or as a caption) clarifying that this flag distinguishes asynchronous render functions from synchronous ones. This will help readers understand its significance in the overall render process.


270-292: Return Type 6: Redirect Object – Documentation Clarity
The redirect example is clear and the inline comments effectively communicate the intended behavior. For added clarity, you might consider a short summary sentence after the code block explaining that when a redirect condition is met, the helper renders nothing and instead performs the redirect logic.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98eed42 and 7c4903d.

📒 Files selected for processing (14)
  • docs/javascript/render-functions.md (1 hunks)
  • eslint.config.ts (1 hunks)
  • node_package/src/ReactOnRailsRSC.ts (2 hunks)
  • node_package/src/createReactOutput.ts (2 hunks)
  • node_package/src/handleError.ts (1 hunks)
  • node_package/src/isServerRenderResult.ts (2 hunks)
  • node_package/src/serverRenderReactComponent.ts (6 hunks)
  • node_package/src/serverRenderUtils.ts (1 hunks)
  • node_package/src/streamServerRenderedReactComponent.ts (4 hunks)
  • node_package/src/transformRSCStreamAndReplayConsoleLogs.ts (2 hunks)
  • node_package/src/types/index.ts (4 hunks)
  • node_package/tests/serverRenderReactComponent.test.js (0 hunks)
  • node_package/tests/serverRenderReactComponent.test.ts (1 hunks)
  • node_package/tests/streamServerRenderedReactComponent.test.jsx (6 hunks)
💤 Files with no reviewable changes (1)
  • node_package/tests/serverRenderReactComponent.test.js
🚧 Files skipped from review as they are similar to previous changes (10)
  • node_package/src/handleError.ts
  • eslint.config.ts
  • node_package/src/transformRSCStreamAndReplayConsoleLogs.ts
  • node_package/src/ReactOnRailsRSC.ts
  • node_package/src/serverRenderUtils.ts
  • node_package/src/createReactOutput.ts
  • node_package/tests/serverRenderReactComponent.test.ts
  • node_package/src/isServerRenderResult.ts
  • node_package/src/streamServerRenderedReactComponent.ts
  • node_package/src/types/index.ts
🧰 Additional context used
🪛 LanguageTool
docs/javascript/render-functions.md

[uncategorized] ~75-~75: You might be missing the article “the” here.
Context: ...nder function causes an error. The test doesn't render html string returned directly from render function demonstrates this. 2. **Non-...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~79-~79: You might be missing the article “a” here.
Context: ...nt Behavior** - Interestingly, the test returns the object returned by async render function even if it doesn't have renderedHtml property shows that Promise-returning ...

(AI_EN_LECTOR_MISSING_DETERMINER_A)


[uncategorized] ~79-~79: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...bjects without a renderedHtml property and they will still work. ## Ruby Helper F...

(COMMA_COMPOUND_SENTENCE)


[style] ~136-~136: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...le HTML strings in an object - When you need to insert rendered content in different pa...

(REP_NEED_TO_VB)


[misspelling] ~147-~147: Did you mean “and”?
Context: ...nts: - The render function MUST return an object - The object MUST include a `com...

(AN_AND)


[uncategorized] ~155-~155: Loose punctuation mark.
Context: ...es errors - either use JSX or wrap in a { renderedHtml: '...' } object. 3. **Async Functions Work wit...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)
docs/javascript/render-functions.md

101-101: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


107-107: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


133-133: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


140-140: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


145-145: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: dummy-app-integration-tests (oldest)
  • GitHub Check: dummy-app-integration-tests (newest)
  • GitHub Check: rspec-package-tests (oldest)
  • GitHub Check: build
🔇 Additional comments (18)
node_package/tests/streamServerRenderedReactComponent.test.jsx (7)

63-97: Well-structured enhancement to support multiple component types.

The addition of the componentType parameter and the switch statement is a good approach to test different component rendering scenarios. This implementation covers all necessary test cases for the new async render function support.


118-118: Good improvement: changed on to once for 'end' event listeners.

Changing from on to once for end event listeners prevents potential memory leaks and ensures the callback is executed exactly once when the stream ends.

Also applies to: 137-137, 153-153, 169-169, 190-190


173-173: Appropriate test assertion update.

Changing from toHaveLength to toBeGreaterThanOrEqual provides more flexibility in the tests, acknowledging that the exact number of chunks might vary but should meet a minimum threshold.

Also applies to: 194-194


206-224: Good test coverage for sync and async render functions.

Using parameterized tests with it.each is an efficient way to test both asyncRenderFunction and renderFunction with the same expectations.


226-260: Comprehensive error handling tests.

These test cases properly verify that both synchronous and asynchronous errors are handled correctly in render functions.


262-307: Good coverage for erroneous render functions.

The tests correctly verify handling of errors thrown directly from render functions and the proper emission of those errors when throwJsErrors is true.


309-334: Important test case for string promise resolution.

This test is crucial as it verifies that the system can properly handle promises that resolve to strings, not just React elements, which expands the flexibility of the API.

node_package/src/serverRenderReactComponent.ts (6)

1-3: Added React import for element validation.

Good addition of the React import which enables the isValidElement check used later in the code. This makes the dependencies more explicit.


18-19: New type imports support async React element handling.

These new types support the async rendering functionality and are crucial for the type safety of the updated code.


48-57: New processReactElement function with helpful error messages.

This is a good addition that encapsulates the rendering of React elements with proper error handling. The detailed error message will help developers understand and fix issues related to render functions vs. React Function Components.


59-62: Updated signature for processPromise function.

The function now accepts CreateReactOutputAsyncResult instead of Promise<string> and returns RenderStateHtml. This provides better type safety and flexibility.


71-76: Enhanced promise handling to support React elements.

The updated promise handling now checks if the resolved value is a valid React element and processes it accordingly. This is a key enhancement for supporting async render functions that return React elements.

However, this change might require updates to ReactOnRails Pro's NodeRenderer as noted in a previous review comment.

Please verify compatibility with ReactOnRails Pro's NodeRenderer, as this change in behavior might affect it.


85-87:

❓ Verification inconclusive

Handling of non-promise, non-server-render-hash results has changed.

Line 86 now directly calls processReactElement for non-promise, non-server-render-hash results, implying these results are expected to be React elements rather than strings. This is a significant behavioral change.

Please verify that all existing code that uses this function now returns React elements instead of strings, or update the code to handle both cases.


🏁 Script executed:

#!/bin/bash
# Search for places where components or render functions might return strings directly
rg -A 3 "ComponentRegistry.register|registerComponent" --type=js --type=jsx --type=ts --type=tsx

Length of output: 126


Action: Confirm React Element Consistency in serverRenderReactComponent Usage

The updated function now processes non-promise, non-server-render-hash results via processReactElement, which means callers are now expected to return React elements instead of strings. However, the initial verification command failed due to the unrecognized file type "jsx". To ensure that no callers still return strings, please run the following updated verification script that uses glob patterns to include JavaScript, JSX, TypeScript, and TSX files:

#!/bin/bash
# Search for occurrences of ComponentRegistry.register or registerComponent in various file types
rg -g "*.js" -g "*.jsx" -g "*.ts" -g "*.tsx" -A 3 "ComponentRegistry\.register|registerComponent"

After executing this command manually, confirm that all usage of the function now returns React elements. If any cases still return strings, update those call sites accordingly.

docs/javascript/render-functions.md (5)

7-10: Example Section for React Components (JSX)
The first example clearly demonstrates a simple JSX return. The code snippet is clear and concise. No changes needed!


17-25: Example Section for Objects with renderedHtml Property
The code example effectively illustrates returning an object with a renderedHtml property. The formatting and clarity are good.


39-46: Example Section for Promises of Strings
The async example is straightforward. The use of async and await is correct and clear.


48-57: Example Section for Promises of Objects
This snippet correctly shows how to return an object from an async function. The example is clear.


59-69: Example Section for Redirect Information
The redirect example is precise and the inline comments clearly explain the purpose of each key. No modifications are necessary here.

@AbanoubGhadban AbanoubGhadban force-pushed the abanoubghadban/ror1719/add-support-for-async-render-function-returns-component branch from 7c4903d to 77d7cea Compare April 3, 2025 10:33
@AbanoubGhadban AbanoubGhadban changed the base branch from master to rename-server-render-react-component-test-to-ts April 3, 2025 10:33
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
docs/javascript/render-functions.md (1)

27-27: Section title could be more descriptive

The section title "Objects with Multiple HTML Properties" should better describe that these objects must include a componentHtml property.

Consider renaming to "Objects with componentHtml Property (and Additional HTML Properties)" to match previous review feedback and better describe the content requirements.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c4903d and 77d7cea.

📒 Files selected for processing (14)
  • docs/javascript/render-functions.md (1 hunks)
  • eslint.config.ts (1 hunks)
  • node_package/src/ReactOnRailsRSC.ts (2 hunks)
  • node_package/src/createReactOutput.ts (2 hunks)
  • node_package/src/handleError.ts (1 hunks)
  • node_package/src/isServerRenderResult.ts (2 hunks)
  • node_package/src/serverRenderReactComponent.ts (6 hunks)
  • node_package/src/serverRenderUtils.ts (1 hunks)
  • node_package/src/streamServerRenderedReactComponent.ts (4 hunks)
  • node_package/src/transformRSCStreamAndReplayConsoleLogs.ts (2 hunks)
  • node_package/src/types/index.ts (4 hunks)
  • node_package/tests/serverRenderReactComponent.test.js (0 hunks)
  • node_package/tests/serverRenderReactComponent.test.ts (1 hunks)
  • node_package/tests/streamServerRenderedReactComponent.test.jsx (6 hunks)
💤 Files with no reviewable changes (1)
  • node_package/tests/serverRenderReactComponent.test.js
🚧 Files skipped from review as they are similar to previous changes (9)
  • node_package/src/transformRSCStreamAndReplayConsoleLogs.ts
  • node_package/src/handleError.ts
  • eslint.config.ts
  • node_package/src/isServerRenderResult.ts
  • node_package/src/serverRenderReactComponent.ts
  • node_package/tests/serverRenderReactComponent.test.ts
  • node_package/src/createReactOutput.ts
  • node_package/src/streamServerRenderedReactComponent.ts
  • node_package/src/serverRenderUtils.ts
🧰 Additional context used
🧬 Code Definitions (2)
node_package/src/ReactOnRailsRSC.ts (2)
node_package/src/types/index.ts (1)
  • RSCRenderParams (156-158)
node_package/src/loadReactClientManifest.ts (1)
  • loadReactClientManifest (7-24)
node_package/tests/streamServerRenderedReactComponent.test.jsx (4)
lib/react_on_rails/react_component/render_options.rb (1)
  • props (26-28)
spec/dummy/client/app/store/composeInitialState.js (1)
  • props (3-3)
spec/dummy/client/app/startup/ReduxSharedStoreApp.client.jsx (1)
  • props (16-50)
node_package/src/ReactOnRails.client.ts (1)
  • streamServerRenderedReactComponent (165-169)
🪛 LanguageTool
docs/javascript/render-functions.md

[uncategorized] ~75-~75: You might be missing the article “the” here.
Context: ...nder function causes an error. The test doesn't render html string returned directly from render function demonstrates this. 2. **Non-...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~79-~79: You might be missing the article “a” here.
Context: ...nt Behavior** - Interestingly, the test returns the object returned by async render function even if it doesn't have renderedHtml property shows that Promise-returning ...

(AI_EN_LECTOR_MISSING_DETERMINER_A)


[uncategorized] ~79-~79: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...bjects without a renderedHtml property and they will still work. ## Ruby Helper F...

(COMMA_COMPOUND_SENTENCE)


[style] ~136-~136: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: ...le HTML strings in an object - When you need to insert rendered content in different pa...

(REP_NEED_TO_VB)


[misspelling] ~147-~147: Did you mean “and”?
Context: ...nts: - The render function MUST return an object - The object MUST include a `com...

(AN_AND)


[uncategorized] ~155-~155: Loose punctuation mark.
Context: ...es errors - either use JSX or wrap in a { renderedHtml: '...' } object. 3. **Async Functions Work wit...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)
docs/javascript/render-functions.md

101-101: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


107-107: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


133-133: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


140-140: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


145-145: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

⏰ 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 (28)
node_package/src/ReactOnRailsRSC.ts (2)

24-26: Support added for async render function returns

The function signature has been enhanced to accept a promise that resolves to either a React element or a string, which aligns with the PR objective of supporting async render functions.


37-38: Good use of Promise.all for parallel execution

Using Promise.all allows concurrent resolution of both the React client manifest and the render function result, which is more efficient than sequential execution.

docs/javascript/render-functions.md (7)

3-3: Good addition of test file reference

Including the reference to the test file provides helpful context for understanding the documentation.


79-79: Revise the wording about async function behavior

The word "Interestingly" doesn't add value and the explanation could be clearer about why async functions don't require the renderedHtml property.

Consider rewording to: "Async Functions Have Different Behavior - Promise-returning functions can return objects without a renderedHtml property, and they will still work because async functions are processed differently in the rendering pipeline."

🧰 Tools
🪛 LanguageTool

[uncategorized] ~79-~79: You might be missing the article “a” here.
Context: ...nt Behavior** - Interestingly, the test returns the object returned by async render function even if it doesn't have renderedHtml property shows that Promise-returning ...

(AI_EN_LECTOR_MISSING_DETERMINER_A)


[uncategorized] ~79-~79: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...bjects without a renderedHtml property and they will still work. ## Ruby Helper F...

(COMMA_COMPOUND_SENTENCE)


99-99: Consider consolidating redundant sections

The examples of react_component with different return types all look the same in this section, which doesn't effectively illustrate the differences.

Replace this section with a single statement explaining that react_component accepts render functions that return JSX, objects with a renderedHtml property, and promises, then refer to the more detailed examples in the section below.


110-110: Add examples of content types for different page parts

Be more specific about what kind of content can be inserted in different parts of the page.

Add examples such as "meta tags, title tags, and style tags" to provide clearer guidance on what types of content can be distributed across the page.


114-114: Add return type acceptance information

This section should specify which render function return types it accepts, similar to the react_component section.

Add a statement clarifying which return types are accepted by react_component_hash, such as "This helper accepts render functions that return objects with a componentHtml property and additional HTML properties."


151-151: Remove reference to tests as authority

Phrases like "Based on the Tests" and "tests show" give the impression that tests are the authority rather than the implementation.

Revise the heading to "Best Practices" and remove references to tests as the source of authority.


157-157: Redundant information with earlier sections

This section repeats information already covered in lines 73-79.

Consider removing or consolidating this redundant information to improve document flow and clarity.

node_package/tests/streamServerRenderedReactComponent.test.jsx (10)

63-64: Good addition of componentType parameter

Adding the componentType parameter to setupStreamTest allows for testing different component rendering scenarios, which is crucial for verifying the new async render function support.


65-97: Well-structured component type handling

The switch statement provides a clean way to register different types of components for testing, covering both synchronous and asynchronous scenarios, as well as error cases.


118-118: Better event handling with once

Changing from on('end', resolve) to once('end', resolve) prevents potential memory leaks by ensuring the callback is only called once.


173-173: More flexible test assertions

Using toBeGreaterThanOrEqual instead of toHaveLength provides more flexibility when testing asynchronous operations that may produce a variable number of chunks.


206-224: Comprehensive test coverage for different component types

This parametrized test effectively verifies that both synchronous and asynchronous render functions can produce the same output when resolved properly.


226-240: Good error handling testing for sync errors

This test ensures that synchronous errors are properly caught and handled in both types of render functions.


242-260: Good error handling testing for async errors

This test ensures that asynchronous errors are properly caught and handled in both types of render functions.


262-282: Comprehensive testing of erroneous component scenarios

This test ensures that errors occurring within the render functions themselves (rather than in the rendered components) are properly caught and handled.


284-307: Complete error propagation testing

This test verifies that errors are properly propagated to the error handler when throwJsErrors is true, which is critical for proper error reporting.


309-334: Test for string promise resolution

This test verifies the ability to handle promises that resolve directly to strings, which is important for the new async render function support.

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

48-51: Good addition of ServerRenderHashRenderedHtml type

This type provides a clear structure for objects that contain rendered HTML, requiring a componentHtml property and allowing additional string properties.


54-54: Improved type safety for renderedHtml property

Using the new ServerRenderHashRenderedHtml type for the renderedHtml property provides better type safety and documentation.


60-64: Enhanced type structure for CreateReactOutputResult

Breaking down the result types into synchronous and asynchronous variants improves type clarity and allows for more precise type checking.


66-70: Improved type structure for RenderFunctionResult

Similar to the CreateReactOutputResult changes, this breakdown into synchronous and asynchronous variants provides better type safety and documentation.


176-176: Addition of FinalHtmlResult type

This union type clearly defines what can be used as the final HTML result, improving type safety throughout the codebase.


179-179: Updated RenderResult to use FinalHtmlResult

This change ensures consistency in the types used for HTML results and improves type safety.


186-188: Addition of RSCPayloadChunk interface

This interface specifically constrains the html property to be a string, which is important for RSC payload chunks that must be stringified.


378-378: Addition of RenderStateHtml type

This type provides a clear definition for what can be used as the HTML in the render state, including both synchronous and asynchronous results.


381-381: Updated RenderState to use RenderStateHtml

This change ensures consistency in the types used for HTML results in the render state and improves type safety.

@AbanoubGhadban
Copy link
Collaborator Author

Please also figure out the necessary commit steps to get git to recognize that serverRenderReactComponent.test.js has not been deleted, but has been renamed to serverRenderReactComponent.test.ts.

I renamed the file at the #1723 , it should be merged before merging this file

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR aims to add support for async render function returns by updating various components in the test suite, server rendering logic, and type definitions, while also enhancing documentation.

  • Updated tests to support additional component types and async error handling.
  • Extended TypeScript types and modified streaming and server rendering functions to deal with Promise-based render function outputs.
  • Added comprehensive documentation for render functions and their supported return types.

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
node_package/tests/streamServerRenderedReactComponent.test.jsx Updates tests to use .once for stream events, add support for new component types, and revise expected error output formatting.
node_package/tests/serverRenderReactComponent.test.ts Refactors tests to use strict type assertions and updated render parameters for improved clarity with async and sync render functions.
node_package/src/types/index.ts Introduces new types to better support async render functions and server render hashes.
node_package/src/streamServerRenderedReactComponent.ts Updates streaming logic to handle Promise-based React components or string return values with improved error reporting.
node_package/src/serverRenderUtils.ts, serverRenderReactComponent.ts, isServerRenderResult.ts, handleError.ts, createReactOutput.ts, ReactOnRailsRSC.ts Refactors error handling, conversion functions and type processing to support the revised return types from render functions.
eslint.config.ts Updates allowed default projects to include additional test files.
docs/javascript/render-functions.md Adds a detailed usage guide on render functions, their return types, and proper usage with Rails helpers.
Comments suppressed due to low confidence (1)

node_package/src/createReactOutput.ts:6

  • [nitpick] The warning message logged when a render function returns a React Element directly is quite verbose; consider clarifying or simplifying the message and updating the documentation to clearly state that render functions should return a React component function rather than a JSX element.
function createReactElementFromRenderFunctionResult(renderFunctionResult: ReactComponent, name: string, props: Record<string, unknown> | undefined): React.ReactElement {


2. **Objects Require Specific Properties** - Non-promise objects must include a `renderedHtml` property to be valid when used with `react_component`.

3. **Async Functions Support All Return Types** - Async functions can return React components, strings, or objects with any property structure due to special handling in the server renderer, but it doesn't support properties like redirectLocation and routingError that can be returned by sync render function.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably redirectLocation and routingError should be described above (under "7. Redirect Information"?) and this should say something like

but it doesn't support redirect information [or "routing information"? and it should have a link to that] that can be returned by sync render function.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I already mentioned at the 7. Redirect Information section that

React on Rails will not handle the actual redirection to another page. It will just return an empty component and depend on the front end to handle the redirection when it renders the router on the front end.

I updated this content to have a link to the above section

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Personally, I don't believe the redirectLocation property serves any purpose. It merely logs the location to which a redirection should occur, doesn’t it, @Judahmeek?

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe that's right. Looks like a redirectLocation return is just to cut out any unnecessary processing.

@AbanoubGhadban AbanoubGhadban changed the title [WIP] Add support for async render function returns component Add support for async render function returns component Apr 4, 2025
@AbanoubGhadban AbanoubGhadban changed the title Add support for async render function returns component Add Support for Async Render Functions Returning React Components Apr 4, 2025
Copy link
Contributor

@Judahmeek Judahmeek left a comment

Choose a reason for hiding this comment

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

Should this PR also be updating spec/dummy to use the async render functions?

@AbanoubGhadban AbanoubGhadban force-pushed the abanoubghadban/ror1719/add-support-for-async-render-function-returns-component branch from 0306315 to e467df4 Compare April 6, 2025 07:22
@AbanoubGhadban AbanoubGhadban force-pushed the rename-server-render-react-component-test-to-ts branch from ed16293 to 4b341f9 Compare April 6, 2025 07:39
@AbanoubGhadban AbanoubGhadban removed the request for review from alexeyr-ci April 6, 2025 07:40
@AbanoubGhadban
Copy link
Collaborator Author

Should this PR also be updating spec/dummy to use the async render functions?

@Judahmeek We can only use promises in the node renderer, so I added an example to the dummy app of RORP. Please check it here
https://github.com/shakacode/react_on_rails_pro/pull/525

@alexeyr-ci2
Copy link
Collaborator

@AbanoubGhadban

We can only use promises in the node renderer

Then the doc should say so, e.g. #1720 (comment).

Base automatically changed from rename-server-render-react-component-test-to-ts to master April 7, 2025 10:36
…d enhance documentation on render functions, clarifying parameter usage and return types.
@AbanoubGhadban AbanoubGhadban force-pushed the abanoubghadban/ror1719/add-support-for-async-render-function-returns-component branch from fe75977 to 86f8bfb Compare April 7, 2025 10:37
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
node_package/src/createReactOutput.ts (1)

5-23: Good addition of helper function with clear warning message.

The new createReactElementFromRenderFunctionResult function properly handles React components and elements, with a helpful warning message about the recommended patterns. This supports React Hooks compatibility by encouraging function components over direct JSX returns.

Note that the warning indicates this will become an error in React on Rails v13, but we're beyond that version now. Consider updating the warning to reflect that this might cause issues with React Hooks currently.

-incorrectly returned a React Element (JSX). Instead, return a React Function Component by
-wrapping your JSX in a function. ReactOnRails v13 will throw error on this, as React Hooks do not
+incorrectly returned a React Element (JSX). Instead, return a React Function Component by
+wrapping your JSX in a function. React Hooks do not
docs/javascript/render-functions.md (2)

38-122: Comprehensive coverage of all return types with good examples.

The documentation clearly explains the 7 different return types with practical code examples. The note about React components versus React elements is particularly important and will help users avoid common pitfalls.

Minor syntax improvement suggestion: Use more consistent formatting for the object examples. Some use ES6 arrow functions with JSX directly, while others use template literals. Consider standardizing the approach across examples.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~63-~63: You might be missing the article “an” here.
Context: ... ### 3. Objects with renderedHtml as object containing componentHtml and other pr...

(AI_EN_LECTOR_MISSING_DETERMINER_AN)


134-197: Clear guidance on helper methods choice with practical examples.

The documentation clearly explains when to use each helper method (react_component vs react_component_hash) and provides examples for various scenarios. This will help users make the right choice based on their needs.

Fix minor MarkdownLint warnings related to trailing punctuation in headings:

-#### When to use:
+#### When to use
 
-#### Not suitable for:
+#### Not suitable for
 
-#### Requirements:
+#### Requirements
🧰 Tools
🪛 LanguageTool

[misspelling] ~194-~194: Did you mean “and”?
Context: ...nts: - The render function MUST return an object - The object MUST include a `com...

(AN_AND)

🪛 markdownlint-cli2 (0.17.2)

146-146: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


152-152: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


180-180: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


187-187: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


192-192: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

node_package/tests/streamServerRenderedReactComponent.test.jsx (1)

63-97: Add type safety or an enum for component types
This switch statement correctly differentiates between multiple component types. However, consider creating a dedicated type or an enum (e.g., 'reactComponent' | 'renderFunction' | 'asyncRenderFunction' etc.) to enforce type safety. This will help prevent typos and make future refactoring safer.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77d7cea and 86f8bfb.

📒 Files selected for processing (14)
  • CHANGELOG.md (1 hunks)
  • docs/javascript/render-functions.md (1 hunks)
  • eslint.config.ts (1 hunks)
  • node_package/src/ReactOnRailsRSC.ts (3 hunks)
  • node_package/src/createReactOutput.ts (2 hunks)
  • node_package/src/handleError.ts (1 hunks)
  • node_package/src/isServerRenderResult.ts (2 hunks)
  • node_package/src/serverRenderReactComponent.ts (6 hunks)
  • node_package/src/serverRenderUtils.ts (1 hunks)
  • node_package/src/streamServerRenderedReactComponent.ts (4 hunks)
  • node_package/src/transformRSCStreamAndReplayConsoleLogs.ts (2 hunks)
  • node_package/src/types/index.ts (5 hunks)
  • node_package/tests/serverRenderReactComponent.test.ts (1 hunks)
  • node_package/tests/streamServerRenderedReactComponent.test.jsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • node_package/src/handleError.ts
  • node_package/src/serverRenderUtils.ts
  • eslint.config.ts
  • node_package/src/transformRSCStreamAndReplayConsoleLogs.ts
  • node_package/src/isServerRenderResult.ts
  • node_package/src/streamServerRenderedReactComponent.ts
  • node_package/src/ReactOnRailsRSC.ts
🧰 Additional context used
🧬 Code Definitions (2)
node_package/src/createReactOutput.ts (1)
node_package/src/isServerRenderResult.ts (2)
  • isServerRenderHash (8-17)
  • isPromise (19-23)
node_package/tests/streamServerRenderedReactComponent.test.jsx (5)
spec/dummy/client/app/store/composeInitialState.js (1)
  • props (3-3)
spec/dummy/client/app/startup/ReduxSharedStoreApp.client.jsx (1)
  • props (16-50)
lib/react_on_rails/react_component/render_options.rb (1)
  • props (26-28)
spec/dummy/client/app/startup/CssModulesImagesFontsExample.jsx (1)
  • _props (5-21)
node_package/src/ReactOnRails.client.ts (1)
  • streamServerRenderedReactComponent (165-169)
🪛 LanguageTool
docs/javascript/render-functions.md

[uncategorized] ~9-~9: Loose punctuation mark.
Context: ...nctions take two parameters: 1. props: The props passed from the Ruby helper m...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~10-~10: Loose punctuation mark.
Context: ...le in your JavaScript. 2. railsContext: Rails contextual information like curre...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~63-~63: You might be missing the article “an” here.
Context: ... ### 3. Objects with renderedHtml as object containing componentHtml and other pr...

(AI_EN_LECTOR_MISSING_DETERMINER_AN)


[uncategorized] ~128-~128: Loose punctuation mark.
Context: ...s an error. Always wrap HTML strings in { renderedHtml: '...' }. 2. **Objects Require Specific Proper...

(UNLIKELY_OPENING_PUNCTUATION)


[misspelling] ~194-~194: Did you mean “and”?
Context: ...nts: - The render function MUST return an object - The object MUST include a `com...

(AN_AND)

🪛 markdownlint-cli2 (0.17.2)
docs/javascript/render-functions.md

146-146: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


152-152: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


180-180: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


187-187: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


192-192: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

⏰ 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 (oldest)
  • GitHub Check: rspec-package-tests (newest)
  • GitHub Check: build
🔇 Additional comments (40)
CHANGELOG.md (1)

30-31: Feature addition looks good!

Clear and concise documentation of the new feature, with proper attribution and linking to the PR.

node_package/src/createReactOutput.ts (3)

2-2: Appropriately updated import to include necessary types.

This change ensures the proper type definitions are available for the new functionality.


70-85: Enhanced promise handling for async render functions.

This change properly handles different types of results from promises, particularly supporting React components returned from async render functions. The .then() callback now checks if the result is a function and processes it accordingly.

The code now correctly distinguishes between functions (React components) and other return types, applying the appropriate transformation in each case.


88-88: Simplified function call using the extracted helper method.

Good refactoring that uses the new helper function, making the code more maintainable and consistent.

docs/javascript/render-functions.md (4)

1-10: Excellent introduction to render functions with clear explanations.

The guide begins with a clear overview and properly explains the parameters that render functions receive. The link to the Rails Context documentation provides helpful context for users.

Consider adding a small introductory paragraph explaining the motivation for using render functions (data fetching, SSR benefits, etc.) to help users understand their value.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~9-~9: Loose punctuation mark.
Context: ...nctions take two parameters: 1. props: The props passed from the Ruby helper m...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~10-~10: Loose punctuation mark.
Context: ...le in your JavaScript. 2. railsContext: Rails contextual information like curre...

(UNLIKELY_OPENING_PUNCTUATION)


12-36: Well-documented methods for identifying render functions.

The explanation of the two ways to mark a function as a render function is clear and provides good code examples. This is essential for users to understand how React on Rails identifies functions that should be treated as render functions versus regular React components.


124-132: Valuable information about rendering behavior with reference to tests.

Including the link to the test file and explaining important behaviors is excellent for helping developers understand the internal workings. This section provides crucial information about limitations and supported features.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~128-~128: Loose punctuation mark.
Context: ...s an error. Always wrap HTML strings in { renderedHtml: '...' }. 2. **Objects Require Specific Proper...

(UNLIKELY_OPENING_PUNCTUATION)


198-344: Excellent comprehensive examples for all return types.

The examples section ties everything together by showing how each return type works with the appropriate helper method. This practical guidance will significantly help developers implement these patterns correctly.

The format of showing both the JavaScript and Ruby code for each example is particularly helpful for understanding the end-to-end implementation.

node_package/src/serverRenderReactComponent.ts (4)

1-1: Added necessary imports for React and new types.

These additions support the enhanced functionality for handling React elements and async rendering.

Also applies to: 18-19


30-31: Improved handling of rendered HTML results.

The type inference for htmlResult and the use of the null coalescing operator (??) improve the type safety and handle potential undefined values appropriately.

Also applies to: 42-42, 45-45


48-57: Added dedicated function for processing React elements with good error handling.

The new processReactElement function properly renders React elements to strings and includes helpful error messaging for common mistakes with render functions. The error message clearly explains a potential cause (missing parameter for render functions) and how to fix it.


59-77: Enhanced promise handling for async render functions.

The updated processPromise function now handles different types of promise results, particularly supporting React components returned from async render functions. The function now checks if the resolved value is a valid React element and processes it accordingly.

The error message clearly communicates that promises are only supported by the React on Rails Pro Node renderer, which is important for users to understand.

node_package/tests/streamServerRenderedReactComponent.test.jsx (9)

118-118: Good use of once instead of on
Switching to renderResult.once('end', ...) ensures the handler only fires once, which is appropriate for a single end event. This is a clean improvement.

Also applies to: 137-137, 153-153, 169-169


173-173: Relaxing expected chunk length
Replacing toHaveLength(2) with toBeGreaterThanOrEqual(2) accommodates potential variations in streaming chunk boundaries. This change is consistent with streaming behavior.

Also applies to: 194-194


179-179: Refined error message pattern
Switching to toMatch(/the server rendering errored:\\n\\nAsync Error/) ensures you're asserting the exact format of error output. This improves test specificity.

Also applies to: 200-200


205-223: Comprehensive test for resolved React component
The it.each approach for 'asyncRenderFunction' and 'renderFunction' effectively verifies that both synchronous and asynchronous render functions correctly produce streaming chunks. Great coverage.


226-240: Expanding coverage of sync errors
These cases ensure sync errors in both async and standard render functions are handled. The thorough checks for chunk output greatly help catch regressions.


242-260: Validating async errors
Testing async throw scenarios for both 'asyncRenderFunction' and 'renderFunction' ensures consistent error handling. This is necessary for robust streaming.


262-282: Erroneous render function test
Verifying the 'erroneousRenderFunction' and 'erroneousAsyncRenderFunction' paths at the streaming layer is an excellent way to confirm your error capture logic.


284-307: Differentiating error emission with throwJsErrors: true
This set of tests confirms that an error event is emitted and properly tracked when JavaScript errors are configured to halt execution. Great scenario coverage.


309-334: Testing a Promise-resolved string
Streaming a purely string-based result tests an important edge case. Your code ensures that a direct string is returned as proper HTML, which confirms broader promise-handling.

node_package/tests/serverRenderReactComponent.test.ts (12)

4-10: Using explicit type imports
Importing RenderParams, RenderResult, RailsContext, etc., clarifies test intentions and improves maintainability. Good practice to keep type usage explicit.


12-16: Assert helper for string
assertIsString is a clean utility to quickly narrow the type and throw if unexpected. It ensures strong runtime checks parallel your TypeScript declarations.


18-24: Assert helper for promise
assertIsPromise helps confirm the shape of asynchronous results. This approach reduces the chance of silent type mismatches.


32-51: Initial test with typed render params
Using RenderParams in this test is a great improvement for clarity. The JSON parsing plus assertIsString ensures your output is valid JSON and a valid string.


54-76: Thorough error coverage
Catching “XYZ” in the rendered output verifies that runtime errors are surfaced. Confirming hasErrors is set to true is essential for diagnosing rendering issues.


78-101: Handling custom renderedHtml
Your logic checks that a provided renderedHtml string is rendered unchanged. This scenario is beneficial for advanced server rendering or partial pre-render approaches.


103-124: Graceful failure on invalid object
Confirming that returning an object without a renderedHtml property triggers an exception is crucial. It prevents accidental misuse of the API.


135-158: Skipping direct HTML string
The test ensures that a simple string like '<div>Hello</div>' is treated as an invalid tag, forcing error handling. This clarifies that direct HTML should be used via a renderedHtml property or a React element.


160-181: Promise of a string
Verifying that renderingReturnsPromises: true handles a stringly promise is beneficial. Your test ensures the final output is indeed that string, no matter the async path.


183-207: Returning an object from async function
This scenario fosters better flexibility for specialized server rendering outputs. It's wise to confirm that the object is returned as-is.


209-231: React component in async function
Ensuring the function returns a React component at runtime is valuable. This test verifies your ability to handle asynchronous component fetching.


251-279: Rendering a renderer
Posting an error for attempts to render “a renderer” clarifies to users that they must differentiate between a component vs. a function that provides HTML or elements. Good error feedback.

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

48-51: Structured ServerRenderHashRenderedHtml
Defining componentHtml as mandatory and allowing additional string keys ensures flexible usage while retaining a clear minimal shape.


54-54: Extending renderedHtml
Mixing string | ServerRenderHashRenderedHtml expands possible rendering outputs. This is well-aligned with use cases that require more than just plain HTML.


60-71: Refined type definitions for sync & async results
Separating CreateReactOutputSyncResult from CreateReactOutputAsyncResult clarifies the differences between immediate and deferred outputs. These definitions strengthen your typed workflow.


117-122: Additional exports
Adding these new exports in a coherent group helps keep your library consistent. This grouping makes it easier to see all related types in one place.


180-182: FinalHtmlResult in RenderResult
Updating the html field to FinalHtmlResult | null allows for plain strings or ServerRenderHashRenderedHtml variants. This is a flexible but safe approach.


189-191: RSCPayloadChunk extends RenderResult
This interface nicely enforces a guaranteed html string in payload chunks, distinguishing it from the possibly more open RenderResult.html type.


381-385: RenderStateHtml for sync or async
Allowing RenderStateHtml to be either FinalHtmlResult or Promise<FinalHtmlResult> captures the hybrid approach of your rendering pipeline. This well represents streaming or sync outcomes.

@AbanoubGhadban AbanoubGhadban merged commit 5621e31 into master Apr 7, 2025
11 checks passed
@AbanoubGhadban AbanoubGhadban deleted the abanoubghadban/ror1719/add-support-for-async-render-function-returns-component branch April 7, 2025 10:45
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