Skip to content

Commit 5f4711b

Browse files
committed
[Fizz] Don't flush empty segments
Before this change, we would sometimes write segments without any content in them. For example for a Suspense boundary that immediately suspends we might emit something like: <div hidden id="123"> <template id="456"></template> </div> Where the outer div is just a temporary wrapper and the inner one is a placeholder for something to be added later. This serves no purpose. We should ideally have a heuristic that holds back segments based on byte size and time. However, this is a straight forward clear win for now.
1 parent 11c5bb6 commit 5f4711b

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ describe('ReactDOMFizzServer', () => {
495495
pipe(writable);
496496
});
497497
expect(getVisibleChildren(container)).toEqual(<div>Loading...</div>);
498+
// Because there is no content inside the Suspense boundary that could've
499+
// been written, we expect to not see any additional partial data flushed
500+
// yet.
501+
expect(container.firstChild.nextSibling).toBe(null);
498502
await act(async () => {
499503
resolveElement({default: <Text text="Hello" />});
500504
});

packages/react-server/src/ReactFizzServer.js

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ function renderSuspenseBoundary(
488488
// We use the safe form because we don't handle suspending here. Only error handling.
489489
renderNode(request, task, content);
490490
contentRootSegment.status = COMPLETED;
491-
newBoundary.completedSegments.push(contentRootSegment);
491+
queueCompletedSegment(request, newBoundary, contentRootSegment);
492492
if (newBoundary.pendingTasks === 0) {
493493
// This must have been the last segment we were waiting on. This boundary is now complete.
494494
// Therefore we won't need the fallback. We early return so that we don't have to create
@@ -1430,6 +1430,23 @@ function abortTask(task: Task): void {
14301430
}
14311431
}
14321432

1433+
function queueCompletedSegment(request: Request, boundary: SuspenseBoundary, segment: Segment): void {
1434+
if (segment.chunks.length === 0 && segment.boundary === null) {
1435+
// This is an empty segment. There's nothing to write, so we can instead mark the
1436+
// children to be written.
1437+
for (let i = 0; i < segment.children.length; i++) {
1438+
const childSegment = segment.children[i];
1439+
childSegment.parentFlushed = true;
1440+
if (childSegment.status === COMPLETED) {
1441+
queueCompletedSegment(request, boundary, childSegment);
1442+
}
1443+
}
1444+
} else {
1445+
const completedSegments = boundary.completedSegments;
1446+
completedSegments.push(segment);
1447+
}
1448+
}
1449+
14331450
function finishedTask(
14341451
request: Request,
14351452
boundary: Root | SuspenseBoundary,
@@ -1463,7 +1480,7 @@ function finishedTask(
14631480
// If it is a segment that was aborted, we'll write other content instead so we don't need
14641481
// to emit it.
14651482
if (segment.status === COMPLETED) {
1466-
boundary.completedSegments.push(segment);
1483+
queueCompletedSegment(request, boundary, segment);
14671484
}
14681485
}
14691486
if (boundary.parentFlushed) {
@@ -1483,14 +1500,18 @@ function finishedTask(
14831500
// to emit it.
14841501
if (segment.status === COMPLETED) {
14851502
const completedSegments = boundary.completedSegments;
1486-
completedSegments.push(segment);
1487-
if (completedSegments.length === 1) {
1503+
if (completedSegments.length === 0) {
1504+
queueCompletedSegment(request, boundary, segment);
14881505
// This is the first time since we last flushed that we completed anything.
14891506
// We can schedule this boundary to emit its partially completed segments early
14901507
// in case the parent has already been flushed.
1491-
if (boundary.parentFlushed) {
1492-
request.partialBoundaries.push(boundary);
1508+
if (completedSegments.length > 0) {
1509+
if (boundary.parentFlushed) {
1510+
request.partialBoundaries.push(boundary);
1511+
}
14931512
}
1513+
} else {
1514+
queueCompletedSegment(request, boundary, segment);
14941515
}
14951516
}
14961517
}

0 commit comments

Comments
 (0)