Skip to content

Commit af1c41d

Browse files
committed
Move client only exports to react-dom/client
This change updates the entrypoints for `react-dom` to only include exports which make sense in every runtime (Flight, Fizz, and Fiber). The main benefit to doing this is we stop including the entire client build when importing anything from `react-dom`. The server-rendering-stub was added as a manual way of doing this prior to the next major and now that stub simply reexports from `react-dom`. In a future major we will remove the stub altogether. This change affects the OSS channels but does not update how the meta entrypoints are organized
1 parent 08b7963 commit af1c41d

File tree

64 files changed

+460
-2293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+460
-2293
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
import {disableCommentsAsDOMContainers} from 'shared/ReactFeatureFlags';
11+
12+
import {
13+
ELEMENT_NODE,
14+
COMMENT_NODE,
15+
DOCUMENT_NODE,
16+
DOCUMENT_FRAGMENT_NODE,
17+
} from './HTMLNodeType';
18+
19+
export function isValidContainer(node: any): boolean {
20+
return !!(
21+
node &&
22+
(node.nodeType === ELEMENT_NODE ||
23+
node.nodeType === DOCUMENT_NODE ||
24+
node.nodeType === DOCUMENT_FRAGMENT_NODE ||
25+
(!disableCommentsAsDOMContainers &&
26+
node.nodeType === COMMENT_NODE &&
27+
(node: any).nodeValue === ' react-mount-point-unstable '))
28+
);
29+
}
30+
31+
// TODO: Remove this function which also includes comment nodes.
32+
// We only use it in places that are currently more relaxed.
33+
export function isValidContainerLegacy(node: any): boolean {
34+
return !!(
35+
node &&
36+
(node.nodeType === ELEMENT_NODE ||
37+
node.nodeType === DOCUMENT_NODE ||
38+
node.nodeType === DOCUMENT_FRAGMENT_NODE ||
39+
(node.nodeType === COMMENT_NODE &&
40+
(node: any).nodeValue === ' react-mount-point-unstable '))
41+
);
42+
}

packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
* @flow
88
*/
99

10-
import type {HostDispatcher} from 'react-dom/src/shared/ReactDOMTypes';
1110
import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities';
1211
import type {DOMEventName} from '../events/DOMEventNames';
1312
import type {Fiber, FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
@@ -20,6 +19,7 @@ import type {ReactScopeInstance} from 'shared/ReactTypes';
2019
import type {AncestorInfoDev} from './validateDOMNesting';
2120
import type {FormStatus} from 'react-dom-bindings/src/shared/ReactDOMFormActions';
2221
import type {
22+
HostDispatcher,
2323
CrossOriginEnum,
2424
PreloadImplOptions,
2525
PreloadModuleImplOptions,
@@ -28,6 +28,10 @@ import type {
2828
PreinitModuleScriptOptions,
2929
} from 'react-dom/src/shared/ReactDOMTypes';
3030

31+
import {
32+
isAlreadyRendering,
33+
flushSync as flushSyncWithoutWarningIfAlreadyRendering,
34+
} from 'react-reconciler/src/ReactFiberReconciler';
3135
import {NotPending} from 'react-dom-bindings/src/shared/ReactDOMFormActions';
3236
import {getCurrentRootHostContainer} from 'react-reconciler/src/ReactFiberHostContext';
3337
import {DefaultEventPriority} from 'react-reconciler/src/ReactEventPriorities';
@@ -106,6 +110,9 @@ import {listenToAllSupportedEvents} from '../events/DOMPluginEventSystem';
106110
import {validateLinkPropsForStyleResource} from '../shared/ReactDOMResourceValidation';
107111
import escapeSelectorAttributeValueInsideDoubleQuotes from './escapeSelectorAttributeValueInsideDoubleQuotes';
108112

113+
import ReactDOMSharedInternals from 'shared/ReactDOMSharedInternals';
114+
const ReactDOMCurrentDispatcher = ReactDOMSharedInternals.Dispatcher;
115+
109116
export type Type = string;
110117
export type Props = {
111118
autoFocus?: boolean,
@@ -2083,19 +2090,44 @@ function getDocumentFromRoot(root: HoistableRoot): Document {
20832090
return root.ownerDocument || root;
20842091
}
20852092

2086-
// We want this to be the default dispatcher on ReactDOMSharedInternals but we don't want to mutate
2087-
// internals in Module scope. Instead we export it and Internals will import it. There is already a cycle
2088-
// from Internals -> ReactDOM -> HostConfig -> Internals so this doesn't introduce a new one.
2089-
export const ReactDOMClientDispatcher: HostDispatcher = {
2093+
const ReactDOMClientDispatcher: HostDispatcher = {
20902094
prefetchDNS,
20912095
preconnect,
20922096
preload,
20932097
preloadModule,
20942098
preinitStyle,
20952099
preinitScript,
20962100
preinitModuleScript,
2101+
flushSync,
2102+
nextDispatcher: null,
20972103
};
20982104

2105+
// We register the HostDispatcher on ReactDOMSharedInternals
2106+
if (ReactDOMCurrentDispatcher.current === null) {
2107+
ReactDOMCurrentDispatcher.current = ReactDOMClientDispatcher;
2108+
} else {
2109+
ReactDOMCurrentDispatcher.current.nextDispatcher = ReactDOMClientDispatcher;
2110+
}
2111+
2112+
function flushSync<R>(fn: void | (() => R)): void | R {
2113+
if (__DEV__) {
2114+
if (isAlreadyRendering()) {
2115+
console.error(
2116+
'flushSync was called from inside a lifecycle method. React cannot ' +
2117+
'flush when React is already rendering. Consider moving this call to ' +
2118+
'a scheduler task or micro task.',
2119+
);
2120+
}
2121+
}
2122+
if (ReactDOMClientDispatcher.nextDispatcher) {
2123+
return ReactDOMClientDispatcher.nextDispatcher.flushSync(() =>
2124+
flushSyncWithoutWarningIfAlreadyRendering(fn),
2125+
);
2126+
} else {
2127+
return flushSyncWithoutWarningIfAlreadyRendering(fn);
2128+
}
2129+
}
2130+
20992131
// We expect this to get inlined. It is a function mostly to communicate the special nature of
21002132
// how we resolve the HoistableRoot for ReactDOM.pre*() methods. Because we support calling
21012133
// these methods outside of render there is no way to know which Document or ShadowRoot is 'scoped'

packages/react-dom-bindings/src/server/ReactDOMFlightServerHostDispatcher.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,22 @@ export const ReactDOMFlightServerDispatcher: HostDispatcher = {
3333
preinitStyle,
3434
preinitScript,
3535
preinitModuleScript,
36+
flushSync,
37+
nextDispatcher: null,
3638
};
3739

40+
function flushSync<R>(fn: void | (() => R)): void | R {
41+
if (ReactDOMFlightServerDispatcher.nextDispatcher) {
42+
return ReactDOMFlightServerDispatcher.nextDispatcher.flushSync(fn);
43+
} else if (fn) {
44+
return fn();
45+
}
46+
}
47+
3848
function prefetchDNS(href: string) {
49+
if (ReactDOMFlightServerDispatcher.nextDispatcher) {
50+
ReactDOMFlightServerDispatcher.nextDispatcher.prefetchDNS(href);
51+
}
3952
if (enableFloat) {
4053
if (typeof href === 'string' && href) {
4154
const request = resolveRequest();
@@ -54,6 +67,9 @@ function prefetchDNS(href: string) {
5467
}
5568

5669
function preconnect(href: string, crossOrigin?: ?CrossOriginEnum) {
70+
if (ReactDOMFlightServerDispatcher.nextDispatcher) {
71+
ReactDOMFlightServerDispatcher.nextDispatcher.preconnect(href, crossOrigin);
72+
}
5773
if (enableFloat) {
5874
if (typeof href === 'string') {
5975
const request = resolveRequest();
@@ -77,6 +93,9 @@ function preconnect(href: string, crossOrigin?: ?CrossOriginEnum) {
7793
}
7894

7995
function preload(href: string, as: string, options?: ?PreloadImplOptions) {
96+
if (ReactDOMFlightServerDispatcher.nextDispatcher) {
97+
ReactDOMFlightServerDispatcher.nextDispatcher.preload(href, as, options);
98+
}
8099
if (enableFloat) {
81100
if (typeof href === 'string') {
82101
const request = resolveRequest();
@@ -110,6 +129,9 @@ function preload(href: string, as: string, options?: ?PreloadImplOptions) {
110129
}
111130

112131
function preloadModule(href: string, options?: ?PreloadModuleImplOptions) {
132+
if (ReactDOMFlightServerDispatcher.nextDispatcher) {
133+
ReactDOMFlightServerDispatcher.nextDispatcher.preloadModule(href, options);
134+
}
113135
if (enableFloat) {
114136
if (typeof href === 'string') {
115137
const request = resolveRequest();
@@ -138,6 +160,13 @@ function preinitStyle(
138160
precedence: ?string,
139161
options?: ?PreinitStyleOptions,
140162
) {
163+
if (ReactDOMFlightServerDispatcher.nextDispatcher) {
164+
ReactDOMFlightServerDispatcher.nextDispatcher.preinitStyle(
165+
href,
166+
precedence,
167+
options,
168+
);
169+
}
141170
if (enableFloat) {
142171
if (typeof href === 'string') {
143172
const request = resolveRequest();
@@ -168,6 +197,9 @@ function preinitStyle(
168197
}
169198

170199
function preinitScript(href: string, options?: ?PreinitScriptOptions) {
200+
if (ReactDOMFlightServerDispatcher.nextDispatcher) {
201+
ReactDOMFlightServerDispatcher.nextDispatcher.preinitScript(href, options);
202+
}
171203
if (enableFloat) {
172204
if (typeof href === 'string') {
173205
const request = resolveRequest();
@@ -195,6 +227,12 @@ function preinitModuleScript(
195227
href: string,
196228
options?: ?PreinitModuleScriptOptions,
197229
) {
230+
if (ReactDOMFlightServerDispatcher.nextDispatcher) {
231+
ReactDOMFlightServerDispatcher.nextDispatcher.preinitModuleScript(
232+
href,
233+
options,
234+
);
235+
}
198236
if (enableFloat) {
199237
if (typeof href === 'string') {
200238
const request = resolveRequest();

packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import type {ReactNodeList, ReactCustomFormAction} from 'shared/ReactTypes';
1111
import type {
12+
HostDispatcher,
1213
CrossOriginEnum,
1314
PreloadImplOptions,
1415
PreloadModuleImplOptions,
@@ -89,20 +90,33 @@ import {NotPending} from '../shared/ReactDOMFormActions';
8990
import ReactDOMSharedInternals from 'shared/ReactDOMSharedInternals';
9091
const ReactDOMCurrentDispatcher = ReactDOMSharedInternals.Dispatcher;
9192

92-
const ReactDOMServerDispatcher = {
93+
const ReactDOMServerDispatcher: HostDispatcher = {
9394
prefetchDNS,
9495
preconnect,
9596
preload,
9697
preloadModule,
9798
preinitStyle,
9899
preinitScript,
99100
preinitModuleScript,
101+
flushSync,
102+
nextDispatcher: null,
100103
};
101104

102-
export function prepareHostDispatcher() {
105+
// We register the HostDispatcher on ReactDOMSharedInternals
106+
if (ReactDOMCurrentDispatcher.current) {
107+
ReactDOMCurrentDispatcher.current.nextDispatcher = ReactDOMServerDispatcher;
108+
} else {
103109
ReactDOMCurrentDispatcher.current = ReactDOMServerDispatcher;
104110
}
105111

112+
function flushSync<R>(fn: void | (() => R)): void | R {
113+
if (ReactDOMServerDispatcher.nextDispatcher) {
114+
return ReactDOMServerDispatcher.nextDispatcher.flushSync(fn);
115+
} else if (fn) {
116+
return fn();
117+
}
118+
}
119+
106120
// We make every property of the descriptor optional because it is not a contract that
107121
// the headers provided by onHeaders has any particular header types.
108122
export type HeadersDescriptor = {

packages/react-dom-bindings/src/server/ReactFizzConfigDOMLegacy.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ export {
163163
writeHoistables,
164164
writePostamble,
165165
hoistHoistables,
166-
prepareHostDispatcher,
167166
resetResumableState,
168167
completeResumableState,
169168
emitEarlyPreloads,

packages/react-dom-bindings/src/server/ReactFlightServerConfigDOM.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ import type {
1616
PreinitModuleScriptOptions,
1717
} from 'react-dom/src/shared/ReactDOMTypes';
1818

19+
import {ReactDOMFlightServerDispatcher} from './ReactDOMFlightServerHostDispatcher';
1920
import ReactDOMSharedInternals from 'shared/ReactDOMSharedInternals';
2021
const ReactDOMCurrentDispatcher = ReactDOMSharedInternals.Dispatcher;
21-
22-
import {ReactDOMFlightServerDispatcher} from './ReactDOMFlightServerHostDispatcher';
23-
24-
export function prepareHostDispatcher(): void {
22+
if (ReactDOMCurrentDispatcher.current) {
23+
ReactDOMCurrentDispatcher.current.nextDispatcher =
24+
ReactDOMFlightServerDispatcher;
25+
} else {
2526
ReactDOMCurrentDispatcher.current = ReactDOMFlightServerDispatcher;
2627
}
2728

packages/react-dom/client.js

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,4 @@
77
* @flow
88
*/
99

10-
'use strict';
11-
12-
import type {ReactNodeList} from 'shared/ReactTypes';
13-
import type {
14-
RootType,
15-
HydrateRootOptions,
16-
CreateRootOptions,
17-
} from './src/client/ReactDOMRoot';
18-
19-
import {
20-
createRoot as createRootImpl,
21-
hydrateRoot as hydrateRootImpl,
22-
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as Internals,
23-
} from './';
24-
25-
export function createRoot(
26-
container: Element | Document | DocumentFragment,
27-
options?: CreateRootOptions,
28-
): RootType {
29-
if (__DEV__) {
30-
Internals.usingClientEntryPoint = true;
31-
}
32-
try {
33-
return createRootImpl(container, options);
34-
} finally {
35-
if (__DEV__) {
36-
Internals.usingClientEntryPoint = false;
37-
}
38-
}
39-
}
40-
41-
export function hydrateRoot(
42-
container: Document | Element,
43-
children: ReactNodeList,
44-
options?: HydrateRootOptions,
45-
): RootType {
46-
if (__DEV__) {
47-
Internals.usingClientEntryPoint = true;
48-
}
49-
try {
50-
return hydrateRootImpl(container, children, options);
51-
} finally {
52-
if (__DEV__) {
53-
Internals.usingClientEntryPoint = false;
54-
}
55-
}
56-
}
10+
export {createRoot, hydrateRoot} from './src/client/ReactDOMClientBrowser';

0 commit comments

Comments
 (0)