@@ -37,6 +37,7 @@ const React = require('react');
3737
3838const { renderToPipeableStream} = require ( 'react-dom/server' ) ;
3939const { createFromNodeStream} = require ( 'react-server-dom-webpack/client' ) ;
40+ const { PassThrough} = require ( 'stream' ) ;
4041
4142const app = express ( ) ;
4243
@@ -146,34 +147,33 @@ app.all('/', async function (req, res, next) {
146147 // so we start by consuming the RSC payload. This needs a module
147148 // map that reverse engineers the client-side path to the SSR path.
148149
149- // This is a bad hack to set the form state after SSR has started. It works
150- // because we block the root component until we have the form state and
151- // any form that reads it necessarily will come later. It also only works
152- // because the formstate type is an object which may change in the future
153- const lazyFormState = [ ] ;
154-
155- let cachedResult = null ;
156- async function getRootAndFormState ( ) {
157- const { root, formState} = await createFromNodeStream (
158- rscResponse ,
159- ssrManifest
160- ) ;
161- // We shouldn't be assuming formState is an object type but at the moment
162- // we have no way of setting the form state from within the render
163- Object . assign ( lazyFormState , formState ) ;
164- return root ;
165- }
150+ // We need to get the formState before we start rendering but we also
151+ // need to run the Flight client inside the render to get all the preloads.
152+ // The API is ambivalent about what's the right one so we need two for now.
153+
154+ // Tee the response into two streams so that we can do both.
155+ const rscResponse1 = new PassThrough ( ) ;
156+ const rscResponse2 = new PassThrough ( ) ;
157+
158+ rscResponse . pipe ( rscResponse1 ) ;
159+ rscResponse . pipe ( rscResponse2 ) ;
160+
161+ const { formState} = await createFromNodeStream ( rscResponse1 , ssrManifest ) ;
162+ rscResponse1 . end ( ) ;
163+
164+ let cachedResult ;
166165 let Root = ( ) => {
167166 if ( ! cachedResult ) {
168- cachedResult = getRootAndFormState ( ) ;
167+ // Read this stream inside the render.
168+ cachedResult = createFromNodeStream ( rscResponse2 , ssrManifest ) ;
169169 }
170- return React . use ( cachedResult ) ;
170+ return React . use ( cachedResult ) . root ;
171171 } ;
172172 // Render it into HTML by resolving the client components
173173 res . set ( 'Content-type' , 'text/html' ) ;
174174 const { pipe} = renderToPipeableStream ( React . createElement ( Root ) , {
175175 bootstrapScripts : mainJSChunks ,
176- formState : lazyFormState ,
176+ formState : formState ,
177177 } ) ;
178178 pipe ( res ) ;
179179 } catch ( e ) {
0 commit comments