Add separator comment between text nodes (#21099)
This is needed to avoid mutating the DOM during hydration. This *always* adds it even when it's just text children. We need to avoid this overhead but it's a somewhat tricky problem to solve so we defer the optimization to later.
Sebastian Markbåge committed
Mar 25, 2021 at 11:48 UTC
6a589ad711db330c68a371321450ee2f0087e22f
3 files changed
+19
-8
packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
+4
-2
@@ -55,7 +55,7 @@ describe('ReactDOMFizzServer', () => {
55
<div>hello world</div>,
56
);
57
const result = await readResult(stream);
58
- expect(result).toBe('<div>hello world</div>');
58
+ expect(result).toMatchInlineSnapshot(`"<div>hello world<!-- --></div>"`);
59
});
60
61
// @gate experimental
@@ -93,7 +93,9 @@ describe('ReactDOMFizzServer', () => {
93
expect(isComplete).toBe(true);
94
95
const result = await readResult(stream);
96
- expect(result).toBe('<div><!--$-->Done<!--/$--></div>');
96
+ expect(result).toMatchInlineSnapshot(
97
+ `"<div><!--$-->Done<!-- --><!--/$--></div>"`,
98
+ );
99
});
100
101
// @gate experimental
packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
+7
-5
@@ -65,7 +65,9 @@ describe('ReactDOMFizzServer', () => {
65
);
66
startWriting();
67
jest.runAllTimers();
68
- expect(output.result).toBe('<div>hello world</div>');
68
+ expect(output.result).toMatchInlineSnapshot(
69
+ `"<div>hello world<!-- --></div>"`,
70
+ );
71
});
72
73
// @gate experimental
@@ -81,8 +83,8 @@ describe('ReactDOMFizzServer', () => {
83
'<!doctype html><html><head><title>test</title><head><body>';
84
// Then React starts writing.
85
startWriting();
84
- expect(output.result).toBe(
85
- '<!doctype html><html><head><title>test</title><head><body><div>hello world</div>',
86
+ expect(output.result).toMatchInlineSnapshot(
87
+ `"<!doctype html><html><head><title>test</title><head><body><div>hello world<!-- --></div>"`,
88
);
89
});
90
@@ -129,8 +131,8 @@ describe('ReactDOMFizzServer', () => {
131
'<!doctype html><html><head><title>test</title><head><body>';
132
// Then React starts writing.
133
startWriting();
132
- expect(output.result).toBe(
133
- '<!doctype html><html><head><title>test</title><head><body><div><!--$-->Done<!--/$--></div>',
134
+ expect(output.result).toMatchInlineSnapshot(
135
+ `"<!doctype html><html><head><title>test</title><head><body><div><!--$-->Done<!-- --><!--/$--></div>"`,
136
);
137
});
138
packages/react-dom/src/server/ReactDOMServerFormatConfig.js
+8
-1
@@ -104,6 +104,8 @@ export function pushEmpty(
104
}
105
}
106
107
+const textSeparator = stringToPrecomputedChunk('<!-- -->');
108
+
109
export function pushTextInstance(
110
target: Array<Chunk | PrecomputedChunk>,
111
text: string,
@@ -113,7 +115,12 @@ export function pushTextInstance(
115
if (assignID !== null) {
116
pushDummyNodeWithID(target, responseState, assignID);
117
}
116
- target.push(stringToChunk(encodeHTMLTextNode(text)));
118
+ if (text === '') {
119
+ // Empty text doesn't have a DOM node representation and the hydration is aware of this.
120
+ return;
121
+ }
122
+ // TODO: Avoid adding a text separator in common cases.
123
+ target.push(stringToChunk(encodeHTMLTextNode(text)), textSeparator);
124
}
125
126
const startTag1 = stringToPrecomputedChunk('<');