@samitouri / QOS-React / commits / 3cc8a9347b

[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(