@@ -94,104 +94,6 @@ def react_component(component_name, options = {})
9494 end
9595 end
9696
97- # Streams a server-side rendered React component using React's `renderToPipeableStream`.
98- # Supports React 18 features like Suspense, concurrent rendering, and selective hydration.
99- # Enables progressive rendering and improved performance for large components.
100- #
101- # Note: This function can only be used with React on Rails Pro.
102- # The view that uses this function must be rendered using the
103- # `stream_view_containing_react_components` method from the React on Rails Pro gem.
104- #
105- # Example of an async React component that can benefit from streaming:
106- #
107- # const AsyncComponent = async () => {
108- # const data = await fetchData();
109- # return <div>{data}</div>;
110- # };
111- #
112- # function App() {
113- # return (
114- # <Suspense fallback={<div>Loading...</div>}>
115- # <AsyncComponent />
116- # </Suspense>
117- # );
118- # }
119- #
120- # @param [String] component_name Name of your registered component
121- # @param [Hash] options Options for rendering
122- # @option options [Hash] :props Props to pass to the react component
123- # @option options [String] :dom_id DOM ID of the component container
124- # @option options [Hash] :html_options Options passed to content_tag
125- # @option options [Boolean] :trace Set to true to add extra debugging information to the HTML
126- # @option options [Boolean] :raise_on_prerender_error Set to true to raise exceptions during server-side rendering
127- # Any other options are passed to the content tag, including the id.
128- def stream_react_component ( component_name , options = { } )
129- # stream_react_component doesn't have the prerender option
130- # Because setting prerender to false is equivalent to calling react_component with prerender: false
131- options [ :prerender ] = true
132- options = options . merge ( immediate_hydration : true ) unless options . key? ( :immediate_hydration )
133- run_stream_inside_fiber do
134- internal_stream_react_component ( component_name , options )
135- end
136- end
137-
138- # Renders the React Server Component (RSC) payload for a given component. This helper generates
139- # a special format designed by React for serializing server components and transmitting them
140- # to the client.
141- #
142- # @return [String] Returns a Newline Delimited JSON (NDJSON) stream where each line contains a JSON object with:
143- # - html: The RSC payload containing the rendered server components and client component references
144- # - consoleReplayScript: JavaScript to replay server-side console logs in the client
145- # - hasErrors: Boolean indicating if any errors occurred during rendering
146- # - isShellReady: Boolean indicating if the initial shell is ready for hydration
147- #
148- # Example NDJSON stream:
149- # {"html":"<RSC Payload>","consoleReplayScript":"","hasErrors":false,"isShellReady":true}
150- # {"html":"<RSC Payload>","consoleReplayScript":"console.log('Loading...')","hasErrors":false,"isShellReady":true}
151- #
152- # The RSC payload within the html field contains:
153- # - The component's rendered output from the server
154- # - References to client components that need hydration
155- # - Data props passed to client components
156- #
157- # @param component_name [String] The name of the React component to render. This component should
158- # be a server component or a mixed component tree containing both server and client components.
159- #
160- # @param options [Hash] Options for rendering the component
161- # @option options [Hash] :props Props to pass to the component (default: {})
162- # @option options [Boolean] :trace Enable tracing for debugging (default: false)
163- # @option options [String] :id Custom DOM ID for the component container (optional)
164- #
165- # @example Basic usage with a server component
166- # <%= rsc_payload_react_component("ReactServerComponentPage") %>
167- #
168- # @example With props and tracing enabled
169- # <%= rsc_payload_react_component("RSCPostsPage",
170- # props: { artificialDelay: 1000 },
171- # trace: true) %>
172- #
173- # @note This helper requires React Server Components support to be enabled in your configuration:
174- # ReactOnRailsPro.configure do |config|
175- # config.enable_rsc_support = true
176- # end
177- #
178- # @raise [ReactOnRailsPro::Error] if RSC support is not enabled in configuration
179- #
180- # @note You don't have to deal directly with this helper function - it's used internally by the
181- # `rsc_payload_route` helper function. The returned data from this function is used internally by
182- # components registered using the `registerServerComponent` function. Don't use it unless you need
183- # more control over the RSC payload generation. To know more about RSC payload, see the following link:
184- # @see https://www.shakacode.com/react-on-rails-pro/docs/how-react-server-components-works.md
185- # for technical details about the RSC payload format
186- def rsc_payload_react_component ( component_name , options = { } )
187- # rsc_payload_react_component doesn't have the prerender option
188- # Because setting prerender to false will not do anything
189- options [ :prerender ] = true
190- run_stream_inside_fiber do
191- internal_rsc_payload_react_component ( component_name , options )
192- end
193- end
194-
19597 # react_component_hash is used to return multiple HTML strings for server rendering, such as for
19698 # adding meta-tags to a page.
19799 # It is exactly like react_component except for the following:
@@ -446,32 +348,6 @@ def load_pack_for_generated_component(react_component_name, render_options)
446348
447349 # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
448350
449- def run_stream_inside_fiber
450- unless ReactOnRails ::Utils . react_on_rails_pro?
451- raise ReactOnRails ::Error ,
452- "You must use React on Rails Pro to use the stream_react_component method."
453- end
454-
455- if @rorp_rendering_fibers . nil?
456- raise ReactOnRails ::Error ,
457- "You must call stream_view_containing_react_components to render the view containing the react component"
458- end
459-
460- rendering_fiber = Fiber . new do
461- stream = yield
462- stream . each_chunk do |chunk |
463- Fiber . yield chunk
464- end
465- end
466-
467- @rorp_rendering_fibers << rendering_fiber
468-
469- # return the first chunk of the fiber
470- # It contains the initial html of the component
471- # all updates will be appended to the stream sent to browser
472- rendering_fiber . resume
473- end
474-
475351 def registered_stores
476352 @registered_stores ||= [ ]
477353 end
@@ -494,25 +370,6 @@ def create_render_options(react_component_name, options)
494370 options : options )
495371 end
496372
497- def internal_stream_react_component ( component_name , options = { } )
498- options = options . merge ( render_mode : :html_streaming )
499- result = internal_react_component ( component_name , options )
500- build_react_component_result_for_server_streamed_content (
501- rendered_html_stream : result [ :result ] ,
502- component_specification_tag : result [ :tag ] ,
503- render_options : result [ :render_options ]
504- )
505- end
506-
507- def internal_rsc_payload_react_component ( react_component_name , options = { } )
508- options = options . merge ( render_mode : :rsc_payload_streaming )
509- render_options = create_render_options ( react_component_name , options )
510- json_stream = server_rendered_react_component ( render_options )
511- json_stream . transform do |chunk |
512- "#{ chunk . to_json } \n " . html_safe
513- end
514- end
515-
516373 def generated_components_pack_path ( component_name )
517374 "#{ ReactOnRails ::PackerUtils . packer_source_entry_path } /generated/#{ component_name } .js"
518375 end
@@ -544,32 +401,6 @@ def build_react_component_result_for_server_rendered_string(
544401 prepend_render_rails_context ( result )
545402 end
546403
547- def build_react_component_result_for_server_streamed_content (
548- rendered_html_stream :,
549- component_specification_tag :,
550- render_options :
551- )
552- is_first_chunk = true
553- rendered_html_stream . transform do |chunk_json_result |
554- if is_first_chunk
555- is_first_chunk = false
556- build_react_component_result_for_server_rendered_string (
557- server_rendered_html : chunk_json_result [ "html" ] ,
558- component_specification_tag : component_specification_tag ,
559- console_script : chunk_json_result [ "consoleReplayScript" ] ,
560- render_options : render_options
561- )
562- else
563- result_console_script = render_options . replay_console ? chunk_json_result [ "consoleReplayScript" ] : ""
564- # No need to prepend component_specification_tag or add rails context again
565- # as they're already included in the first chunk
566- compose_react_component_html_with_spec_and_console (
567- "" , chunk_json_result [ "html" ] , result_console_script
568- )
569- end
570- end
571- end
572-
573404 def build_react_component_result_for_server_rendered_hash (
574405 server_rendered_html : required ( "server_rendered_html" ) ,
575406 component_specification_tag : required ( "component_specification_tag" ) ,
0 commit comments