Skip to content

Commit b123b9c

Browse files
authored
[Flight] Refactor the Render Loop to Behave More Like Fizz (#28065)
This refactors the Flight render loop to behave more like Fizz with similar naming conventions. So it's easier to apply similar techniques across both. This is not necessarily better/faster - at least not yet. This doesn't yet implement serialization by writing segments to chunks but we probably should do that since the built-in parts that `JSON.stringify` gets us isn't really much anymore (except serializing strings). When we switch to that it probably makes sense for the whole thing to be recursive. Right now it's not technically fully recursive because each recursive render returns the next JSON value to encode. So it's kind of like a trampoline. This means we can't have many contextual things on the stack. It needs to use the Server Context `__POP` trick. However, it does work for things that are contextual only for one sequence of server component abstractions in a row. Since those are now recursive. An interesting observation here is that `renderModel` means that anything can suspend while still serializing the outer siblings. Typically only Lazy or Components would suspend but in principle a Proxy can suspend/postpone too and now that is left serialized by reference to a future value. It's only if the thing that we rendered was something that can reduce to Lazy e.g. an Element that we can serialize it as a lazy. Similarly to how Suspense boundaries in Fizz can catch errors, anything that can be reduced to Lazy can also catch an error rather than bubbling it. It only errors when the Lazy resolves. Unlike Suspense boundaries though, those things don't render anything so they're otherwise going to use the destructive form. To ensure that throwing in an Element can reuse the current task, this must be handled by `renderModel`, not for example `renderElement`.
1 parent 8bb6ee1 commit b123b9c

File tree

3 files changed

+322
-263
lines changed

3 files changed

+322
-263
lines changed

packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,20 @@ describe('ReactFlightDOMEdge', () => {
242242
expect(result).toEqual(resolvedChildren);
243243
});
244244

245+
it('should execute repeated server components in a compact form', async () => {
246+
async function ServerComponent({recurse}) {
247+
if (recurse > 0) {
248+
return <ServerComponent recurse={recurse - 1} />;
249+
}
250+
return <div>Fin</div>;
251+
}
252+
const stream = ReactServerDOMServer.renderToReadableStream(
253+
<ServerComponent recurse={20} />,
254+
);
255+
const serializedContent = await readResult(stream);
256+
expect(serializedContent.length).toBeLessThan(150);
257+
});
258+
245259
// @gate enableBinaryFlight
246260
it('should be able to serialize any kind of typed array', async () => {
247261
const buffer = new Uint8Array([

packages/react-server/src/ReactFizzServer.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2201,8 +2201,12 @@ function renderNodeDestructive(
22012201
task.node = node;
22022202
task.childIndex = childIndex;
22032203

2204+
if (node === null) {
2205+
return;
2206+
}
2207+
22042208
// Handle object types
2205-
if (typeof node === 'object' && node !== null) {
2209+
if (typeof node === 'object') {
22062210
switch ((node: any).$$typeof) {
22072211
case REACT_ELEMENT_TYPE: {
22082212
const element: any = node;

0 commit comments

Comments
 (0)