Skip to content

Commit 54f785b

Browse files
authored
Disallow comments as DOM containers for createRoot (#23321)
This is an old feature that we no longer support. `hydrateRoot` already throws if you pass a comment node; this change makes `createRoot` throw, too. Still enabled in the Facebook build until we migrate the callers.
1 parent e9aa959 commit 54f785b

11 files changed

+42
-3
lines changed

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

+18
Original file line numberDiff line numberDiff line change
@@ -402,4 +402,22 @@ describe('ReactDOMRoot', () => {
402402
'already rendering.',
403403
);
404404
});
405+
406+
// @gate disableCommentsAsDOMContainers
407+
it('errors if container is a comment node', () => {
408+
// This is an old feature used by www. Disabled in the open source build.
409+
const div = document.createElement('div');
410+
div.innerHTML = '<!-- react-mount-point-unstable -->';
411+
const commentNode = div.childNodes[0];
412+
413+
expect(() => ReactDOM.createRoot(commentNode)).toThrow(
414+
'createRoot(...): Target container is not a DOM element.',
415+
);
416+
expect(() => ReactDOM.hydrateRoot(commentNode)).toThrow(
417+
'hydrateRoot(...): Target container is not a DOM element.',
418+
);
419+
420+
// Still works in the legacy API
421+
ReactDOM.render(<div />, commentNode);
422+
});
405423
});

packages/react-dom/src/client/ReactDOMRoot.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ import {
6868
isAlreadyRendering,
6969
} from 'react-reconciler/src/ReactFiberReconciler';
7070
import {ConcurrentRoot} from 'react-reconciler/src/ReactRootTags';
71-
import {allowConcurrentByDefault} from 'shared/ReactFeatureFlags';
71+
import {
72+
allowConcurrentByDefault,
73+
disableCommentsAsDOMContainers,
74+
} from 'shared/ReactFeatureFlags';
7275

7376
/* global reportError */
7477
const defaultOnRecoverableError =
@@ -153,7 +156,7 @@ export function createRoot(
153156
container: Container,
154157
options?: CreateRootOptions,
155158
): RootType {
156-
if (!isValidContainerLegacy(container)) {
159+
if (!isValidContainer(container)) {
157160
throw new Error('createRoot(...): Target container is not a DOM element.');
158161
}
159162

@@ -293,7 +296,10 @@ export function isValidContainer(node: any): boolean {
293296
node &&
294297
(node.nodeType === ELEMENT_NODE ||
295298
node.nodeType === DOCUMENT_NODE ||
296-
node.nodeType === DOCUMENT_FRAGMENT_NODE)
299+
node.nodeType === DOCUMENT_FRAGMENT_NODE ||
300+
(!disableCommentsAsDOMContainers &&
301+
node.nodeType === COMMENT_NODE &&
302+
(node: any).nodeValue === ' react-mount-point-unstable '))
297303
);
298304
}
299305

packages/shared/ReactFeatureFlags.js

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ export const enableSchedulerDebugging = false;
6868
// Disable javascript: URL strings in href for XSS protection.
6969
export const disableJavaScriptURLs = false;
7070

71+
// Disable support for comment nodes as React DOM containers. Only supported
72+
// by www builds.
73+
export const disableCommentsAsDOMContainers = true;
74+
7175
// Experimental Scope support.
7276
export const enableScopeAPI = false;
7377

packages/shared/forks/ReactFeatureFlags.native-fb.js

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const enableCache = false;
3333
export const enableSchedulerDebugging = false;
3434
export const debugRenderPhaseSideEffectsForStrictMode = true;
3535
export const disableJavaScriptURLs = false;
36+
export const disableCommentsAsDOMContainers = true;
3637
export const disableInputAttributeSyncing = false;
3738
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
3839
export const warnAboutDeprecatedLifecycles = true;

packages/shared/forks/ReactFeatureFlags.native-oss.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const enableSelectiveHydration = false;
2525
export const enableLazyElements = false;
2626
export const enableCache = false;
2727
export const disableJavaScriptURLs = false;
28+
export const disableCommentsAsDOMContainers = true;
2829
export const disableInputAttributeSyncing = false;
2930
export const enableSchedulerDebugging = false;
3031
export const enableScopeAPI = false;

packages/shared/forks/ReactFeatureFlags.test-renderer.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const enableSelectiveHydration = false;
2525
export const enableLazyElements = false;
2626
export const enableCache = __EXPERIMENTAL__;
2727
export const disableJavaScriptURLs = false;
28+
export const disableCommentsAsDOMContainers = true;
2829
export const disableInputAttributeSyncing = false;
2930
export const enableSchedulerDebugging = false;
3031
export const enableScopeAPI = false;

packages/shared/forks/ReactFeatureFlags.test-renderer.native.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const enableSelectiveHydration = false;
2525
export const enableLazyElements = false;
2626
export const enableCache = false;
2727
export const disableJavaScriptURLs = false;
28+
export const disableCommentsAsDOMContainers = true;
2829
export const disableInputAttributeSyncing = false;
2930
export const enableSchedulerDebugging = false;
3031
export const enableScopeAPI = false;

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export const enableLazyElements = false;
2626
export const enableCache = true;
2727
export const enableSchedulerDebugging = false;
2828
export const disableJavaScriptURLs = false;
29+
export const disableCommentsAsDOMContainers = true;
2930
export const disableInputAttributeSyncing = false;
3031
export const enableScopeAPI = true;
3132
export const enableCreateEventHandleAPI = false;

packages/shared/forks/ReactFeatureFlags.testing.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const enableSelectiveHydration = false;
2525
export const enableLazyElements = false;
2626
export const enableCache = __EXPERIMENTAL__;
2727
export const disableJavaScriptURLs = false;
28+
export const disableCommentsAsDOMContainers = true;
2829
export const disableInputAttributeSyncing = false;
2930
export const enableSchedulerDebugging = false;
3031
export const enableScopeAPI = false;

packages/shared/forks/ReactFeatureFlags.testing.www.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const enableSelectiveHydration = true;
2525
export const enableLazyElements = false;
2626
export const enableCache = true;
2727
export const disableJavaScriptURLs = true;
28+
export const disableCommentsAsDOMContainers = true;
2829
export const disableInputAttributeSyncing = false;
2930
export const enableSchedulerDebugging = false;
3031
export const enableScopeAPI = true;

packages/shared/forks/ReactFeatureFlags.www.js

+4
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ export const enableCache = true;
7474

7575
export const disableJavaScriptURLs = true;
7676

77+
// TODO: www currently relies on this feature. It's disabled in open source.
78+
// Need to remove it.
79+
export const disableCommentsAsDOMContainers = false;
80+
7781
export const disableModulePatternComponents = true;
7882

7983
export const enableCreateEventHandleAPI = true;

0 commit comments

Comments
 (0)