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