@samitouri / QOS-React / commits / 2505bf9b34

[Fizz] track postpones when aborting boundaries with a postpone (#30751)

When aborting with a postpone value boundaries are put into client rendered mode even during prerenders. This doesn't follow the postpoen semantics of the rest of fizz where during a prerender a postpone is tracked and it will leave holes in tracked postpone state that can be resumed. This change updates this behavior to match the postpones semantics between aborts and imperative postpones.

Josh Story committed Aug 20, 2024 at 09:49 UTC 2505bf9b3400c6a00381e86d30b495935f5339df
2 files changed +13 -2
packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
-1
@@ -7727,7 +7727,6 @@ describe('ReactDOMFizzServer', () => {
7727
7728 const prerendered = await pendingPrerender;
7729
7730 - expect(prerendered.postponed).toBe(null);
7730 expect(errors).toEqual([]);
7731 expect(postpones).toEqual(['manufactured', 'manufactured']);
7732
packages/react-server/src/ReactFizzServer.js
+13 -1
@@ -3857,7 +3857,6 @@ function abortTask(task: Task, request: Request, error: mixed): void {
3857 } else {
3858 boundary.pendingTasks--;
3859 if (boundary.status !== CLIENT_RENDERED) {
3860 - boundary.status = CLIENT_RENDERED;
3860 // We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which
3861 // boundary the message is referring to
3862 const errorInfo = getThrownInfo(task.componentStack);
@@ -3870,11 +3869,24 @@ function abortTask(task: Task, request: Request, error: mixed): void {
3869 ) {
3870 const postponeInstance: Postpone = (error: any);
3871 logPostpone(request, postponeInstance.message, errorInfo, null);
3872 + if (request.trackedPostpones !== null && segment !== null) {
3873 + trackPostpone(request, request.trackedPostpones, task, segment);
3874 + finishedTask(request, task.blockedBoundary, segment);
3875 +
3876 + // If this boundary was still pending then we haven't already cancelled its fallbacks.
3877 + // We'll need to abort the fallbacks, which will also error that parent boundary.
3878 + boundary.fallbackAbortableTasks.forEach(fallbackTask =>
3879 + abortTask(fallbackTask, request, error),
3880 + );
3881 + boundary.fallbackAbortableTasks.clear();
3882 + return;
3883 + }
3884 // TODO: Figure out a better signal than a magic digest value.
3885 errorDigest = 'POSTPONE';
3886 } else {
3887 errorDigest = logRecoverableError(request, error, errorInfo, null);
3888 }
3889 + boundary.status = CLIENT_RENDERED;
3890 encodeErrorForBoundary(boundary, errorDigest, error, errorInfo, true);
3891
3892 untrackBoundary(request, boundary);