[Fizz] Move formatContext tracking back to the task (#27325)
In https://github.com/facebook/react/pull/21113 I moved this over to the segment from the task. This partially reverts this two use two fields instead. I was just trying to micro-optimize by reusing a single field. This is really conceptually two different values. Task is keeping track of the working state of the currently executing context. The segment just needs to keep track of which parent context it was created in so that it can be wrapped correctly when a segment is written. We just happened to rely on the working state returning to the top before completing. The main motivation is that there is no `segment` for replaying.
Sebastian Markbåge committed
Sep 5, 2023 at 15:55 UTC
3cc8a9347bd540ac68acfb181fbc7fba7c371648
1 file changed
+23
-17
packages/react-server/src/ReactFizzServer.js
+23
-17
@@ -221,6 +221,7 @@ export type Task = {
221
blockedSegment: Segment, // the segment we'll write to
222
abortSet: Set<Task>, // the abortable set that this task belongs to
223
keyPath: Root | KeyNode, // the path of all parent keys currently rendering
224
+ formatContext: FormatContext, // the format's specific context (e.g. HTML/SVG/MathML)
225
legacyContext: LegacyContext, // the current legacy context that this task is executing in
226
context: ContextSnapshot, // the current new context that this task is executing in
227
treeContext: TreeContext, // the current tree context that this task is executing in
@@ -245,7 +246,7 @@ type Segment = {
246
+chunks: Array<Chunk | PrecomputedChunk>,
247
+children: Array<Segment>,
248
// The context that this segment was created in.
248
- formatContext: FormatContext,
249
+ parentFormatContext: FormatContext,
250
// If this segment represents a fallback, this is the content that will replace that fallback.
251
+boundary: null | SuspenseBoundary,
252
// used to discern when text separator boundaries are needed
@@ -386,6 +387,7 @@ export function createRequest(
387
rootSegment,
388
abortSet,
389
null,
390
+ rootFormatContext,
391
emptyContextObject,
392
rootContextSnapshot,
393
emptyTreeContext,
@@ -442,6 +444,7 @@ function createTask(
444
blockedSegment: Segment,
445
abortSet: Set<Task>,
446
keyPath: Root | KeyNode,
447
+ formatContext: FormatContext,
448
legacyContext: LegacyContext,
449
context: ContextSnapshot,
450
treeContext: TreeContext,
@@ -459,6 +462,7 @@ function createTask(
462
blockedSegment,
463
abortSet,
464
keyPath,
465
+ formatContext,
466
legacyContext,
467
context,
468
treeContext,
@@ -475,7 +479,7 @@ function createPendingSegment(
479
request: Request,
480
index: number,
481
boundary: null | SuspenseBoundary,
478
- formatContext: FormatContext,
482
+ parentFormatContext: FormatContext,
483
lastPushedText: boolean,
484
textEmbedded: boolean,
485
): Segment {
@@ -486,7 +490,7 @@ function createPendingSegment(
490
parentFlushed: false,
491
chunks: [],
492
children: [],
489
- formatContext,
493
+ parentFormatContext,
494
boundary,
495
lastPushedText,
496
textEmbedded,
@@ -635,7 +639,7 @@ function renderSuspenseBoundary(
639
request,
640
insertionIndex,
641
newBoundary,
638
- parentSegment.formatContext,
642
+ task.formatContext,
643
// boundaries never require text embedding at their edges because comment nodes bound them
644
false,
645
false,
@@ -649,7 +653,7 @@ function renderSuspenseBoundary(
653
request,
654
0,
655
null,
652
- parentSegment.formatContext,
656
+ task.formatContext,
657
// boundaries never require text embedding at their edges because comment nodes bound them
658
false,
659
false,
@@ -739,6 +743,7 @@ function renderSuspenseBoundary(
743
boundarySegment,
744
fallbackAbortSet,
745
task.keyPath,
746
+ task.formatContext,
747
task.legacyContext,
748
task.context,
749
task.treeContext,
@@ -785,12 +790,12 @@ function renderHostElement(
790
props,
791
request.resumableState,
792
request.renderState,
788
- segment.formatContext,
793
+ task.formatContext,
794
segment.lastPushedText,
795
);
796
segment.lastPushedText = false;
792
- const prevContext = segment.formatContext;
793
- segment.formatContext = getChildFormatContext(prevContext, type, props);
797
+ const prevContext = task.formatContext;
798
+ task.formatContext = getChildFormatContext(prevContext, type, props);
799
800
// We use the non-destructive form because if something suspends, we still
801
// need to pop back up and finish this subtree of HTML.
@@ -798,7 +803,7 @@ function renderHostElement(
803
804
// We expect that errors will fatal the whole task and that we don't need
805
// the correct context. Therefore this is not in a finally.
801
- segment.formatContext = prevContext;
806
+ task.formatContext = prevContext;
807
pushEndInstance(
808
segment.chunks,
809
type,
@@ -1740,7 +1745,7 @@ function injectPostponedHole(
1745
request,
1746
insertionIndex,
1747
null,
1743
- segment.formatContext,
1748
+ task.formatContext,
1749
// Adopt the parent segment's leading text embed
1750
segment.lastPushedText,
1751
// Assume we are text embedded at the trailing edge
@@ -1765,7 +1770,7 @@ function spawnNewSuspendedTask(
1770
request,
1771
insertionIndex,
1772
null,
1768
- segment.formatContext,
1773
+ task.formatContext,
1774
// Adopt the parent segment's leading text embed
1775
segment.lastPushedText,
1776
// Assume we are text embedded at the trailing edge
@@ -1782,6 +1787,7 @@ function spawnNewSuspendedTask(
1787
newSegment,
1788
task.abortSet,
1789
task.keyPath,
1790
+ task.formatContext,
1791
task.legacyContext,
1792
task.context,
1793
task.treeContext,
@@ -1814,7 +1820,7 @@ function renderNode(
1820
1821
// Snapshot the current context in case something throws to interrupt the
1822
// process.
1817
- const previousFormatContext = task.blockedSegment.formatContext;
1823
+ const previousFormatContext = task.formatContext;
1824
const previousLegacyContext = task.legacyContext;
1825
const previousContext = task.context;
1826
const previousKeyPath = task.keyPath;
@@ -1850,7 +1856,7 @@ function renderNode(
1856
1857
// Restore the context. We assume that this will be restored by the inner
1858
// functions in case nothing throws so we don't use "finally" here.
1853
- task.blockedSegment.formatContext = previousFormatContext;
1859
+ task.formatContext = previousFormatContext;
1860
task.legacyContext = previousLegacyContext;
1861
task.context = previousContext;
1862
task.keyPath = previousKeyPath;
@@ -1882,7 +1888,7 @@ function renderNode(
1888
1889
// Restore the context. We assume that this will be restored by the inner
1890
// functions in case nothing throws so we don't use "finally" here.
1885
- task.blockedSegment.formatContext = previousFormatContext;
1891
+ task.formatContext = previousFormatContext;
1892
task.legacyContext = previousLegacyContext;
1893
task.context = previousContext;
1894
task.keyPath = previousKeyPath;
@@ -1896,7 +1902,7 @@ function renderNode(
1902
}
1903
// Restore the context. We assume that this will be restored by the inner
1904
// functions in case nothing throws so we don't use "finally" here.
1899
- task.blockedSegment.formatContext = previousFormatContext;
1905
+ task.formatContext = previousFormatContext;
1906
task.legacyContext = previousLegacyContext;
1907
task.context = previousContext;
1908
task.keyPath = previousKeyPath;
@@ -2474,11 +2480,11 @@ function flushSegmentContainer(
2480
writeStartSegment(
2481
destination,
2482
request.renderState,
2477
- segment.formatContext,
2483
+ segment.parentFormatContext,
2484
segment.id,
2485
);
2486
flushSegment(request, destination, segment);
2481
- return writeEndSegment(destination, segment.formatContext);
2487
+ return writeEndSegment(destination, segment.parentFormatContext);
2488
}
2489
2490
function flushCompletedBoundary(