@samitouri / QOS-React-2 / commits / 6a589ad711

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('<');