@@ -4,7 +4,7 @@ import type { ReactElement } from 'react';
44
55import ComponentRegistry from './ComponentRegistry' ;
66import createReactOutput from './createReactOutput' ;
7- import { isPromise , isServerRenderHash } from './isServerRenderResult' ;
7+ import { isServerRenderHash } from './isServerRenderResult' ;
88import buildConsoleReplay from './buildConsoleReplay' ;
99import handleError from './handleError' ;
1010import { createResultObject , convertToError , validateComponent } from './serverRenderUtils' ;
@@ -158,7 +158,7 @@ export const transformRenderStreamChunksToResultObject = (renderState: StreamRen
158158 return { readableStream, pipeToTransform, writeChunk, emitError, endStream } ;
159159} ;
160160
161- const streamRenderReactComponent = ( reactRenderingResult : ReactElement , options : RenderParams ) => {
161+ const streamRenderReactComponent = ( reactRenderingResult : ReactElement | Promise < ReactElement | string > , options : RenderParams ) => {
162162 const { name : componentName , throwJsErrors, domNodeId } = options ;
163163 const renderState : StreamRenderState = {
164164 result : null ,
@@ -169,42 +169,59 @@ const streamRenderReactComponent = (reactRenderingResult: ReactElement, options:
169169 const { readableStream, pipeToTransform, writeChunk, emitError, endStream } =
170170 transformRenderStreamChunksToResultObject ( renderState ) ;
171171
172- const renderingStream = ReactDOMServer . renderToPipeableStream ( reactRenderingResult , {
173- onShellError ( e ) {
174- const error = convertToError ( e ) ;
175- renderState . hasErrors = true ;
176- renderState . error = error ;
172+ Promise . resolve ( reactRenderingResult ) . then ( reactRenderedElement => {
173+ if ( typeof reactRenderedElement === 'string' ) {
174+ console . error (
175+ `Error: stream_react_component helper received a string instead of a React component for component "${ componentName } ".\n` +
176+ 'To benefit from React on Rails Pro streaming feature, your render function should return a React component.\n' +
177+ 'Do not call ReactDOMServer.renderToString() inside the render function as this defeats the purpose of streaming.\n'
178+ ) ;
177179
178- if ( throwJsErrors ) {
179- emitError ( error ) ;
180- }
181-
182- const errorHtml = handleError ( { e : error , name : componentName , serverSide : true } ) ;
183- writeChunk ( errorHtml ) ;
180+ writeChunk ( reactRenderedElement ) ;
184181 endStream ( ) ;
185- } ,
186- onShellReady ( ) {
187- renderState . isShellReady = true ;
188- pipeToTransform ( renderingStream ) ;
189- } ,
190- onError ( e ) {
191- if ( ! renderState . isShellReady ) {
192- return ;
193- }
194- const error = convertToError ( e ) ;
195- if ( throwJsErrors ) {
196- emitError ( error ) ;
197- }
198- renderState . hasErrors = true ;
199- renderState . error = error ;
200- } ,
201- identifierPrefix : domNodeId ,
182+ return ;
183+ }
184+
185+ const renderingStream = ReactDOMServer . renderToPipeableStream ( reactRenderedElement , {
186+ onShellError ( e ) {
187+ const error = convertToError ( e ) ;
188+ renderState . hasErrors = true ;
189+ renderState . error = error ;
190+
191+ if ( throwJsErrors ) {
192+ emitError ( error ) ;
193+ }
194+
195+ const errorHtml = handleError ( { e : error , name : componentName , serverSide : true } ) ;
196+ writeChunk ( errorHtml ) ;
197+ endStream ( ) ;
198+ } ,
199+ onShellReady ( ) {
200+ renderState . isShellReady = true ;
201+ pipeToTransform ( renderingStream ) ;
202+ } ,
203+ onError ( e ) {
204+ if ( ! renderState . isShellReady ) {
205+ return ;
206+ }
207+ const error = convertToError ( e ) ;
208+ if ( throwJsErrors ) {
209+ emitError ( error ) ;
210+ }
211+ renderState . hasErrors = true ;
212+ renderState . error = error ;
213+ } ,
214+ identifierPrefix : domNodeId ,
215+ } ) ;
202216 } ) ;
203217
204218 return readableStream ;
205219} ;
206220
207- type StreamRenderer < T , P extends RenderParams > = ( reactElement : ReactElement , options : P ) => T ;
221+ type StreamRenderer < T , P extends RenderParams > = (
222+ reactElement : ReactElement | Promise < ReactElement | string > ,
223+ options : P ,
224+ ) => T ;
208225
209226export const streamServerRenderedComponent = < T , P extends RenderParams > (
210227 options : P ,
@@ -224,7 +241,7 @@ export const streamServerRenderedComponent = <T, P extends RenderParams>(
224241 railsContext,
225242 } ) ;
226243
227- if ( isServerRenderHash ( reactRenderingResult ) || isPromise ( reactRenderingResult ) ) {
244+ if ( isServerRenderHash ( reactRenderingResult ) ) {
228245 throw new Error ( 'Server rendering of streams is not supported for server render hashes or promises.' ) ;
229246 }
230247
0 commit comments