mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
Add Flag to Favor Hydration Performance over User Safety (#28655)
If false, this ignores text comparison checks during hydration at the risk of privacy safety. Since React 18 we recreate the DOM starting from the nearest Suspense boundary if any of the text content mismatches. This ensures that if we have nodes that otherwise line up correctly such as if they're the same type of Component but in a different order, then we don't accidentally transfer state or attributes to the wrong one. If we didn't do this e.g. attributes like image src might not line up with the text. E.g. you might show the wrong profile picture with the wrong name. However, the main reason we do this is because it's a security/privacy concern if state from the original node can transfer to the other one. For example if you start typing into a text field to reply to a story but then it turns out that the hydration was in a different order, you might submit that text into a different story than you intended. Similarly, if you've already clicked an item and that gets replayed using Action replaying or is synchronously force hydrated - that click might end up applying to a different item in the list than you intended. E.g. liking the wrong photo. Unfortunately a common case where this happens is when Google Translate is applied to a page. It'll always cause mismatches and recreate the tree. Most of the time this wouldn't be visible to users because it'd just recreate to the same thing and then translate again. It can affect metrics that trace when this hydration happened though. Meta can use this flag to decide if they favor this perf metric over the risk to user privacy. This is similar to the old enableClientRenderFallbackOnTextMismatch flag except this flag doesn't patch up the text when there's a mismatch. Because we don't have the patching anymore. The assumption is that it is safe to ignore the safety concern because we assume it's a match and therefore favoring not patching it will lead to better perf.
This commit is contained in:
committed by
GitHub
parent
2ec2aaea98
commit
5910eb3456
@@ -4423,6 +4423,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
);
|
||||
});
|
||||
|
||||
// @gate favorSafetyOverHydrationPerf
|
||||
it('#24384: Suspending should halt hydration warnings but still emit hydration warnings after unsuspending if mismatches are genuine', async () => {
|
||||
const makeApp = () => {
|
||||
let resolve, resolved;
|
||||
@@ -4506,6 +4507,7 @@ describe('ReactDOMFizzServer', () => {
|
||||
await waitForAll([]);
|
||||
});
|
||||
|
||||
// @gate favorSafetyOverHydrationPerf
|
||||
it('only warns once on hydration mismatch while within a suspense boundary', async () => {
|
||||
const originalConsoleError = console.error;
|
||||
const mockError = jest.fn();
|
||||
|
||||
@@ -6446,6 +6446,7 @@ body {
|
||||
);
|
||||
});
|
||||
|
||||
// @gate favorSafetyOverHydrationPerf
|
||||
it('retains styles even when a new html, head, and/body mount', async () => {
|
||||
await act(() => {
|
||||
const {pipe} = renderToPipeableStream(
|
||||
@@ -8230,6 +8231,7 @@ background-color: green;
|
||||
]);
|
||||
});
|
||||
|
||||
// @gate favorSafetyOverHydrationPerf
|
||||
it('can render a title before a singleton even if that singleton clears its contents', async () => {
|
||||
await act(() => {
|
||||
const {pipe} = renderToPipeableStream(
|
||||
|
||||
@@ -80,30 +80,55 @@ describe('ReactDOMServerHydration', () => {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
|
||||
"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:
|
||||
if (gate(flags => flags.favorSafetyOverHydrationPerf)) {
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
|
||||
"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:
|
||||
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
|
||||
https://react.dev/link/hydration-mismatch
|
||||
https://react.dev/link/hydration-mismatch
|
||||
|
||||
<Mismatch isClient={true}>
|
||||
<div className="parent">
|
||||
<main className="child">
|
||||
+ client
|
||||
- server
|
||||
]",
|
||||
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
|
||||
]
|
||||
`);
|
||||
<Mismatch isClient={true}>
|
||||
<div className="parent">
|
||||
<main className="child">
|
||||
+ client
|
||||
- server
|
||||
]",
|
||||
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
|
||||
]
|
||||
`);
|
||||
} else {
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"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:
|
||||
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
|
||||
https://react.dev/link/hydration-mismatch
|
||||
|
||||
<Mismatch isClient={true}>
|
||||
<div className="parent">
|
||||
<main className="child">
|
||||
+ client
|
||||
- server
|
||||
",
|
||||
]
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
// @gate __DEV__
|
||||
@@ -120,29 +145,53 @@ describe('ReactDOMServerHydration', () => {
|
||||
}
|
||||
|
||||
/* eslint-disable no-irregular-whitespace */
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
|
||||
"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:
|
||||
if (gate(flags => flags.favorSafetyOverHydrationPerf)) {
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
|
||||
"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:
|
||||
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
|
||||
https://react.dev/link/hydration-mismatch
|
||||
https://react.dev/link/hydration-mismatch
|
||||
|
||||
<Mismatch isClient={true}>
|
||||
<div>
|
||||
+ This markup contains an nbsp entity: client text
|
||||
- This markup contains an nbsp entity: server text
|
||||
]",
|
||||
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
|
||||
]
|
||||
`);
|
||||
<Mismatch isClient={true}>
|
||||
<div>
|
||||
+ This markup contains an nbsp entity: client text
|
||||
- This markup contains an nbsp entity: server text
|
||||
]",
|
||||
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
|
||||
]
|
||||
`);
|
||||
} else {
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"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:
|
||||
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
|
||||
https://react.dev/link/hydration-mismatch
|
||||
|
||||
<Mismatch isClient={true}>
|
||||
<div>
|
||||
+ This markup contains an nbsp entity: client text
|
||||
- This markup contains an nbsp entity: server text
|
||||
",
|
||||
]
|
||||
`);
|
||||
}
|
||||
/* eslint-enable no-irregular-whitespace */
|
||||
});
|
||||
|
||||
@@ -549,29 +598,53 @@ describe('ReactDOMServerHydration', () => {
|
||||
function Mismatch({isClient}) {
|
||||
return <div className="parent">{isClient && 'only'}</div>;
|
||||
}
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
|
||||
"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:
|
||||
if (gate(flags => flags.favorSafetyOverHydrationPerf)) {
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"Warning: An error occurred during hydration. The server HTML was replaced with client content.",
|
||||
"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:
|
||||
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
|
||||
https://react.dev/link/hydration-mismatch
|
||||
https://react.dev/link/hydration-mismatch
|
||||
|
||||
<Mismatch isClient={true}>
|
||||
<div className="parent">
|
||||
+ only
|
||||
-
|
||||
]",
|
||||
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
|
||||
]
|
||||
`);
|
||||
<Mismatch isClient={true}>
|
||||
<div className="parent">
|
||||
+ only
|
||||
-
|
||||
]",
|
||||
"Caught [There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.]",
|
||||
]
|
||||
`);
|
||||
} else {
|
||||
expect(testMismatch(Mismatch)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"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:
|
||||
|
||||
- A server/client branch \`if (typeof window !== 'undefined')\`.
|
||||
- Variable input such as \`Date.now()\` or \`Math.random()\` which changes each time it's called.
|
||||
- Date formatting in a user's locale which doesn't match the server.
|
||||
- External changing data without sending a snapshot of it along with the HTML.
|
||||
- Invalid HTML tag nesting.
|
||||
|
||||
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
|
||||
|
||||
https://react.dev/link/hydration-mismatch
|
||||
|
||||
<Mismatch isClient={true}>
|
||||
<div className="parent">
|
||||
+ only
|
||||
-
|
||||
",
|
||||
]
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
// @gate __DEV__
|
||||
|
||||
@@ -3816,6 +3816,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
);
|
||||
});
|
||||
|
||||
// @gate favorSafetyOverHydrationPerf
|
||||
it("falls back to client rendering when there's a text mismatch (direct text child)", async () => {
|
||||
function DirectTextChild({text}) {
|
||||
return <div>{text}</div>;
|
||||
@@ -3845,6 +3846,7 @@ describe('ReactDOMServerPartialHydration', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
// @gate favorSafetyOverHydrationPerf
|
||||
it("falls back to client rendering when there's a text mismatch (text child with siblings)", async () => {
|
||||
function Sibling() {
|
||||
return 'Sibling';
|
||||
|
||||
@@ -276,6 +276,9 @@ describe('rendering React components at document', () => {
|
||||
);
|
||||
const testDocument = getTestDocument(markup);
|
||||
|
||||
const favorSafetyOverHydrationPerf = gate(
|
||||
flags => flags.favorSafetyOverHydrationPerf,
|
||||
);
|
||||
expect(() => {
|
||||
ReactDOM.flushSync(() => {
|
||||
ReactDOMClient.hydrateRoot(
|
||||
@@ -291,19 +294,29 @@ describe('rendering React components at document', () => {
|
||||
);
|
||||
});
|
||||
}).toErrorDev(
|
||||
[
|
||||
'Warning: An error occurred during hydration. The server HTML was replaced with client content.',
|
||||
],
|
||||
favorSafetyOverHydrationPerf
|
||||
? [
|
||||
'Warning: An error occurred during hydration. The server HTML was replaced with client content.',
|
||||
]
|
||||
: [
|
||||
"Warning: A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.",
|
||||
],
|
||||
{
|
||||
withoutStack: 1,
|
||||
},
|
||||
);
|
||||
|
||||
assertLog([
|
||||
"Log recoverable error: Hydration failed because the server rendered HTML didn't match the client.",
|
||||
'Log recoverable error: There was an error while hydrating.',
|
||||
]);
|
||||
expect(testDocument.body.innerHTML).toBe('Hello world');
|
||||
assertLog(
|
||||
favorSafetyOverHydrationPerf
|
||||
? [
|
||||
"Log recoverable error: Hydration failed because the server rendered HTML didn't match the client.",
|
||||
'Log recoverable error: There was an error while hydrating.',
|
||||
]
|
||||
: [],
|
||||
);
|
||||
expect(testDocument.body.innerHTML).toBe(
|
||||
favorSafetyOverHydrationPerf ? 'Hello world' : 'Goodbye world',
|
||||
);
|
||||
});
|
||||
|
||||
it('should render w/ no markup to full document', async () => {
|
||||
|
||||
@@ -123,6 +123,9 @@ describe('ReactDOMServerHydration', () => {
|
||||
// Now simulate a situation where the app is not idempotent. React should
|
||||
// warn but do the right thing.
|
||||
element.innerHTML = lastMarkup;
|
||||
const favorSafetyOverHydrationPerf = gate(
|
||||
flags => flags.favorSafetyOverHydrationPerf,
|
||||
);
|
||||
await expect(async () => {
|
||||
root = await act(() => {
|
||||
return ReactDOMClient.hydrateRoot(
|
||||
@@ -139,14 +142,22 @@ describe('ReactDOMServerHydration', () => {
|
||||
);
|
||||
});
|
||||
}).toErrorDev(
|
||||
[
|
||||
'An error occurred during hydration. The server HTML was replaced with client content.',
|
||||
],
|
||||
favorSafetyOverHydrationPerf
|
||||
? [
|
||||
'An error occurred during hydration. The server HTML was replaced with client content.',
|
||||
]
|
||||
: [
|
||||
" A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.",
|
||||
],
|
||||
{withoutStack: 1},
|
||||
);
|
||||
expect(mountCount).toEqual(4);
|
||||
expect(element.innerHTML.length > 0).toBe(true);
|
||||
expect(element.innerHTML).not.toEqual(lastMarkup);
|
||||
if (favorSafetyOverHydrationPerf) {
|
||||
expect(element.innerHTML).not.toEqual(lastMarkup);
|
||||
} else {
|
||||
expect(element.innerHTML).toEqual(lastMarkup);
|
||||
}
|
||||
|
||||
// Ensure the events system works after markup mismatch.
|
||||
expect(numClicks).toEqual(1);
|
||||
@@ -212,6 +223,9 @@ describe('ReactDOMServerHydration', () => {
|
||||
const onFocusAfterHydration = jest.fn();
|
||||
element.firstChild.focus = onFocusBeforeHydration;
|
||||
|
||||
const favorSafetyOverHydrationPerf = gate(
|
||||
flags => flags.favorSafetyOverHydrationPerf,
|
||||
);
|
||||
await expect(async () => {
|
||||
await act(() => {
|
||||
ReactDOMClient.hydrateRoot(
|
||||
@@ -223,9 +237,13 @@ describe('ReactDOMServerHydration', () => {
|
||||
);
|
||||
});
|
||||
}).toErrorDev(
|
||||
[
|
||||
'An error occurred during hydration. The server HTML was replaced with client content.',
|
||||
],
|
||||
favorSafetyOverHydrationPerf
|
||||
? [
|
||||
'An error occurred during hydration. The server HTML was replaced with client content.',
|
||||
]
|
||||
: [
|
||||
"A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.",
|
||||
],
|
||||
{withoutStack: 1},
|
||||
);
|
||||
|
||||
@@ -514,6 +532,9 @@ describe('ReactDOMServerHydration', () => {
|
||||
);
|
||||
domElement.innerHTML = markup;
|
||||
|
||||
const favorSafetyOverHydrationPerf = gate(
|
||||
flags => flags.favorSafetyOverHydrationPerf,
|
||||
);
|
||||
await expect(async () => {
|
||||
await act(() => {
|
||||
ReactDOMClient.hydrateRoot(
|
||||
@@ -524,14 +545,22 @@ describe('ReactDOMServerHydration', () => {
|
||||
{onRecoverableError: error => {}},
|
||||
);
|
||||
});
|
||||
|
||||
expect(domElement.innerHTML).not.toEqual(markup);
|
||||
}).toErrorDev(
|
||||
[
|
||||
'An error occurred during hydration. The server HTML was replaced with client content.',
|
||||
],
|
||||
favorSafetyOverHydrationPerf
|
||||
? [
|
||||
'An error occurred during hydration. The server HTML was replaced with client content.',
|
||||
]
|
||||
: [
|
||||
" A tree hydrated but some attributes of the server rendered HTML didn't match the client properties.",
|
||||
],
|
||||
{withoutStack: 1},
|
||||
);
|
||||
|
||||
if (favorSafetyOverHydrationPerf) {
|
||||
expect(domElement.innerHTML).not.toEqual(markup);
|
||||
} else {
|
||||
expect(domElement.innerHTML).toEqual(markup);
|
||||
}
|
||||
});
|
||||
|
||||
it('should warn if innerHTML mismatches with dangerouslySetInnerHTML=undefined on the client', async () => {
|
||||
|
||||
@@ -17,10 +17,12 @@ module.exports = function (initModules) {
|
||||
let ReactDOMClient;
|
||||
let ReactDOMServer;
|
||||
let act;
|
||||
let ReactFeatureFlags;
|
||||
|
||||
function resetModules() {
|
||||
({ReactDOM, ReactDOMClient, ReactDOMServer} = initModules());
|
||||
act = require('internal-test-utils').act;
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
}
|
||||
|
||||
function shouldUseDocument(reactElement) {
|
||||
@@ -276,8 +278,10 @@ module.exports = function (initModules) {
|
||||
const cleanTextContent =
|
||||
(cleanContainer.lastChild && cleanContainer.lastChild.textContent) || '';
|
||||
|
||||
// The only guarantee is that text content has been patched up if needed.
|
||||
expect(hydratedTextContent).toBe(cleanTextContent);
|
||||
if (ReactFeatureFlags.favorSafetyOverHydrationPerf) {
|
||||
// The only guarantee is that text content has been patched up if needed.
|
||||
expect(hydratedTextContent).toBe(cleanTextContent);
|
||||
}
|
||||
|
||||
// Abort any further expects. All bets are off at this point.
|
||||
throw new BadMarkupExpected();
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
HostRoot,
|
||||
SuspenseComponent,
|
||||
} from './ReactWorkTags';
|
||||
import {favorSafetyOverHydrationPerf} from 'shared/ReactFeatureFlags';
|
||||
|
||||
import {createFiberFromDehydratedFragment} from './ReactFiber';
|
||||
import {
|
||||
@@ -472,7 +473,7 @@ function prepareToHydrateHostInstance(
|
||||
hostContext,
|
||||
fiber,
|
||||
);
|
||||
if (!didHydrate) {
|
||||
if (!didHydrate && favorSafetyOverHydrationPerf) {
|
||||
throwOnHydrationMismatch(fiber);
|
||||
}
|
||||
}
|
||||
@@ -538,7 +539,7 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): void {
|
||||
fiber,
|
||||
parentProps,
|
||||
);
|
||||
if (!didHydrate) {
|
||||
if (!didHydrate && favorSafetyOverHydrationPerf) {
|
||||
throwOnHydrationMismatch(fiber);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ export const enableComponentStackLocations = true;
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// TODO: Finish rolling out in www
|
||||
export const favorSafetyOverHydrationPerf = true;
|
||||
export const enableAsyncActions = true;
|
||||
|
||||
// Need to remove didTimeout argument from Scheduler before landing
|
||||
|
||||
@@ -65,6 +65,7 @@ export const enableSuspenseAvoidThisFallbackFizz = false;
|
||||
export const enableCPUSuspense = true;
|
||||
export const enableUseMemoCacheHook = true;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const favorSafetyOverHydrationPerf = true;
|
||||
export const enableLegacyFBSupport = false;
|
||||
export const enableFilterEmptyStringAttributesDOM = true;
|
||||
export const enableGetInspectorDataForInstanceInProduction = true;
|
||||
|
||||
@@ -87,6 +87,7 @@ export const disableTextareaChildren = false;
|
||||
export const enableSuspenseAvoidThisFallback = false;
|
||||
export const enableSuspenseAvoidThisFallbackFizz = false;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const favorSafetyOverHydrationPerf = true;
|
||||
export const enableLegacyFBSupport = false;
|
||||
export const enableFilterEmptyStringAttributesDOM = true;
|
||||
export const enableGetInspectorDataForInstanceInProduction = false;
|
||||
|
||||
@@ -39,6 +39,7 @@ export const enableSuspenseAvoidThisFallbackFizz = false;
|
||||
export const enableCPUSuspense = false;
|
||||
export const enableUseMemoCacheHook = true;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const favorSafetyOverHydrationPerf = true;
|
||||
export const enableComponentStackLocations = true;
|
||||
export const enableLegacyFBSupport = false;
|
||||
export const enableFilterEmptyStringAttributesDOM = true;
|
||||
|
||||
@@ -45,6 +45,7 @@ export const enableSuspenseAvoidThisFallbackFizz = false;
|
||||
export const enableCPUSuspense = false;
|
||||
export const enableUseMemoCacheHook = true;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const favorSafetyOverHydrationPerf = true;
|
||||
export const enableUseRefAccessWarning = false;
|
||||
export const enableInfiniteRenderLoopDetection = false;
|
||||
export const enableRenderableContext = false;
|
||||
|
||||
@@ -41,6 +41,7 @@ export const enableSuspenseAvoidThisFallbackFizz = false;
|
||||
export const enableCPUSuspense = false;
|
||||
export const enableUseMemoCacheHook = true;
|
||||
export const enableUseEffectEventHook = false;
|
||||
export const favorSafetyOverHydrationPerf = true;
|
||||
export const enableComponentStackLocations = true;
|
||||
export const enableLegacyFBSupport = false;
|
||||
export const enableFilterEmptyStringAttributesDOM = true;
|
||||
|
||||
@@ -60,6 +60,8 @@ export const enableUseEffectEventHook = true;
|
||||
export const enableFilterEmptyStringAttributesDOM = true;
|
||||
export const enableAsyncActions = true;
|
||||
|
||||
export const favorSafetyOverHydrationPerf = false;
|
||||
|
||||
// Logs additional User Timing API marks for use with an experimental profiling tool.
|
||||
export const enableSchedulingProfiler: boolean =
|
||||
__PROFILE__ && dynamicFeatureFlags.enableSchedulingProfiler;
|
||||
|
||||
Reference in New Issue
Block a user