Skip to content

Commit 1fddce3

Browse files
committed
[Fizz] Fix root segment IDs (#27371)
Typically we assign IDs lazily when flushing to minimize the ids we have to assign and we try to maximize inlining. When we prerender we could always flush into a buffer before returning but that's not actually what we do right now. We complete rendering before returning but we don't actually run the flush path until someone reads the resulting stream. We assign IDs eagerly when something postpone so that we can refer to those ids in the holes without flushing first. This leads to some interesting conditions that needs to consider this. This PR also deals with rootSegmentId which is the ID of the segment that contains the body of a Suspense boundary. The boundary needs to know this in addition to the Suspense Boundary's ID to know how to inject the root segment into the boundary. Why is the suspense boundary ID and the rootSegmentID just not the same ID? Why don't segments and suspense boundary not share ID namespace? That's a good question and I don't really remember. It might not be a good reason and maybe they should just be the same. DiffTrain build for [a6e4791](a6e4791)
1 parent df2c19f commit 1fddce3

8 files changed

+57
-30
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
95c9554bc72813b0ee2b028774bb7cf0482887ba
1+
a6e4791b11816374d015eb4531a82e6cf209c7f2

compiled/facebook-www/ReactDOMServer-dev.classic.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ if (__DEV__) {
1919
var React = require("react");
2020
var ReactDOM = require("react-dom");
2121

22-
var ReactVersion = "18.3.0-www-classic-62f810e0";
22+
var ReactVersion = "18.3.0-www-classic-f2b91051";
2323

2424
// This refers to a WWW module.
2525
var warningWWW = require("warning");
@@ -11337,7 +11337,8 @@ function queueCompletedSegment(boundary, segment) {
1133711337
if (
1133811338
segment.chunks.length === 0 &&
1133911339
segment.children.length === 1 &&
11340-
segment.children[0].boundary === null
11340+
segment.children[0].boundary === null && // Typically the id would not be assigned yet but if it's a postponed segment it might be.
11341+
segment.children[0].id === -1
1134111342
) {
1134211343
// This is an empty segment. There's nothing to write, so we can instead transfer the ID
1134311344
// to the child. That way any existing references point to the child.
@@ -11681,19 +11682,20 @@ function flushSegment(request, destination, segment) {
1168111682
);
1168211683
} else if (boundary.status !== COMPLETED) {
1168311684
if (boundary.status === PENDING) {
11685+
// For pending boundaries we lazily assign an ID to the boundary
11686+
// and root segment.
1168411687
boundary.id = assignSuspenseBoundaryID(
1168511688
request.renderState,
1168611689
request.resumableState
1168711690
);
11688-
} // This boundary is still loading. Emit a pending suspense boundary wrapper.
11689-
// Assign an ID to refer to the future content by.
11690-
11691-
boundary.rootSegmentID = request.nextSegmentId++;
11691+
boundary.rootSegmentID = request.nextSegmentId++;
11692+
}
1169211693

1169311694
if (boundary.completedSegments.length > 0) {
1169411695
// If this is at least partially complete, we can queue it to be partially emitted early.
1169511696
request.partialBoundaries.push(boundary);
11696-
} /// This is the first time we should have referenced this ID.
11697+
} // This boundary is still loading. Emit a pending suspense boundary wrapper.
11698+
/// This is the first time we should have referenced this ID.
1169711699

1169811700
var id = boundary.id;
1169911701
writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
@@ -11861,6 +11863,10 @@ function flushPartiallyCompletedSegment(
1186111863
);
1186211864
}
1186311865

11866+
return flushSegmentContainer(request, destination, segment);
11867+
} else if (segmentID === boundary.rootSegmentID) {
11868+
// When we emit postponed boundaries, we might have assigned the ID already
11869+
// but it's still the root segment so we can't inject it into the parent yet.
1186411870
return flushSegmentContainer(request, destination, segment);
1186511871
} else {
1186611872
flushSegmentContainer(request, destination, segment);

compiled/facebook-www/ReactDOMServer-dev.modern.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ if (__DEV__) {
1919
var React = require("react");
2020
var ReactDOM = require("react-dom");
2121

22-
var ReactVersion = "18.3.0-www-modern-9f6e7af7";
22+
var ReactVersion = "18.3.0-www-modern-82925a4c";
2323

2424
// This refers to a WWW module.
2525
var warningWWW = require("warning");
@@ -11085,7 +11085,8 @@ function queueCompletedSegment(boundary, segment) {
1108511085
if (
1108611086
segment.chunks.length === 0 &&
1108711087
segment.children.length === 1 &&
11088-
segment.children[0].boundary === null
11088+
segment.children[0].boundary === null && // Typically the id would not be assigned yet but if it's a postponed segment it might be.
11089+
segment.children[0].id === -1
1108911090
) {
1109011091
// This is an empty segment. There's nothing to write, so we can instead transfer the ID
1109111092
// to the child. That way any existing references point to the child.
@@ -11429,19 +11430,20 @@ function flushSegment(request, destination, segment) {
1142911430
);
1143011431
} else if (boundary.status !== COMPLETED) {
1143111432
if (boundary.status === PENDING) {
11433+
// For pending boundaries we lazily assign an ID to the boundary
11434+
// and root segment.
1143211435
boundary.id = assignSuspenseBoundaryID(
1143311436
request.renderState,
1143411437
request.resumableState
1143511438
);
11436-
} // This boundary is still loading. Emit a pending suspense boundary wrapper.
11437-
// Assign an ID to refer to the future content by.
11438-
11439-
boundary.rootSegmentID = request.nextSegmentId++;
11439+
boundary.rootSegmentID = request.nextSegmentId++;
11440+
}
1144011441

1144111442
if (boundary.completedSegments.length > 0) {
1144211443
// If this is at least partially complete, we can queue it to be partially emitted early.
1144311444
request.partialBoundaries.push(boundary);
11444-
} /// This is the first time we should have referenced this ID.
11445+
} // This boundary is still loading. Emit a pending suspense boundary wrapper.
11446+
/// This is the first time we should have referenced this ID.
1144511447

1144611448
var id = boundary.id;
1144711449
writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
@@ -11609,6 +11611,10 @@ function flushPartiallyCompletedSegment(
1160911611
);
1161011612
}
1161111613

11614+
return flushSegmentContainer(request, destination, segment);
11615+
} else if (segmentID === boundary.rootSegmentID) {
11616+
// When we emit postponed boundaries, we might have assigned the ID already
11617+
// but it's still the root segment so we can't inject it into the parent yet.
1161211618
return flushSegmentContainer(request, destination, segment);
1161311619
} else {
1161411620
flushSegmentContainer(request, destination, segment);

compiled/facebook-www/ReactDOMServer-prod.classic.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3744,7 +3744,8 @@ function queueCompletedSegment(boundary, segment) {
37443744
if (
37453745
0 === segment.chunks.length &&
37463746
1 === segment.children.length &&
3747-
null === segment.children[0].boundary
3747+
null === segment.children[0].boundary &&
3748+
-1 === segment.children[0].id
37483749
) {
37493750
var childSegment = segment.children[0];
37503751
childSegment.id = segment.id;
@@ -3955,8 +3956,8 @@ function flushSegment(request, destination, segment) {
39553956
JSCompiler_inline_result =
39563957
JSCompiler_inline_result.boundaryPrefix + generatedID.toString(16);
39573958
boundary.id = JSCompiler_inline_result;
3959+
boundary.rootSegmentID = request.nextSegmentId++;
39583960
}
3959-
boundary.rootSegmentID = request.nextSegmentId++;
39603961
0 < boundary.completedSegments.length &&
39613962
request.partialBoundaries.push(boundary);
39623963
writeStartPendingSuspenseBoundary(
@@ -4082,6 +4083,8 @@ function flushPartiallyCompletedSegment(
40824083
throw Error(formatProdErrorMessage(392));
40834084
return flushSegmentContainer(request, destination, segment);
40844085
}
4086+
if (segmentID === boundary.rootSegmentID)
4087+
return flushSegmentContainer(request, destination, segment);
40854088
flushSegmentContainer(request, destination, segment);
40864089
boundary = request.resumableState;
40874090
request = request.renderState;
@@ -4548,4 +4551,4 @@ exports.renderToString = function (children, options) {
45484551
'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server'
45494552
);
45504553
};
4551-
exports.version = "18.3.0-www-classic-aa5cc76a";
4554+
exports.version = "18.3.0-www-classic-f7fe51fc";

compiled/facebook-www/ReactDOMServer-prod.modern.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3711,7 +3711,8 @@ function queueCompletedSegment(boundary, segment) {
37113711
if (
37123712
0 === segment.chunks.length &&
37133713
1 === segment.children.length &&
3714-
null === segment.children[0].boundary
3714+
null === segment.children[0].boundary &&
3715+
-1 === segment.children[0].id
37153716
) {
37163717
var childSegment = segment.children[0];
37173718
childSegment.id = segment.id;
@@ -3922,8 +3923,8 @@ function flushSegment(request, destination, segment) {
39223923
JSCompiler_inline_result =
39233924
JSCompiler_inline_result.boundaryPrefix + generatedID.toString(16);
39243925
boundary.id = JSCompiler_inline_result;
3926+
boundary.rootSegmentID = request.nextSegmentId++;
39253927
}
3926-
boundary.rootSegmentID = request.nextSegmentId++;
39273928
0 < boundary.completedSegments.length &&
39283929
request.partialBoundaries.push(boundary);
39293930
writeStartPendingSuspenseBoundary(
@@ -4049,6 +4050,8 @@ function flushPartiallyCompletedSegment(
40494050
throw Error(formatProdErrorMessage(392));
40504051
return flushSegmentContainer(request, destination, segment);
40514052
}
4053+
if (segmentID === boundary.rootSegmentID)
4054+
return flushSegmentContainer(request, destination, segment);
40524055
flushSegmentContainer(request, destination, segment);
40534056
boundary = request.resumableState;
40544057
request = request.renderState;
@@ -4515,4 +4518,4 @@ exports.renderToString = function (children, options) {
45154518
'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server'
45164519
);
45174520
};
4518-
exports.version = "18.3.0-www-modern-ffdd98cf";
4521+
exports.version = "18.3.0-www-modern-8898fe0f";

compiled/facebook-www/ReactDOMServerStreaming-dev.modern.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10988,7 +10988,8 @@ function queueCompletedSegment(boundary, segment) {
1098810988
if (
1098910989
segment.chunks.length === 0 &&
1099010990
segment.children.length === 1 &&
10991-
segment.children[0].boundary === null
10991+
segment.children[0].boundary === null && // Typically the id would not be assigned yet but if it's a postponed segment it might be.
10992+
segment.children[0].id === -1
1099210993
) {
1099310994
// This is an empty segment. There's nothing to write, so we can instead transfer the ID
1099410995
// to the child. That way any existing references point to the child.
@@ -11329,19 +11330,20 @@ function flushSegment(request, destination, segment) {
1132911330
return writeEndClientRenderedSuspenseBoundary(destination);
1133011331
} else if (boundary.status !== COMPLETED) {
1133111332
if (boundary.status === PENDING) {
11333+
// For pending boundaries we lazily assign an ID to the boundary
11334+
// and root segment.
1133211335
boundary.id = assignSuspenseBoundaryID(
1133311336
request.renderState,
1133411337
request.resumableState
1133511338
);
11336-
} // This boundary is still loading. Emit a pending suspense boundary wrapper.
11337-
// Assign an ID to refer to the future content by.
11338-
11339-
boundary.rootSegmentID = request.nextSegmentId++;
11339+
boundary.rootSegmentID = request.nextSegmentId++;
11340+
}
1134011341

1134111342
if (boundary.completedSegments.length > 0) {
1134211343
// If this is at least partially complete, we can queue it to be partially emitted early.
1134311344
request.partialBoundaries.push(boundary);
11344-
} /// This is the first time we should have referenced this ID.
11345+
} // This boundary is still loading. Emit a pending suspense boundary wrapper.
11346+
/// This is the first time we should have referenced this ID.
1134511347

1134611348
var id = boundary.id;
1134711349
writeStartPendingSuspenseBoundary(destination, request.renderState, id); // Flush the fallback.
@@ -11509,6 +11511,10 @@ function flushPartiallyCompletedSegment(
1150911511
);
1151011512
}
1151111513

11514+
return flushSegmentContainer(request, destination, segment);
11515+
} else if (segmentID === boundary.rootSegmentID) {
11516+
// When we emit postponed boundaries, we might have assigned the ID already
11517+
// but it's still the root segment so we can't inject it into the parent yet.
1151211518
return flushSegmentContainer(request, destination, segment);
1151311519
} else {
1151411520
flushSegmentContainer(request, destination, segment);

compiled/facebook-www/ReactDOMServerStreaming-prod.modern.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3509,7 +3509,8 @@ function queueCompletedSegment(boundary, segment) {
35093509
if (
35103510
0 === segment.chunks.length &&
35113511
1 === segment.children.length &&
3512-
null === segment.children[0].boundary
3512+
null === segment.children[0].boundary &&
3513+
-1 === segment.children[0].id
35133514
) {
35143515
var childSegment = segment.children[0];
35153516
childSegment.id = segment.id;
@@ -3610,8 +3611,8 @@ function flushSegment(request, destination, segment) {
36103611
JSCompiler_inline_result =
36113612
JSCompiler_inline_result.boundaryPrefix + generatedID.toString(16);
36123613
boundary.id = JSCompiler_inline_result;
3614+
boundary.rootSegmentID = request.nextSegmentId++;
36133615
}
3614-
boundary.rootSegmentID = request.nextSegmentId++;
36153616
0 < boundary.completedSegments.length &&
36163617
request.partialBoundaries.push(boundary);
36173618
writeStartPendingSuspenseBoundary(
@@ -3743,6 +3744,8 @@ function flushPartiallyCompletedSegment(
37433744
);
37443745
return flushSegmentContainer(request, destination, segment);
37453746
}
3747+
if (segmentID === boundary.rootSegmentID)
3748+
return flushSegmentContainer(request, destination, segment);
37463749
flushSegmentContainer(request, destination, segment);
37473750
boundary = request.resumableState;
37483751
request = request.renderState;

compiled/facebook-www/ReactTestRenderer-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24360,7 +24360,7 @@ function createFiberRoot(
2436024360
return root;
2436124361
}
2436224362

24363-
var ReactVersion = "18.3.0-www-modern-1f53bcad";
24363+
var ReactVersion = "18.3.0-www-modern-0976aca4";
2436424364

2436524365
// Might add PROFILE later.
2436624366

0 commit comments

Comments
 (0)