Skip to content

Commit fe709a2

Browse files
committed
Add favorSafetyOverHydrationPerf flag
If false, this ignores text comparison checks during hydration at the risk of privacy safety.
1 parent 2ec2aae commit fe709a2

15 files changed

+294
-146
lines changed

packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js

+2
Original file line numberDiff line numberDiff line change
@@ -4423,6 +4423,7 @@ describe('ReactDOMFizzServer', () => {
44234423
);
44244424
});
44254425

4426+
// @gate favorSafetyOverHydrationPerf
44264427
it('#24384: Suspending should halt hydration warnings but still emit hydration warnings after unsuspending if mismatches are genuine', async () => {
44274428
const makeApp = () => {
44284429
let resolve, resolved;
@@ -4506,6 +4507,7 @@ describe('ReactDOMFizzServer', () => {
45064507
await waitForAll([]);
45074508
});
45084509

4510+
// @gate favorSafetyOverHydrationPerf
45094511
it('only warns once on hydration mismatch while within a suspense boundary', async () => {
45104512
const originalConsoleError = console.error;
45114513
const mockError = jest.fn();

packages/react-dom/src/__tests__/ReactDOMFloat-test.js

+2
Original file line numberDiff line numberDiff line change
@@ -6446,6 +6446,7 @@ body {
64466446
);
64476447
});
64486448

6449+
// @gate favorSafetyOverHydrationPerf
64496450
it('retains styles even when a new html, head, and/body mount', async () => {
64506451
await act(() => {
64516452
const {pipe} = renderToPipeableStream(
@@ -8230,6 +8231,7 @@ background-color: green;
82308231
]);
82318232
});
82328233

8234+
// @gate favorSafetyOverHydrationPerf || !__DEV__
82338235
it('can render a title before a singleton even if that singleton clears its contents', async () => {
82348236
await act(() => {
82358237
const {pipe} = renderToPipeableStream(

packages/react-dom/src/__tests__/ReactDOMHydrationDiff-test.js

+131-58
Original file line numberDiff line numberDiff line change
@@ -80,30 +80,55 @@ describe('ReactDOMServerHydration', () => {
8080
</div>
8181
);
8282
}
83-
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
84-
[
85-
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
86-
"Caught [Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
83+
if (gate(flags => flags.favorSafetyOverHydrationPerf)) {
84+
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
85+
[
86+
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
87+
"Caught [Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
88+
89+
- A server/client branch \`if (typeof window !== 'undefined')\`.
90+
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
91+
- Date formatting in a user's locale which doesn't match the server.
92+
- External changing data without sending a snapshot of it along with the HTML.
93+
- Invalid HTML tag nesting.
94+
95+
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
96+
97+
https://react.dev/link/hydration-mismatch
98+
99+
<Mismatch isClient={true}>
100+
<div className="parent">
101+
<main className="child">
102+
+ client
103+
- server
104+
]",
105+
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
106+
]
107+
`);
108+
} else {
109+
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
110+
[
111+
"Warning: A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
87112
88-
- A server/client branch \`if (typeof window !== 'undefined')\`.
89-
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
90-
- Date formatting in a user's locale which doesn't match the server.
91-
- External changing data without sending a snapshot of it along with the HTML.
92-
- Invalid HTML tag nesting.
113+
- A server/client branch \`if (typeof window !== 'undefined')\`.
114+
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
115+
- Date formatting in a user's locale which doesn't match the server.
116+
- External changing data without sending a snapshot of it along with the HTML.
117+
- Invalid HTML tag nesting.
93118
94-
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
119+
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
95120
96-
https://react.dev/link/hydration-mismatch
121+
https://react.dev/link/hydration-mismatch
97122
98-
<Mismatch isClient={true}>
99-
<div className="parent">
100-
<main className="child">
101-
+ client
102-
- server
103-
]",
104-
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
105-
]
106-
`);
123+
<Mismatch isClient={true}>
124+
<div className="parent">
125+
<main className="child">
126+
+ client
127+
- server
128+
",
129+
]
130+
`);
131+
}
107132
});
108133

109134
// @gate __DEV__
@@ -120,29 +145,53 @@ describe('ReactDOMServerHydration', () => {
120145
}
121146

122147
/* eslint-disable no-irregular-whitespace */
123-
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
124-
[
125-
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
126-
"Caught [Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
148+
if (gate(flags => flags.favorSafetyOverHydrationPerf)) {
149+
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
150+
[
151+
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
152+
"Caught [Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
127153
128-
- A server/client branch \`if (typeof window !== 'undefined')\`.
129-
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
130-
- Date formatting in a user's locale which doesn't match the server.
131-
- External changing data without sending a snapshot of it along with the HTML.
132-
- Invalid HTML tag nesting.
154+
- A server/client branch \`if (typeof window !== 'undefined')\`.
155+
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
156+
- Date formatting in a user's locale which doesn't match the server.
157+
- External changing data without sending a snapshot of it along with the HTML.
158+
- Invalid HTML tag nesting.
133159
134-
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
160+
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
135161
136-
https://react.dev/link/hydration-mismatch
162+
https://react.dev/link/hydration-mismatch
137163
138-
<Mismatch isClient={true}>
139-
<div>
140-
+ This markup contains an nbsp entity:   client text
141-
- This markup contains an nbsp entity:   server text
142-
]",
143-
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
144-
]
145-
`);
164+
<Mismatch isClient={true}>
165+
<div>
166+
+ This markup contains an nbsp entity:   client text
167+
- This markup contains an nbsp entity:   server text
168+
]",
169+
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
170+
]
171+
`);
172+
} else {
173+
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
174+
[
175+
"Warning: A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
176+
177+
- A server/client branch \`if (typeof window !== 'undefined')\`.
178+
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
179+
- Date formatting in a user's locale which doesn't match the server.
180+
- External changing data without sending a snapshot of it along with the HTML.
181+
- Invalid HTML tag nesting.
182+
183+
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
184+
185+
https://react.dev/link/hydration-mismatch
186+
187+
<Mismatch isClient={true}>
188+
<div>
189+
+ This markup contains an nbsp entity:   client text
190+
- This markup contains an nbsp entity:   server text
191+
",
192+
]
193+
`);
194+
}
146195
/* eslint-enable no-irregular-whitespace */
147196
});
148197

@@ -549,29 +598,53 @@ describe('ReactDOMServerHydration', () => {
549598
function Mismatch({isClient}) {
550599
return <div className="parent">{isClient && 'only'}</div>;
551600
}
552-
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
553-
[
554-
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
555-
"Caught [Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
601+
if (gate(flags => flags.favorSafetyOverHydrationPerf)) {
602+
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
603+
[
604+
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
605+
"Caught [Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
606+
607+
- A server/client branch \`if (typeof window !== 'undefined')\`.
608+
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
609+
- Date formatting in a user's locale which doesn't match the server.
610+
- External changing data without sending a snapshot of it along with the HTML.
611+
- Invalid HTML tag nesting.
612+
613+
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
614+
615+
https://react.dev/link/hydration-mismatch
616+
617+
<Mismatch isClient={true}>
618+
<div className="parent">
619+
+ only
620+
-
621+
]",
622+
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
623+
]
624+
`);
625+
} else {
626+
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
627+
[
628+
"Warning: A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
556629
557-
- A server/client branch \`if (typeof window !== 'undefined')\`.
558-
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
559-
- Date formatting in a user's locale which doesn't match the server.
560-
- External changing data without sending a snapshot of it along with the HTML.
561-
- Invalid HTML tag nesting.
630+
- A server/client branch \`if (typeof window !== 'undefined')\`.
631+
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
632+
- Date formatting in a user's locale which doesn't match the server.
633+
- External changing data without sending a snapshot of it along with the HTML.
634+
- Invalid HTML tag nesting.
562635
563-
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
636+
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
564637
565-
https://react.dev/link/hydration-mismatch
638+
https://react.dev/link/hydration-mismatch
566639
567-
<Mismatch isClient={true}>
568-
<div className="parent">
569-
+ only
570-
-
571-
]",
572-
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
573-
]
574-
`);
640+
<Mismatch isClient={true}>
641+
<div className="parent">
642+
+ only
643+
-
644+
",
645+
]
646+
`);
647+
}
575648
});
576649

577650
// @gate __DEV__

0 commit comments

Comments
 (0)