Remove disableIEWorkarounds (#31756)
Based off https://github.com/facebook/react/pull/31755 This is landed everywhere.
Ricky committed
Dec 13, 2024 at 12:26 UTC
fb12845d779667b35cc7f44eee6bea47f4db72ba
12 files changed
+17
-255
packages/react-dom-bindings/src/client/ReactDOMComponent.js
+17
-43
@@ -16,7 +16,6 @@ import {
16
possibleRegistrationNames,
17
} from '../events/EventRegistry';
18
19
-import {canUseDOM} from 'shared/ExecutionEnvironment';
19
import {checkHtmlStringCoercion} from 'shared/CheckStringCoercion';
20
import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion';
21
import {checkControlledValueProps} from '../shared/ReactControlledValuePropTypes';
@@ -50,7 +49,6 @@ import {
49
} from './ReactDOMTextarea';
50
import {validateTextNesting} from './validateDOMNesting';
51
import {track} from './inputValueTracking';
53
-import setInnerHTML from './setInnerHTML';
52
import setTextContent from './setTextContent';
53
import {
54
createDangerousStringForStyles,
@@ -66,7 +64,6 @@ import {validateProperties as validateUnknownProperties} from '../shared/ReactDO
64
import sanitizeURL from '../shared/sanitizeURL';
65
66
import {
69
- disableIEWorkarounds,
67
enableTrustedTypesIntegration,
68
enableFilterEmptyStringAttributesDOM,
69
} from 'shared/ReactFeatureFlags';
@@ -83,19 +80,8 @@ let didWarnFormActionTarget = false;
80
let didWarnFormActionMethod = false;
81
let didWarnForNewBooleanPropsWithEmptyValue: {[string]: boolean};
82
let didWarnPopoverTargetObject = false;
86
-let canDiffStyleForHydrationWarning;
83
if (__DEV__) {
84
didWarnForNewBooleanPropsWithEmptyValue = {};
89
- // IE 11 parses & normalizes the style attribute as opposed to other
90
- // browsers. It adds spaces and sorts the properties in some
91
- // non-alphabetical order. Handling that would require sorting CSS
92
- // properties in the client & server versions or applying
93
- // `expectedStyle` to a temporary DOM node to read its `style` attribute
94
- // normalized. Since it only affects IE, we're skipping style warnings
95
- // in that browser completely in favor of doing all that work.
96
- // See https://github.com/facebook/react/issues/11807
97
- canDiffStyleForHydrationWarning =
98
- disableIEWorkarounds || (canUseDOM && !document.documentMode);
85
}
86
87
function validatePropertiesInDevelopment(type: string, props: any) {
@@ -579,11 +565,7 @@ function setProp(
565
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
566
);
567
}
582
- if (disableIEWorkarounds) {
583
- domElement.innerHTML = nextHtml;
584
- } else {
585
- setInnerHTML(domElement, nextHtml);
586
- }
568
+ domElement.innerHTML = nextHtml;
569
}
570
}
571
break;
@@ -939,11 +921,7 @@ function setPropOnCustomElement(
921
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
922
);
923
}
942
- if (disableIEWorkarounds) {
943
- domElement.innerHTML = nextHtml;
944
- } else {
945
- setInnerHTML(domElement, nextHtml);
946
- }
924
+ domElement.innerHTML = nextHtml;
925
}
926
}
927
break;
@@ -1931,27 +1909,23 @@ function diffHydratedStyles(
1909
}
1910
return;
1911
}
1934
- if (canDiffStyleForHydrationWarning) {
1935
- // First we compare the string form and see if it's equivalent.
1936
- // This lets us bail out on anything that used to pass in this form.
1937
- // It also lets us compare anything that's not parsed by this browser.
1938
- const clientValue = createDangerousStringForStyles(value);
1939
- const serverValue = domElement.getAttribute('style');
1912
+ // First we compare the string form and see if it's equivalent.
1913
+ // This lets us bail out on anything that used to pass in this form.
1914
+ // It also lets us compare anything that's not parsed by this browser.
1915
+ const clientValue = createDangerousStringForStyles(value);
1916
+ const serverValue = domElement.getAttribute('style');
1917
1941
- if (serverValue === clientValue) {
1942
- return;
1943
- }
1944
- const normalizedClientValue =
1945
- normalizeMarkupForTextOrAttribute(clientValue);
1946
- const normalizedServerValue =
1947
- normalizeMarkupForTextOrAttribute(serverValue);
1948
- if (normalizedServerValue === normalizedClientValue) {
1949
- return;
1950
- }
1951
-
1952
- // Otherwise, we create the object from the DOM for the diff view.
1953
- serverDifferences.style = getStylesObjectFromElement(domElement);
1918
+ if (serverValue === clientValue) {
1919
+ return;
1920
+ }
1921
+ const normalizedClientValue = normalizeMarkupForTextOrAttribute(clientValue);
1922
+ const normalizedServerValue = normalizeMarkupForTextOrAttribute(serverValue);
1923
+ if (normalizedServerValue === normalizedClientValue) {
1924
+ return;
1925
}
1926
+
1927
+ // Otherwise, we create the object from the DOM for the diff view.
1928
+ serverDifferences.style = getStylesObjectFromElement(domElement);
1929
}
1930
1931
function hydrateAttribute(
packages/react-dom-bindings/src/client/setInnerHTML.js
deleted
-82
@@ -1,82 +0,0 @@
1
-/**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @flow
8
- */
9
-
10
-/* globals MSApp */
11
-
12
-import {SVG_NAMESPACE} from './DOMNamespaces';
13
-import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags';
14
-
15
-// SVG temp container for IE lacking innerHTML
16
-let reusableSVGContainer: HTMLElement;
17
-
18
-function setInnerHTMLImpl(
19
- node: Element,
20
- html: {valueOf(): {toString(): string, ...}, ...},
21
-): void {
22
- if (node.namespaceURI === SVG_NAMESPACE) {
23
- if (__DEV__) {
24
- if (enableTrustedTypesIntegration) {
25
- // TODO: reconsider the text of this warning and when it should show
26
- // before enabling the feature flag.
27
- if (typeof trustedTypes !== 'undefined') {
28
- console.error(
29
- "Using 'dangerouslySetInnerHTML' in an svg element with " +
30
- 'Trusted Types enabled in an Internet Explorer will cause ' +
31
- 'the trusted value to be converted to string. Assigning string ' +
32
- "to 'innerHTML' will throw an error if Trusted Types are enforced. " +
33
- "You can try to wrap your svg element inside a div and use 'dangerouslySetInnerHTML' " +
34
- 'on the enclosing div instead.',
35
- );
36
- }
37
- }
38
- }
39
- if (!('innerHTML' in node)) {
40
- // IE does not have innerHTML for SVG nodes, so instead we inject the
41
- // new markup in a temp node and then move the child nodes across into
42
- // the target node
43
- reusableSVGContainer =
44
- reusableSVGContainer || document.createElement('div');
45
- reusableSVGContainer.innerHTML =
46
- '<svg>' + html.valueOf().toString() + '</svg>';
47
- const svgNode = reusableSVGContainer.firstChild;
48
- while (node.firstChild) {
49
- node.removeChild(node.firstChild);
50
- }
51
- // $FlowFixMe[incompatible-use]
52
- // $FlowFixMe[incompatible-type]
53
- while (svgNode.firstChild) {
54
- node.appendChild(svgNode.firstChild);
55
- }
56
- return;
57
- }
58
- }
59
- node.innerHTML = (html: any);
60
-}
61
-
62
-let setInnerHTML: (
63
- node: Element,
64
- html: {valueOf(): {toString(): string, ...}, ...},
65
-) => void = setInnerHTMLImpl;
66
-// $FlowFixMe[cannot-resolve-name]
67
-if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) {
68
- /**
69
- * Create a function which has 'unsafe' privileges (required by windows8 apps)
70
- */
71
- setInnerHTML = function (
72
- node: Element,
73
- html: {valueOf(): {toString(): string, ...}, ...},
74
- ): void {
75
- // $FlowFixMe[cannot-resolve-name]
76
- return MSApp.execUnsafeLocalFunction(function () {
77
- return setInnerHTMLImpl(node, html);
78
- });
79
- };
80
-}
81
-
82
-export default setInnerHTML;
packages/react-dom/src/client/__tests__/dangerouslySetInnerHTML-test.js
-69
@@ -27,73 +27,4 @@ describe('dangerouslySetInnerHTML', () => {
27
expect(container.firstChild.innerHTML).toBe('<h1>Hello</h1>');
28
});
29
});
30
-
31
- describe('when the node does not have an innerHTML property', () => {
32
- let innerHTMLDescriptor;
33
-
34
- // In some versions of IE (TODO: which ones?) SVG nodes don't have
35
- // innerHTML. To simulate this, we will take it off the Element prototype
36
- // and put it onto the HTMLDivElement prototype. We expect that the logic
37
- // checks for existence of innerHTML on SVG, and if one doesn't exist, falls
38
- // back to using appendChild and removeChild.
39
-
40
- beforeEach(() => {
41
- innerHTMLDescriptor = Object.getOwnPropertyDescriptor(
42
- Element.prototype,
43
- 'innerHTML',
44
- );
45
- delete Element.prototype.innerHTML;
46
- Object.defineProperty(
47
- HTMLDivElement.prototype,
48
- 'innerHTML',
49
- innerHTMLDescriptor,
50
- );
51
- });
52
-
53
- afterEach(() => {
54
- delete HTMLDivElement.prototype.innerHTML;
55
- Object.defineProperty(
56
- Element.prototype,
57
- 'innerHTML',
58
- innerHTMLDescriptor,
59
- );
60
- });
61
-
62
- // @gate !disableIEWorkarounds
63
- it('sets innerHTML on it', async () => {
64
- const html = '<circle></circle>';
65
- const container = document.createElementNS(
66
- 'http://www.w3.org/2000/svg',
67
- 'svg',
68
- );
69
- const root = ReactDOMClient.createRoot(container);
70
- await act(() => {
71
- root.render(<g dangerouslySetInnerHTML={{__html: html}} />);
72
- });
73
- const circle = container.firstChild.firstChild;
74
- expect(circle.tagName).toBe('circle');
75
- });
76
-
77
- // @gate !disableIEWorkarounds
78
- it('clears previous children', async () => {
79
- const firstHtml = '<rect></rect>';
80
- const secondHtml = '<circle></circle>';
81
-
82
- const container = document.createElementNS(
83
- 'http://www.w3.org/2000/svg',
84
- 'svg',
85
- );
86
- const root = ReactDOMClient.createRoot(container);
87
- await act(() => {
88
- root.render(<g dangerouslySetInnerHTML={{__html: firstHtml}} />);
89
- });
90
- const rect = container.firstChild.firstChild;
91
- expect(rect.tagName).toBe('rect');
92
- await act(() => {
93
- root.render(<g dangerouslySetInnerHTML={{__html: secondHtml}} />);
94
- });
95
- const circle = container.firstChild.firstChild;
96
- expect(circle.tagName).toBe('circle');
97
- });
98
- });
30
});
packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js
-50
@@ -206,56 +206,6 @@ describe('when Trusted Types are available in global object', () => {
206
}
207
});
208
209
- describe('dangerouslySetInnerHTML in svg elements in Internet Explorer', () => {
210
- let innerHTMLDescriptor;
211
-
212
- // simulate svg elements in Internet Explorer which don't have 'innerHTML' property
213
- beforeEach(() => {
214
- innerHTMLDescriptor = Object.getOwnPropertyDescriptor(
215
- Element.prototype,
216
- 'innerHTML',
217
- );
218
- delete Element.prototype.innerHTML;
219
- Object.defineProperty(
220
- HTMLDivElement.prototype,
221
- 'innerHTML',
222
- innerHTMLDescriptor,
223
- );
224
- });
225
-
226
- afterEach(() => {
227
- delete HTMLDivElement.prototype.innerHTML;
228
- Object.defineProperty(
229
- Element.prototype,
230
- 'innerHTML',
231
- innerHTMLDescriptor,
232
- );
233
- });
234
-
235
- // @gate !disableIEWorkarounds
236
- it('should log a warning', async () => {
237
- class Component extends React.Component {
238
- render() {
239
- return <svg dangerouslySetInnerHTML={{__html: 'unsafe html'}} />;
240
- }
241
- }
242
- const root = ReactDOMClient.createRoot(container);
243
- await expect(async () => {
244
- await act(() => {
245
- root.render(<Component />);
246
- });
247
- }).toErrorDev(
248
- "Using 'dangerouslySetInnerHTML' in an svg element with " +
249
- 'Trusted Types enabled in an Internet Explorer will cause ' +
250
- 'the trusted value to be converted to string. Assigning string ' +
251
- "to 'innerHTML' will throw an error if Trusted Types are enforced. " +
252
- "You can try to wrap your svg element inside a div and use 'dangerouslySetInnerHTML' " +
253
- 'on the enclosing div instead.',
254
- );
255
- expect(container.innerHTML).toBe('<svg>unsafe html</svg>');
256
- });
257
- });
258
-
209
it('should warn once when rendering script tag in jsx on client', async () => {
210
const root = ReactDOMClient.createRoot(container);
211
await expect(async () => {
packages/shared/ReactFeatureFlags.js
-4
@@ -203,10 +203,6 @@ export const disableLegacyContextForFunctionComponents = true;
203
// TODO: clean up legacy <StrictMode /> once tests pass WWW.
204
export const useModernStrictMode = true;
205
206
-// Not ready to break experimental yet.
207
-// Remove IE and MsApp specific workarounds for innerHTML
208
-export const disableIEWorkarounds = true;
209
-
206
// Filter certain DOM attributes (e.g. src, href) if their values are empty
207
// strings. This prevents e.g. <img src=""> from making an unnecessary HTTP
208
// request for certain browsers.
packages/shared/forks/ReactFeatureFlags.native-fb.js
-1
@@ -36,7 +36,6 @@ export const debugRenderPhaseSideEffectsForStrictMode = __DEV__;
36
export const disableClientCache = true;
37
export const disableCommentsAsDOMContainers = true;
38
export const disableDefaultPropsExceptForClasses = true;
39
-export const disableIEWorkarounds = true;
39
export const disableInputAttributeSyncing = false;
40
export const disableLegacyContext = false;
41
export const disableLegacyContextForFunctionComponents = false;
packages/shared/forks/ReactFeatureFlags.native-oss.js
-1
@@ -23,7 +23,6 @@ export const alwaysThrottleRetries = false;
23
export const disableClientCache = true;
24
export const disableCommentsAsDOMContainers = true;
25
export const disableDefaultPropsExceptForClasses = true;
26
-export const disableIEWorkarounds = true;
26
export const disableInputAttributeSyncing = false;
27
export const disableLegacyContext = true;
28
export const disableLegacyContextForFunctionComponents = true;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-1
@@ -29,7 +29,6 @@ export const enablePostpone = false;
29
export const enableHalt = false;
30
export const disableCommentsAsDOMContainers = true;
31
export const disableInputAttributeSyncing = false;
32
-export const disableIEWorkarounds = true;
32
export const enableScopeAPI = false;
33
export const enableCreateEventHandleAPI = false;
34
export const enableSuspenseCallback = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js
-1
@@ -15,7 +15,6 @@ export const debugRenderPhaseSideEffectsForStrictMode = false;
15
export const disableClientCache = true;
16
export const disableCommentsAsDOMContainers = true;
17
export const disableDefaultPropsExceptForClasses = true;
18
-export const disableIEWorkarounds = true;
18
export const disableInputAttributeSyncing = false;
19
export const disableLegacyContext = false;
20
export const disableLegacyContextForFunctionComponents = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-1
@@ -29,7 +29,6 @@ export const enablePostpone = false;
29
export const enableHalt = false;
30
export const disableCommentsAsDOMContainers = true;
31
export const disableInputAttributeSyncing = false;
32
-export const disableIEWorkarounds = true;
32
export const enableScopeAPI = true;
33
export const enableCreateEventHandleAPI = false;
34
export const enableSuspenseCallback = true;
packages/shared/forks/ReactFeatureFlags.www.js
-1
@@ -53,7 +53,6 @@ export const enableFabricCompleteRootInCommitPhase = false;
53
export const enableSuspenseAvoidThisFallback = true;
54
export const enableSuspenseAvoidThisFallbackFizz = false;
55
56
-export const disableIEWorkarounds = true;
56
export const enableCPUSuspense = true;
57
export const enableUseMemoCacheHook = true;
58
export const enableUseEffectEventHook = true;
scripts/jest/setupTests.www.js
-1
@@ -15,7 +15,6 @@ jest.mock('shared/ReactFeatureFlags', () => {
15
// These are hardcoded to true for the next release,
16
// but still run the tests against both variants until
17
// we remove the flag.
18
- actual.disableIEWorkarounds = __VARIANT__;
18
actual.disableClientCache = __VARIANT__;
19
20
return actual;