From e7fc04b2970197cb953833aa15597cbc9fe38f2e Mon Sep 17 00:00:00 2001 From: Josh Story Date: Thu, 15 Sep 2022 15:31:31 -0700 Subject: [PATCH] [react-dom] Reorganize react-dom internals to match react (#25277) * reorganize react-dom internals to match react * refactor and make forks work for flow and internal imports * flew too close to the sun * typo --- packages/react-dom/index.classic.fb.js | 7 ++-- packages/react-dom/index.experimental.js | 2 +- packages/react-dom/index.js | 2 +- packages/react-dom/index.modern.fb.js | 2 +- packages/react-dom/index.stable.js | 2 +- .../react-dom/src/ReactDOMSharedInternals.js | 35 +++++++++++++++++++ packages/react-dom/src/client/ReactDOM.js | 29 ++------------- packages/shared/ReactDOMSharedInternals.js | 15 ++++++++ scripts/jest/setupHostConfigs.js | 6 ++++ scripts/rollup/forks.js | 27 ++++++++++++++ scripts/shared/inlinedHostConfigs.js | 3 ++ 11 files changed, 97 insertions(+), 33 deletions(-) create mode 100644 packages/react-dom/src/ReactDOMSharedInternals.js create mode 100644 packages/shared/ReactDOMSharedInternals.js diff --git a/packages/react-dom/index.classic.fb.js b/packages/react-dom/index.classic.fb.js index 93cc883d0cded..fddf873d48b60 100644 --- a/packages/react-dom/index.classic.fb.js +++ b/packages/react-dom/index.classic.fb.js @@ -9,17 +9,16 @@ import {isEnabled} from './src/events/ReactDOMEventListener'; -import {__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './src/client/ReactDOM'; +import Internals from './src/ReactDOMSharedInternals'; // For classic WWW builds, include a few internals that are already in use. -Object.assign((__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: any), { +Object.assign((Internals: any), { ReactBrowserEventEmitter: { isEnabled, }, }); export { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, createPortal, createRoot, hydrateRoot, @@ -36,3 +35,5 @@ export { unstable_runWithPriority, // DO NOT USE: Temporarily exposed to migrate off of Scheduler.runWithPriority. version, } from './src/client/ReactDOM'; + +export {Internals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED}; diff --git a/packages/react-dom/index.experimental.js b/packages/react-dom/index.experimental.js index 44f7dcfe0b1e2..11cb1a262f4d5 100644 --- a/packages/react-dom/index.experimental.js +++ b/packages/react-dom/index.experimental.js @@ -7,8 +7,8 @@ * @flow */ +export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './src/ReactDOMSharedInternals'; export { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, createPortal, createRoot, hydrateRoot, diff --git a/packages/react-dom/index.js b/packages/react-dom/index.js index 18dfcf43ca9d0..905754e092976 100644 --- a/packages/react-dom/index.js +++ b/packages/react-dom/index.js @@ -9,8 +9,8 @@ // Export all exports so that they're available in tests. // We can't use export * from in Flow for some reason. +export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './src/ReactDOMSharedInternals'; export { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, createPortal, createRoot, hydrateRoot, diff --git a/packages/react-dom/index.modern.fb.js b/packages/react-dom/index.modern.fb.js index 866a5ebe31f62..3368a3f9c9eba 100644 --- a/packages/react-dom/index.modern.fb.js +++ b/packages/react-dom/index.modern.fb.js @@ -7,8 +7,8 @@ * @flow */ +export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './src/ReactDOMSharedInternals'; export { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, createPortal, createRoot, hydrateRoot, diff --git a/packages/react-dom/index.stable.js b/packages/react-dom/index.stable.js index 7d8b01be53e3d..c0a01d6662318 100644 --- a/packages/react-dom/index.stable.js +++ b/packages/react-dom/index.stable.js @@ -7,8 +7,8 @@ * @flow */ +export {default as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './src/ReactDOMSharedInternals'; export { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, createPortal, createRoot, hydrateRoot, diff --git a/packages/react-dom/src/ReactDOMSharedInternals.js b/packages/react-dom/src/ReactDOMSharedInternals.js new file mode 100644 index 0000000000000..6b4525cffca2a --- /dev/null +++ b/packages/react-dom/src/ReactDOMSharedInternals.js @@ -0,0 +1,35 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import {batchedUpdates} from 'react-reconciler/src/ReactFiberReconciler'; +import { + enqueueStateRestore, + restoreStateIfNeeded, +} from './events/ReactDOMControlledComponent'; +import { + getInstanceFromNode, + getNodeFromInstance, + getFiberCurrentPropsFromNode, +} from './client/ReactDOMComponentTree'; + +const Internals = { + usingClientEntryPoint: false, + // Keep in sync with ReactTestUtils.js. + // This is an array for better minification. + Events: [ + getInstanceFromNode, + getNodeFromInstance, + getFiberCurrentPropsFromNode, + enqueueStateRestore, + restoreStateIfNeeded, + batchedUpdates, + ], +}; + +export default Internals; diff --git a/packages/react-dom/src/client/ReactDOM.js b/packages/react-dom/src/client/ReactDOM.js index 406cda4f266a8..bfd300f7b4c39 100644 --- a/packages/react-dom/src/client/ReactDOM.js +++ b/packages/react-dom/src/client/ReactDOM.js @@ -50,12 +50,7 @@ import {canUseDOM} from 'shared/ExecutionEnvironment'; import ReactVersion from 'shared/ReactVersion'; import {enableNewReconciler} from 'shared/ReactFeatureFlags'; -import { - getInstanceFromNode, - getNodeFromInstance, - getFiberCurrentPropsFromNode, - getClosestInstanceFromNode, -} from './ReactDOMComponentTree'; +import {getClosestInstanceFromNode} from './ReactDOMComponentTree'; import {restoreControlledState} from './ReactDOMComponent'; import { setAttemptSynchronousHydration, @@ -66,11 +61,8 @@ import { setAttemptHydrationAtPriority, } from '../events/ReactDOMEventReplaying'; import {setBatchingImplementation} from '../events/ReactDOMUpdateBatching'; -import { - setRestoreImplementation, - enqueueStateRestore, - restoreStateIfNeeded, -} from '../events/ReactDOMControlledComponent'; +import {setRestoreImplementation} from '../events/ReactDOMControlledComponent'; +import Internals from '../ReactDOMSharedInternals'; setAttemptSynchronousHydration(attemptSynchronousHydration); setAttemptDiscreteHydration(attemptDiscreteHydration); @@ -133,20 +125,6 @@ function renderSubtreeIntoContainer( ); } -const Internals = { - usingClientEntryPoint: false, - // Keep in sync with ReactTestUtils.js. - // This is an array for better minification. - Events: [ - getInstanceFromNode, - getNodeFromInstance, - getFiberCurrentPropsFromNode, - enqueueStateRestore, - restoreStateIfNeeded, - batchedUpdates, - ], -}; - function createRoot( container: Element | Document | DocumentFragment, options?: CreateRootOptions, @@ -201,7 +179,6 @@ export { createPortal, batchedUpdates as unstable_batchedUpdates, flushSync, - Internals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, ReactVersion as version, // Disabled behind disableLegacyReactDOMAPIs findDOMNode, diff --git a/packages/shared/ReactDOMSharedInternals.js b/packages/shared/ReactDOMSharedInternals.js new file mode 100644 index 0000000000000..4ba19d407f7fc --- /dev/null +++ b/packages/shared/ReactDOMSharedInternals.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import * as ReactDOM from 'react-dom'; + +const ReactDOMSharedInternals = + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +export default ReactDOMSharedInternals; diff --git a/scripts/jest/setupHostConfigs.js b/scripts/jest/setupHostConfigs.js index 1dc72761e03ba..b82367f2f493d 100644 --- a/scripts/jest/setupHostConfigs.js +++ b/scripts/jest/setupHostConfigs.js @@ -148,4 +148,10 @@ jest.mock('shared/ReactSharedInternals', () => jest.requireActual('react/src/ReactSharedInternals') ); +// Make it possible to import this module inside +// the ReactDOM package itself. +jest.mock('shared/ReactDOMSharedInternals', () => + jest.requireActual('react-dom/src/ReactDOMSharedInternals') +); + jest.mock('scheduler', () => jest.requireActual('scheduler/unstable_mock')); diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js index d45c41a74268d..34345c80a1352 100644 --- a/scripts/rollup/forks.js +++ b/scripts/rollup/forks.js @@ -67,6 +67,33 @@ const forks = Object.freeze({ return null; }, + // Without this fork, importing `shared/ReactDOMSharedInternals` inside + // the `react-dom` package itself would not work due to a cyclical dependency. + './packages/shared/ReactDOMSharedInternals.js': ( + bundleType, + entry, + dependencies + ) => { + if (entry === 'react-dom') { + return './packages/react-dom/src/ReactDOMSharedInternals.js'; + } + if ( + !entry.startsWith('react-dom/') && + dependencies.indexOf('react-dom') === -1 + ) { + // React DOM internals are unavailable if we can't reference the package. + // We return an error because we only want to throw if this module gets used. + return new Error( + 'Cannot use a module that depends on ReactDOMSharedInternals ' + + 'from "' + + entry + + '" because it does not declare "react-dom" in the package ' + + 'dependencies or peerDependencies.' + ); + } + return null; + }, + // We have a few forks for different environments. './packages/shared/ReactFeatureFlags.js': (bundleType, entry) => { switch (entry) { diff --git a/scripts/shared/inlinedHostConfigs.js b/scripts/shared/inlinedHostConfigs.js index 458c5410eaf18..977a1cae2e6b2 100644 --- a/scripts/shared/inlinedHostConfigs.js +++ b/scripts/shared/inlinedHostConfigs.js @@ -36,6 +36,7 @@ module.exports = [ 'react-devtools-shell', 'react-devtools-shared', 'react-interactions', + 'shared/ReactDOMSharedInternals', ], isFlowTyped: true, isServerSupported: true, @@ -66,6 +67,7 @@ module.exports = [ 'react-devtools-core', 'react-devtools-shell', 'react-devtools-shared', + 'shared/ReactDOMSharedInternals', ], isFlowTyped: true, isServerSupported: true, @@ -85,6 +87,7 @@ module.exports = [ 'react-dom/src/server/ReactDOMLegacyServerNode.classic.fb.js', 'react-dom/src/server/ReactDOMLegacyServerNodeStream.js', // file indirection to support partial forking of some methods in *Node 'react-client/src/ReactFlightClientStream.js', // We can only type check this in streaming configurations. + 'shared/ReactDOMSharedInternals', ], isFlowTyped: true, isServerSupported: true,