@samitouri / QOS-React-2 / commits / fb12845d77

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;