Skip to content

Commit 0909efb

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 dbadfa2 commit 0909efb

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

@@ -58,6 +59,7 @@ export type ResponseState = {
5859
sentCompleteSegmentFunction: boolean,
5960
sentCompleteBoundaryFunction: boolean,
6061
sentClientRenderFunction: boolean,
62+
hasEmittedRoot: boolean,
6163
};
6264

6365
// Allows us to keep track of what we've already written so we can refer back to it.
@@ -73,6 +75,7 @@ export function createResponseState(
7375
sentCompleteSegmentFunction: false,
7476
sentCompleteBoundaryFunction: false,
7577
sentClientRenderFunction: false,
78+
hasEmittedRoot: false,
7679
};
7780
}
7881

@@ -93,7 +96,7 @@ type InsertionMode = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
9396

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

@@ -486,6 +489,19 @@ const endOfStartTagSelfClosing = stringToPrecomputedChunk('/>');
486489
const idAttr = stringToPrecomputedChunk(' id="');
487490
const attrEnd = stringToPrecomputedChunk('"');
488491

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

621638
target.push(endOfStartTag);
622639
pushInnerHTML(target, innerHTML, children);
@@ -730,6 +747,7 @@ function pushStartOption(
730747
if (assignID !== null) {
731748
pushID(target, responseState, assignID, props.id);
732749
}
750+
pushReactRoot(target, responseState);
733751

734752
target.push(endOfStartTag);
735753
return children;
@@ -817,6 +835,7 @@ function pushInput(
817835
if (assignID !== null) {
818836
pushID(target, responseState, assignID, props.id);
819837
}
838+
pushReactRoot(target, responseState);
820839

821840
target.push(endOfStartTagSelfClosing);
822841
return null;
@@ -881,6 +900,7 @@ function pushStartTextArea(
881900
if (assignID !== null) {
882901
pushID(target, responseState, assignID, props.id);
883902
}
903+
pushReactRoot(target, responseState);
884904

885905
target.push(endOfStartTag);
886906

@@ -957,6 +977,7 @@ function pushSelfClosing(
957977
if (assignID !== null) {
958978
pushID(target, responseState, assignID, props.id);
959979
}
980+
pushReactRoot(target, responseState);
960981

961982
target.push(endOfStartTagSelfClosing);
962983
return null;
@@ -993,6 +1014,7 @@ function pushStartMenuItem(
9931014
if (assignID !== null) {
9941015
pushID(target, responseState, assignID, props.id);
9951016
}
1017+
pushReactRoot(target, responseState);
9961018

9971019
target.push(endOfStartTag);
9981020
return null;
@@ -1031,6 +1053,7 @@ function pushStartGenericElement(
10311053
if (assignID !== null) {
10321054
pushID(target, responseState, assignID, props.id);
10331055
}
1056+
pushReactRoot(target, responseState);
10341057

10351058
target.push(endOfStartTag);
10361059
pushInnerHTML(target, innerHTML, children);
@@ -1089,6 +1112,7 @@ function pushStartCustomElement(
10891112
if (assignID !== null) {
10901113
pushID(target, responseState, assignID, props.id);
10911114
}
1115+
pushReactRoot(target, responseState);
10921116

10931117
target.push(endOfStartTag);
10941118
pushInnerHTML(target, innerHTML, children);
@@ -1130,6 +1154,7 @@ function pushStartPreformattedElement(
11301154
if (assignID !== null) {
11311155
pushID(target, responseState, assignID, props.id);
11321156
}
1157+
pushReactRoot(target, responseState);
11331158

11341159
target.push(endOfStartTag);
11351160

0 commit comments

Comments
 (0)