@@ -37,6 +37,7 @@ const React = require('react');
37
37
38
38
const { renderToPipeableStream} = require ( 'react-dom/server' ) ;
39
39
const { createFromNodeStream} = require ( 'react-server-dom-webpack/client' ) ;
40
+ const { PassThrough} = require ( 'stream' ) ;
40
41
41
42
const app = express ( ) ;
42
43
@@ -146,34 +147,33 @@ app.all('/', async function (req, res, next) {
146
147
// so we start by consuming the RSC payload. This needs a module
147
148
// map that reverse engineers the client-side path to the SSR path.
148
149
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 ;
166
165
let Root = ( ) => {
167
166
if ( ! cachedResult ) {
168
- cachedResult = getRootAndFormState ( ) ;
167
+ // Read this stream inside the render.
168
+ cachedResult = createFromNodeStream ( rscResponse2 , ssrManifest ) ;
169
169
}
170
- return React . use ( cachedResult ) ;
170
+ return React . use ( cachedResult ) . root ;
171
171
} ;
172
172
// Render it into HTML by resolving the client components
173
173
res . set ( 'Content-type' , 'text/html' ) ;
174
174
const { pipe} = renderToPipeableStream ( React . createElement ( Root ) , {
175
175
bootstrapScripts : mainJSChunks ,
176
- formState : lazyFormState ,
176
+ formState : formState ,
177
177
} ) ;
178
178
pipe ( res ) ;
179
179
} catch ( e ) {
0 commit comments