Skip to content

Commit 0aa22fd

Browse files
committed
Emit reactroot attribute on the first element we discover
This may not be the first root element if the root is a fragment and the second one unsuspends first. But this tag doesn't work well for root fragments anyway.
1 parent b9e4c10 commit 0aa22fd

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

packages/react-dom/src/server/ReactDOMServerFormatConfig.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
OVERLOADED_BOOLEAN,
3333
NUMERIC,
3434
POSITIVE_NUMERIC,
35+
ROOT_ATTRIBUTE_NAME,
3536
} from '../shared/DOMProperty';
3637
import {isUnitlessNumber} from '../shared/CSSProperty';
3738

@@ -59,6 +60,7 @@ export type ResponseState = {
5960
sentCompleteSegmentFunction: boolean,
6061
sentCompleteBoundaryFunction: boolean,
6162
sentClientRenderFunction: boolean,
63+
hasEmittedRoot: boolean,
6264
};
6365

6466
// Allows us to keep track of what we've already written so we can refer back to it.
@@ -74,6 +76,7 @@ export function createResponseState(
7476
sentCompleteSegmentFunction: false,
7577
sentCompleteBoundaryFunction: false,
7678
sentClientRenderFunction: false,
79+
hasEmittedRoot: false,
7780
};
7881
}
7982

@@ -94,7 +97,7 @@ type InsertionMode = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
9497

9598
// Lets us keep track of contextual state and pick it back up after suspending.
9699
export type FormatContext = {
97-
insertionMode: InsertionMode, // root/svg/html/mathml/table
100+
insertionMode: InsertionMode, // svg/html/mathml/table
98101
selectedValue: null | string | Array<string>, // the selected value(s) inside a <select>, or null outside <select>
99102
};
100103

@@ -487,6 +490,19 @@ const endOfStartTagSelfClosing = stringToPrecomputedChunk('/>');
487490
const idAttr = stringToPrecomputedChunk(' id="');
488491
const attrEnd = stringToPrecomputedChunk('"');
489492

493+
const reactRootAttribute = stringToPrecomputedChunk(
494+
' ' + ROOT_ATTRIBUTE_NAME + '=""',
495+
);
496+
function pushReactRoot(
497+
target: Array<Chunk | PrecomputedChunk>,
498+
responseState: ResponseState,
499+
): void {
500+
if (!responseState.hasEmittedRoot) {
501+
responseState.hasEmittedRoot = true;
502+
target.push(reactRootAttribute);
503+
}
504+
}
505+
490506
function pushID(
491507
target: Array<Chunk | PrecomputedChunk>,
492508
responseState: ResponseState,
@@ -618,6 +634,7 @@ function pushStartSelect(
618634
if (assignID !== null) {
619635
pushID(target, responseState, assignID, props.id);
620636
}
637+
pushReactRoot(target, responseState);
621638

622639
target.push(endOfStartTag);
623640
pushInnerHTML(target, innerHTML, children);
@@ -731,6 +748,7 @@ function pushStartOption(
731748
if (assignID !== null) {
732749
pushID(target, responseState, assignID, props.id);
733750
}
751+
pushReactRoot(target, responseState);
734752

735753
target.push(endOfStartTag);
736754
return children;
@@ -818,6 +836,7 @@ function pushInput(
818836
if (assignID !== null) {
819837
pushID(target, responseState, assignID, props.id);
820838
}
839+
pushReactRoot(target, responseState);
821840

822841
target.push(endOfStartTagSelfClosing);
823842
return null;
@@ -882,6 +901,7 @@ function pushStartTextArea(
882901
if (assignID !== null) {
883902
pushID(target, responseState, assignID, props.id);
884903
}
904+
pushReactRoot(target, responseState);
885905

886906
target.push(endOfStartTag);
887907

@@ -958,6 +978,7 @@ function pushSelfClosing(
958978
if (assignID !== null) {
959979
pushID(target, responseState, assignID, props.id);
960980
}
981+
pushReactRoot(target, responseState);
961982

962983
target.push(endOfStartTagSelfClosing);
963984
return null;
@@ -994,6 +1015,7 @@ function pushStartMenuItem(
9941015
if (assignID !== null) {
9951016
pushID(target, responseState, assignID, props.id);
9961017
}
1018+
pushReactRoot(target, responseState);
9971019

9981020
target.push(endOfStartTag);
9991021
return null;
@@ -1032,6 +1054,7 @@ function pushStartGenericElement(
10321054
if (assignID !== null) {
10331055
pushID(target, responseState, assignID, props.id);
10341056
}
1057+
pushReactRoot(target, responseState);
10351058

10361059
target.push(endOfStartTag);
10371060
pushInnerHTML(target, innerHTML, children);
@@ -1086,6 +1109,7 @@ function pushStartCustomElement(
10861109
if (assignID !== null) {
10871110
pushID(target, responseState, assignID, props.id);
10881111
}
1112+
pushReactRoot(target, responseState);
10891113

10901114
target.push(endOfStartTag);
10911115
pushInnerHTML(target, innerHTML, children);
@@ -1127,6 +1151,7 @@ function pushStartPreformattedElement(
11271151
if (assignID !== null) {
11281152
pushID(target, responseState, assignID, props.id);
11291153
}
1154+
pushReactRoot(target, responseState);
11301155

11311156
target.push(endOfStartTag);
11321157

0 commit comments

Comments
 (0)