Export React as Named Exports instead of CommonJS (#18106)

* Add options for forked entry points

We currently fork .fb.js entry points. This adds a few more options.

.modern.fb.js - experimental FB builds
.classic.fb.js - stable FB builds
.fb.js - if no other FB build, use this for FB builds
.experimental.js - experimental builds
.stable.js - stable builds
.js - used if no other override exists

This will be used to have different ES exports for different builds.

* Switch React to named exports

* Export named exports from the export point itself

We need to re-export the Flow exported types so we can use them in our code.

We don't want to use the Flow types from upstream since it doesn't have the non-public APIs that we have.

This should be able to use export * but I don't know why it doesn't work.

This actually enables Flow typing of React which was just "any" before.
This exposed some Flow errors that needs fixing.

* Create forks for the react entrypoint

None of our builds expose all exports and they all differ in at least one
way, so we need four forks.

* Set esModule flag to false

We don't want to emit the esModule compatibility flag on our CommonJS
output. For now we treat our named exports as if they're CommonJS.

This is a potentially breaking change for scheduler (but all those apis
are unstable), react-is and use-subscription. However, it seems unlikely
that anyone would rely on this since these only have named exports.

* Remove unused Feature Flags

* Let jest observe the stable fork for stable tests

This lets it do the negative test by ensuring that the right tests fail.

However, this in turn will make other tests that are not behind
__EXPERIMENTAL__ fail. So I need to do that next.

* Put all tests that depend on exports behind __EXPERIMENTAL__

Since there's no way to override the exports using feature flags
in .intern.js anymore we can't use these APIs in stable.

The tradeoff here is that we can either enable the negative tests on
"stable" that means experimental are expected to fail, or we can disable
tests on stable. This is unfortunate since some of these APIs now run on
a "stable" config at FB instead of the experimental.

* Switch ReactDOM to named exports

Same strategy as React.

I moved the ReactDOMFB runtime injection to classic.fb.js

Since we only fork the entrypoint, the `/testing` entrypoint needs to
be forked too to re-export the same things plus `act`. This is a bit
unfortunate. If it becomes a pattern we can consider forking in the
module resolution deeply.

fix flow

* Fix ReactDOM Flow Types

Now that ReactDOM is Flow type checked we need to fix up its types.

* Configure jest to use stable entry for ReactDOM in non-experimental

* Remove additional FeatureFlags that are no longer needed

These are only flagging the exports and no implementation details so we
can control them fully through the export overrides.
This commit is contained in:
Sebastian Markbåge
2020-02-25 13:54:27 -08:00
committed by GitHub
parent 8d7535e540
commit 60016c448b
62 changed files with 1106 additions and 703 deletions
@@ -22,6 +22,11 @@ describe('ReactHooksInspection', () => {
ReactDebugTools = require('react-debug-tools');
});
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
it('should inspect a simple useResponder hook', () => {
const TestResponder = React.DEPRECATED_createResponder('TestResponder', {});
@@ -19,18 +19,22 @@ export default function useContextMenu({
}: {|
data: Object,
id: string,
ref: ElementRef<HTMLElement>,
ref: {current: ElementRef<'div'> | null},
|}) {
const {showMenu} = useContext(RegistryContext);
useEffect(() => {
if (ref.current !== null) {
const handleContextMenu = event => {
const handleContextMenu = (event: MouseEvent | TouchEvent) => {
event.preventDefault();
event.stopPropagation();
const pageX = event.pageX || (event.touches && event.touches[0].pageX);
const pageY = event.pageY || (event.touches && event.touches[0].pageY);
const pageX =
event.pageX ||
(event.touches && ((event: any): TouchEvent).touches[0].pageX);
const pageY =
event.pageY ||
(event.touches && ((event: any): TouchEvent).touches[0].pageY);
showMenu({data, id, pageX, pageY});
};
+46
View File
@@ -0,0 +1,46 @@
/**
* 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 {addUserTimingListener} from 'shared/ReactFeatureFlags';
import {isEnabled} from './src/events/ReactDOMEventListener';
import {getClosestInstanceFromNode} from './src/client/ReactDOMComponentTree';
import {__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED} from './src/client/ReactDOM';
// 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), {
ReactBrowserEventEmitter: {
isEnabled,
},
ReactDOMComponentTree: {
getClosestInstanceFromNode,
},
// Perf experiment
addUserTimingListener,
});
export {
createPortal,
unstable_batchedUpdates,
flushSync,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
version,
findDOMNode,
hydrate,
render,
unmountComponentAtNode,
createRoot,
createBlockingRoot,
unstable_discreteUpdates,
unstable_flushDiscreteUpdates,
unstable_flushControlled,
unstable_scheduleHydration,
unstable_renderSubtreeIntoContainer,
unstable_createPortal,
} from './src/client/ReactDOM';
+34
View File
@@ -0,0 +1,34 @@
/**
* 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
*/
export {
createPortal,
unstable_batchedUpdates,
flushSync,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
version,
// Disabled behind disableLegacyReactDOMAPIs
findDOMNode,
hydrate,
render,
unmountComponentAtNode,
// exposeConcurrentModeAPIs
createRoot,
createBlockingRoot,
unstable_discreteUpdates,
unstable_flushDiscreteUpdates,
unstable_flushControlled,
unstable_scheduleHydration,
// Disabled behind disableUnstableRenderSubtreeIntoContainer
unstable_renderSubtreeIntoContainer,
// Disabled behind disableUnstableCreatePortal
// Temporary alias since we already shipped React 16 RC with it.
// TODO: remove in React 17.
unstable_createPortal,
} from './src/client/ReactDOM';
-14
View File
@@ -1,14 +0,0 @@
/**
* 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.
*/
'use strict';
const ReactDOMFB = require('./src/client/ReactDOMFB');
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = ReactDOMFB.default || ReactDOMFB;
+1 -7
View File
@@ -7,10 +7,4 @@
* @flow
*/
'use strict';
const ReactDOM = require('./src/client/ReactDOM');
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = ReactDOM.default || ReactDOM;
export * from './src/client/ReactDOM';
+22
View File
@@ -0,0 +1,22 @@
/**
* 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
*/
export {
createPortal,
unstable_batchedUpdates,
flushSync,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
version,
createRoot,
createBlockingRoot,
unstable_discreteUpdates,
unstable_flushDiscreteUpdates,
unstable_flushControlled,
unstable_scheduleHydration,
} from './src/client/ReactDOM';
+24
View File
@@ -0,0 +1,24 @@
/**
* 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
*/
export {
createPortal,
unstable_batchedUpdates,
flushSync,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
version,
findDOMNode,
hydrate,
render,
unmountComponentAtNode,
unstable_renderSubtreeIntoContainer,
// Temporary alias since we already shipped React 16 RC with it.
// TODO: remove in React 17.
unstable_createPortal,
} from './src/client/ReactDOM';
+1 -3
View File
@@ -13,8 +13,6 @@ const React = require('react');
const ReactDOM = require('react-dom');
const PropTypes = require('prop-types');
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
describe('ReactDOMFiber', () => {
let container;
@@ -249,7 +247,7 @@ describe('ReactDOMFiber', () => {
});
// TODO: remove in React 17
if (!ReactFeatureFlags.disableUnstableCreatePortal) {
if (!__EXPERIMENTAL__) {
it('should support unstable_createPortal alias', () => {
const portalContainer = document.createElement('div');
@@ -86,8 +86,6 @@ describe('ReactDOMServerPartialHydration', () => {
Scheduler = require('scheduler');
Suspense = React.Suspense;
SuspenseList = React.SuspenseList;
useHover = require('react-interactions/events/hover').useHover;
});
if (!__EXPERIMENTAL__) {
@@ -2368,120 +2366,124 @@ describe('ReactDOMServerPartialHydration', () => {
document.body.removeChild(container);
});
it('blocks only on the last continuous event (Responder system)', async () => {
let suspend1 = false;
let resolve1;
let promise1 = new Promise(resolvePromise => (resolve1 = resolvePromise));
let suspend2 = false;
let resolve2;
let promise2 = new Promise(resolvePromise => (resolve2 = resolvePromise));
if (__EXPERIMENTAL__) {
it('blocks only on the last continuous event (Responder system)', async () => {
useHover = require('react-interactions/events/hover').useHover;
function First({text}) {
if (suspend1) {
throw promise1;
} else {
return 'Hello';
let suspend1 = false;
let resolve1;
let promise1 = new Promise(resolvePromise => (resolve1 = resolvePromise));
let suspend2 = false;
let resolve2;
let promise2 = new Promise(resolvePromise => (resolve2 = resolvePromise));
function First({text}) {
if (suspend1) {
throw promise1;
} else {
return 'Hello';
}
}
}
function Second({text}) {
if (suspend2) {
throw promise2;
} else {
return 'World';
function Second({text}) {
if (suspend2) {
throw promise2;
} else {
return 'World';
}
}
}
let ops = [];
let ops = [];
function App() {
const listener1 = useHover({
onHoverStart() {
ops.push('Hover Start First');
},
onHoverEnd() {
ops.push('Hover End First');
},
});
const listener2 = useHover({
onHoverStart() {
ops.push('Hover Start Second');
},
onHoverEnd() {
ops.push('Hover End Second');
},
});
return (
<div>
<Suspense fallback="Loading First...">
<span DEPRECATED_flareListeners={listener1} />
{/* We suspend after to test what happens when we eager
function App() {
const listener1 = useHover({
onHoverStart() {
ops.push('Hover Start First');
},
onHoverEnd() {
ops.push('Hover End First');
},
});
const listener2 = useHover({
onHoverStart() {
ops.push('Hover Start Second');
},
onHoverEnd() {
ops.push('Hover End Second');
},
});
return (
<div>
<Suspense fallback="Loading First...">
<span DEPRECATED_flareListeners={listener1} />
{/* We suspend after to test what happens when we eager
attach the listener. */}
<First />
</Suspense>
<Suspense fallback="Loading Second...">
<span DEPRECATED_flareListeners={listener2}>
<Second />
</span>
</Suspense>
</div>
);
}
<First />
</Suspense>
<Suspense fallback="Loading Second...">
<span DEPRECATED_flareListeners={listener2}>
<Second />
</span>
</Suspense>
</div>
);
}
let finalHTML = ReactDOMServer.renderToString(<App />);
let container = document.createElement('div');
container.innerHTML = finalHTML;
let finalHTML = ReactDOMServer.renderToString(<App />);
let container = document.createElement('div');
container.innerHTML = finalHTML;
// We need this to be in the document since we'll dispatch events on it.
document.body.appendChild(container);
// We need this to be in the document since we'll dispatch events on it.
document.body.appendChild(container);
let appDiv = container.getElementsByTagName('div')[0];
let firstSpan = appDiv.getElementsByTagName('span')[0];
let secondSpan = appDiv.getElementsByTagName('span')[1];
expect(firstSpan.textContent).toBe('');
expect(secondSpan.textContent).toBe('World');
let appDiv = container.getElementsByTagName('div')[0];
let firstSpan = appDiv.getElementsByTagName('span')[0];
let secondSpan = appDiv.getElementsByTagName('span')[1];
expect(firstSpan.textContent).toBe('');
expect(secondSpan.textContent).toBe('World');
// On the client we don't have all data yet but we want to start
// hydrating anyway.
suspend1 = true;
suspend2 = true;
let root = ReactDOM.createRoot(container, {hydrate: true});
root.render(<App />);
// On the client we don't have all data yet but we want to start
// hydrating anyway.
suspend1 = true;
suspend2 = true;
let root = ReactDOM.createRoot(container, {hydrate: true});
root.render(<App />);
Scheduler.unstable_flushAll();
jest.runAllTimers();
Scheduler.unstable_flushAll();
jest.runAllTimers();
dispatchMouseEvent(appDiv, null);
dispatchMouseEvent(firstSpan, appDiv);
dispatchMouseEvent(secondSpan, firstSpan);
dispatchMouseEvent(appDiv, null);
dispatchMouseEvent(firstSpan, appDiv);
dispatchMouseEvent(secondSpan, firstSpan);
// Neither target is yet hydrated.
expect(ops).toEqual([]);
// Neither target is yet hydrated.
expect(ops).toEqual([]);
// Resolving the second promise so that rendering can complete.
suspend2 = false;
resolve2();
await promise2;
// Resolving the second promise so that rendering can complete.
suspend2 = false;
resolve2();
await promise2;
Scheduler.unstable_flushAll();
jest.runAllTimers();
Scheduler.unstable_flushAll();
jest.runAllTimers();
// We've unblocked the current hover target so we should be
// able to replay it now.
expect(ops).toEqual(['Hover Start Second']);
// We've unblocked the current hover target so we should be
// able to replay it now.
expect(ops).toEqual(['Hover Start Second']);
// Resolving the first promise has no effect now.
suspend1 = false;
resolve1();
await promise1;
// Resolving the first promise has no effect now.
suspend1 = false;
resolve1();
await promise1;
Scheduler.unstable_flushAll();
jest.runAllTimers();
Scheduler.unstable_flushAll();
jest.runAllTimers();
expect(ops).toEqual(['Hover Start Second']);
expect(ops).toEqual(['Hover Start Second']);
document.body.removeChild(container);
});
document.body.removeChild(container);
});
}
it('finishes normal pri work before continuing to hydrate a retry', async () => {
let suspend = false;
@@ -17,7 +17,6 @@ let ReactDOMServer;
let ReactTestUtils;
let Scheduler;
let Suspense;
let usePress;
function dispatchMouseHoverEvent(to, from) {
if (!to) {
@@ -106,7 +105,6 @@ describe('ReactDOMServerSelectiveHydration', () => {
ReactTestUtils = require('react-dom/test-utils');
Scheduler = require('scheduler');
Suspense = React.Suspense;
usePress = require('react-interactions/events/press').usePress;
});
if (!__EXPERIMENTAL__) {
@@ -352,240 +350,246 @@ describe('ReactDOMServerSelectiveHydration', () => {
document.body.removeChild(container);
});
it('hydrates the target boundary synchronously during a click (flare)', async () => {
function Child({text}) {
Scheduler.unstable_yieldValue(text);
const listener = usePress({
onPress() {
Scheduler.unstable_yieldValue('Clicked ' + text);
},
});
if (__EXPERIMENTAL__) {
it('hydrates the target boundary synchronously during a click (flare)', async () => {
let usePress = require('react-interactions/events/press').usePress;
return <span DEPRECATED_flareListeners={listener}>{text}</span>;
}
function Child({text}) {
Scheduler.unstable_yieldValue(text);
const listener = usePress({
onPress() {
Scheduler.unstable_yieldValue('Clicked ' + text);
},
});
function App() {
Scheduler.unstable_yieldValue('App');
return (
<div>
<Suspense fallback="Loading...">
<Child text="A" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="B" />
</Suspense>
</div>
);
}
let finalHTML = ReactDOMServer.renderToString(<App />);
expect(Scheduler).toHaveYielded(['App', 'A', 'B']);
let container = document.createElement('div');
// We need this to be in the document since we'll dispatch events on it.
document.body.appendChild(container);
container.innerHTML = finalHTML;
let root = ReactDOM.createRoot(container, {hydrate: true});
root.render(<App />);
// Nothing has been hydrated so far.
expect(Scheduler).toHaveYielded([]);
let span = container.getElementsByTagName('span')[1];
let target = createEventTarget(span);
// This should synchronously hydrate the root App and the second suspense
// boundary.
let preventDefault = jest.fn();
target.virtualclick({preventDefault});
// The event should have been canceled because we called preventDefault.
expect(preventDefault).toHaveBeenCalled();
// We rendered App, B and then invoked the event without rendering A.
expect(Scheduler).toHaveYielded(['App', 'B', 'Clicked B']);
// After continuing the scheduler, we finally hydrate A.
expect(Scheduler).toFlushAndYield(['A']);
document.body.removeChild(container);
});
it('hydrates at higher pri if sync did not work first time (flare)', async () => {
let suspend = false;
let resolve;
let promise = new Promise(resolvePromise => (resolve = resolvePromise));
function Child({text}) {
if ((text === 'A' || text === 'D') && suspend) {
throw promise;
return <span DEPRECATED_flareListeners={listener}>{text}</span>;
}
Scheduler.unstable_yieldValue(text);
const listener = usePress({
onPress() {
Scheduler.unstable_yieldValue('Clicked ' + text);
},
});
return <span DEPRECATED_flareListeners={listener}>{text}</span>;
}
function App() {
Scheduler.unstable_yieldValue('App');
return (
<div>
<Suspense fallback="Loading...">
<Child text="A" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="B" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="C" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="D" />
</Suspense>
</div>
);
}
let finalHTML = ReactDOMServer.renderToString(<App />);
expect(Scheduler).toHaveYielded(['App', 'A', 'B', 'C', 'D']);
let container = document.createElement('div');
// We need this to be in the document since we'll dispatch events on it.
document.body.appendChild(container);
container.innerHTML = finalHTML;
let spanD = container.getElementsByTagName('span')[3];
suspend = true;
// A and D will be suspended. We'll click on D which should take
// priority, after we unsuspend.
let root = ReactDOM.createRoot(container, {hydrate: true});
root.render(<App />);
// Nothing has been hydrated so far.
expect(Scheduler).toHaveYielded([]);
// This click target cannot be hydrated yet because it's suspended.
let result = dispatchClickEvent(spanD);
expect(Scheduler).toHaveYielded(['App']);
expect(result).toBe(true);
// Continuing rendering will render B next.
expect(Scheduler).toFlushAndYield(['B', 'C']);
suspend = false;
resolve();
await promise;
// After the click, we should prioritize D and the Click first,
// and only after that render A and C.
expect(Scheduler).toFlushAndYield(['D', 'Clicked D', 'A']);
document.body.removeChild(container);
});
it('hydrates at higher pri for secondary discrete events (flare)', async () => {
let suspend = false;
let resolve;
let promise = new Promise(resolvePromise => (resolve = resolvePromise));
function Child({text}) {
if ((text === 'A' || text === 'D') && suspend) {
throw promise;
function App() {
Scheduler.unstable_yieldValue('App');
return (
<div>
<Suspense fallback="Loading...">
<Child text="A" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="B" />
</Suspense>
</div>
);
}
Scheduler.unstable_yieldValue(text);
const listener = usePress({
onPress() {
Scheduler.unstable_yieldValue('Clicked ' + text);
},
});
return <span DEPRECATED_flareListeners={listener}>{text}</span>;
}
let finalHTML = ReactDOMServer.renderToString(<App />);
function App() {
Scheduler.unstable_yieldValue('App');
return (
<div>
<Suspense fallback="Loading...">
<Child text="A" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="B" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="C" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="D" />
</Suspense>
</div>
);
}
expect(Scheduler).toHaveYielded(['App', 'A', 'B']);
let finalHTML = ReactDOMServer.renderToString(<App />);
let container = document.createElement('div');
// We need this to be in the document since we'll dispatch events on it.
document.body.appendChild(container);
expect(Scheduler).toHaveYielded(['App', 'A', 'B', 'C', 'D']);
container.innerHTML = finalHTML;
let container = document.createElement('div');
// We need this to be in the document since we'll dispatch events on it.
document.body.appendChild(container);
let root = ReactDOM.createRoot(container, {hydrate: true});
root.render(<App />);
container.innerHTML = finalHTML;
// Nothing has been hydrated so far.
expect(Scheduler).toHaveYielded([]);
let spanA = container.getElementsByTagName('span')[0];
let spanC = container.getElementsByTagName('span')[2];
let spanD = container.getElementsByTagName('span')[3];
let span = container.getElementsByTagName('span')[1];
suspend = true;
let target = createEventTarget(span);
// A and D will be suspended. We'll click on D which should take
// priority, after we unsuspend.
let root = ReactDOM.createRoot(container, {hydrate: true});
root.render(<App />);
// This should synchronously hydrate the root App and the second suspense
// boundary.
let preventDefault = jest.fn();
target.virtualclick({preventDefault});
// Nothing has been hydrated so far.
expect(Scheduler).toHaveYielded([]);
// The event should have been canceled because we called preventDefault.
expect(preventDefault).toHaveBeenCalled();
// This click target cannot be hydrated yet because the first is Suspended.
dispatchClickEvent(spanA);
dispatchClickEvent(spanC);
dispatchClickEvent(spanD);
// We rendered App, B and then invoked the event without rendering A.
expect(Scheduler).toHaveYielded(['App', 'B', 'Clicked B']);
expect(Scheduler).toHaveYielded(['App']);
// After continuing the scheduler, we finally hydrate A.
expect(Scheduler).toFlushAndYield(['A']);
suspend = false;
resolve();
await promise;
document.body.removeChild(container);
});
// We should prioritize hydrating A, C and D first since we clicked in
// them. Only after they're done will we hydrate B.
expect(Scheduler).toFlushAndYield([
'A',
'Clicked A',
'C',
'Clicked C',
'D',
'Clicked D',
// B should render last since it wasn't clicked.
'B',
]);
it('hydrates at higher pri if sync did not work first time (flare)', async () => {
let usePress = require('react-interactions/events/press').usePress;
let suspend = false;
let resolve;
let promise = new Promise(resolvePromise => (resolve = resolvePromise));
document.body.removeChild(container);
});
function Child({text}) {
if ((text === 'A' || text === 'D') && suspend) {
throw promise;
}
Scheduler.unstable_yieldValue(text);
const listener = usePress({
onPress() {
Scheduler.unstable_yieldValue('Clicked ' + text);
},
});
return <span DEPRECATED_flareListeners={listener}>{text}</span>;
}
function App() {
Scheduler.unstable_yieldValue('App');
return (
<div>
<Suspense fallback="Loading...">
<Child text="A" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="B" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="C" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="D" />
</Suspense>
</div>
);
}
let finalHTML = ReactDOMServer.renderToString(<App />);
expect(Scheduler).toHaveYielded(['App', 'A', 'B', 'C', 'D']);
let container = document.createElement('div');
// We need this to be in the document since we'll dispatch events on it.
document.body.appendChild(container);
container.innerHTML = finalHTML;
let spanD = container.getElementsByTagName('span')[3];
suspend = true;
// A and D will be suspended. We'll click on D which should take
// priority, after we unsuspend.
let root = ReactDOM.createRoot(container, {hydrate: true});
root.render(<App />);
// Nothing has been hydrated so far.
expect(Scheduler).toHaveYielded([]);
// This click target cannot be hydrated yet because it's suspended.
let result = dispatchClickEvent(spanD);
expect(Scheduler).toHaveYielded(['App']);
expect(result).toBe(true);
// Continuing rendering will render B next.
expect(Scheduler).toFlushAndYield(['B', 'C']);
suspend = false;
resolve();
await promise;
// After the click, we should prioritize D and the Click first,
// and only after that render A and C.
expect(Scheduler).toFlushAndYield(['D', 'Clicked D', 'A']);
document.body.removeChild(container);
});
it('hydrates at higher pri for secondary discrete events (flare)', async () => {
let usePress = require('react-interactions/events/press').usePress;
let suspend = false;
let resolve;
let promise = new Promise(resolvePromise => (resolve = resolvePromise));
function Child({text}) {
if ((text === 'A' || text === 'D') && suspend) {
throw promise;
}
Scheduler.unstable_yieldValue(text);
const listener = usePress({
onPress() {
Scheduler.unstable_yieldValue('Clicked ' + text);
},
});
return <span DEPRECATED_flareListeners={listener}>{text}</span>;
}
function App() {
Scheduler.unstable_yieldValue('App');
return (
<div>
<Suspense fallback="Loading...">
<Child text="A" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="B" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="C" />
</Suspense>
<Suspense fallback="Loading...">
<Child text="D" />
</Suspense>
</div>
);
}
let finalHTML = ReactDOMServer.renderToString(<App />);
expect(Scheduler).toHaveYielded(['App', 'A', 'B', 'C', 'D']);
let container = document.createElement('div');
// We need this to be in the document since we'll dispatch events on it.
document.body.appendChild(container);
container.innerHTML = finalHTML;
let spanA = container.getElementsByTagName('span')[0];
let spanC = container.getElementsByTagName('span')[2];
let spanD = container.getElementsByTagName('span')[3];
suspend = true;
// A and D will be suspended. We'll click on D which should take
// priority, after we unsuspend.
let root = ReactDOM.createRoot(container, {hydrate: true});
root.render(<App />);
// Nothing has been hydrated so far.
expect(Scheduler).toHaveYielded([]);
// This click target cannot be hydrated yet because the first is Suspended.
dispatchClickEvent(spanA);
dispatchClickEvent(spanC);
dispatchClickEvent(spanD);
expect(Scheduler).toHaveYielded(['App']);
suspend = false;
resolve();
await promise;
// We should prioritize hydrating A, C and D first since we clicked in
// them. Only after they're done will we hydrate B.
expect(Scheduler).toFlushAndYield([
'A',
'Clicked A',
'C',
'Clicked C',
'D',
'Clicked D',
// B should render last since it wasn't clicked.
'B',
]);
document.body.removeChild(container);
});
}
it('hydrates the hovered targets as higher priority for continuous events', async () => {
let suspend = false;
@@ -19,7 +19,7 @@ const renderSubtreeIntoContainer = require('react-dom')
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
// Once this flag is always true, we should delete this test file
if (ReactFeatureFlags.disableUnstableRenderSubtreeIntoContainer) {
if (__EXPERIMENTAL__) {
describe('renderSubtreeIntoContainer', () => {
it('empty test', () => {
// Empty test to prevent "Your test suite must contain at least one test." error.
+93 -98
View File
@@ -35,7 +35,6 @@ import {
attemptUserBlockingHydration,
attemptContinuousHydration,
attemptHydrationAtCurrentPriority,
act,
} from 'react-reconciler/inline.dom';
import {createPortal as createPortalImpl} from 'shared/ReactPortal';
import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -56,14 +55,7 @@ import {
} from 'legacy-events/EventPropagators';
import ReactVersion from 'shared/ReactVersion';
import invariant from 'shared/invariant';
import {
exposeConcurrentModeAPIs,
disableLegacyReactDOMAPIs,
disableUnstableCreatePortal,
disableUnstableRenderSubtreeIntoContainer,
warnUnstableRenderSubtreeIntoContainer,
isTestEnvironment,
} from 'shared/ReactFeatureFlags';
import {warnUnstableRenderSubtreeIntoContainer} from 'shared/ReactFeatureFlags';
import {
getInstanceFromNode,
@@ -120,104 +112,113 @@ function createPortal(
children: ReactNodeList,
container: Container,
key: ?string = null,
) {
): React$Portal {
invariant(
isValidContainer(container),
'Target container is not a DOM element.',
);
// TODO: pass ReactDOM portal implementation as third argument
// $FlowFixMe The Flow type is opaque but there's no way to actually create it.
return createPortalImpl(children, container, null, key);
}
const ReactDOM: Object = {
createPortal,
function scheduleHydration(target: Node) {
if (target) {
queueExplicitHydrationTarget(target);
}
}
unstable_batchedUpdates: batchedUpdates,
function renderSubtreeIntoContainer(
parentComponent: React$Component<any, any>,
element: React$Element<any>,
containerNode: Container,
callback: ?Function,
) {
if (__DEV__) {
if (
warnUnstableRenderSubtreeIntoContainer &&
!didWarnAboutUnstableRenderSubtreeIntoContainer
) {
didWarnAboutUnstableRenderSubtreeIntoContainer = true;
console.warn(
'ReactDOM.unstable_renderSubtreeIntoContainer() is deprecated ' +
'and will be removed in a future major release. Consider using ' +
'React Portals instead.',
);
}
}
return unstable_renderSubtreeIntoContainer(
parentComponent,
element,
containerNode,
callback,
);
}
flushSync: flushSync,
function unstable_createPortal(
children: ReactNodeList,
container: Container,
key: ?string = null,
) {
if (__DEV__) {
if (!didWarnAboutUnstableCreatePortal) {
didWarnAboutUnstableCreatePortal = true;
console.warn(
'The ReactDOM.unstable_createPortal() alias has been deprecated, ' +
'and will be removed in React 17+. Update your code to use ' +
'ReactDOM.createPortal() instead. It has the exact same API, ' +
'but without the "unstable_" prefix.',
);
}
}
return createPortal(children, container, key);
}
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
// Keep in sync with ReactDOMUnstableNativeDependencies.js
// ReactTestUtils.js, and ReactTestUtilsAct.js. This is an array for better minification.
Events: [
getInstanceFromNode,
getNodeFromInstance,
getFiberCurrentPropsFromNode,
injectEventPluginsByName,
eventNameDispatchConfigs,
accumulateTwoPhaseDispatches,
accumulateDirectDispatches,
enqueueStateRestore,
restoreStateIfNeeded,
dispatchEvent,
runEventsInBatch,
flushPassiveEffects,
IsThisRendererActing,
],
},
version: ReactVersion,
const Internals = {
// Keep in sync with ReactDOMUnstableNativeDependencies.js
// ReactTestUtils.js, and ReactTestUtilsAct.js. This is an array for better minification.
Events: [
getInstanceFromNode,
getNodeFromInstance,
getFiberCurrentPropsFromNode,
injectEventPluginsByName,
eventNameDispatchConfigs,
accumulateTwoPhaseDispatches,
accumulateDirectDispatches,
enqueueStateRestore,
restoreStateIfNeeded,
dispatchEvent,
runEventsInBatch,
flushPassiveEffects,
IsThisRendererActing,
],
};
if (!disableLegacyReactDOMAPIs) {
ReactDOM.findDOMNode = findDOMNode;
ReactDOM.hydrate = hydrate;
ReactDOM.render = render;
ReactDOM.unmountComponentAtNode = unmountComponentAtNode;
}
if (exposeConcurrentModeAPIs) {
ReactDOM.createRoot = createRoot;
ReactDOM.createBlockingRoot = createBlockingRoot;
ReactDOM.unstable_discreteUpdates = discreteUpdates;
ReactDOM.unstable_flushDiscreteUpdates = flushDiscreteUpdates;
ReactDOM.unstable_flushControlled = flushControlled;
ReactDOM.unstable_scheduleHydration = target => {
if (target) {
queueExplicitHydrationTarget(target);
}
};
}
if (!disableUnstableRenderSubtreeIntoContainer) {
ReactDOM.unstable_renderSubtreeIntoContainer = function(...args) {
if (__DEV__) {
if (
warnUnstableRenderSubtreeIntoContainer &&
!didWarnAboutUnstableRenderSubtreeIntoContainer
) {
didWarnAboutUnstableRenderSubtreeIntoContainer = true;
console.warn(
'ReactDOM.unstable_renderSubtreeIntoContainer() is deprecated ' +
'and will be removed in a future major release. Consider using ' +
'React Portals instead.',
);
}
}
return unstable_renderSubtreeIntoContainer(...args);
};
}
if (!disableUnstableCreatePortal) {
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,
hydrate,
render,
unmountComponentAtNode,
// exposeConcurrentModeAPIs
createRoot,
createBlockingRoot,
discreteUpdates as unstable_discreteUpdates,
flushDiscreteUpdates as unstable_flushDiscreteUpdates,
flushControlled as unstable_flushControlled,
scheduleHydration as unstable_scheduleHydration,
// Disabled behind disableUnstableRenderSubtreeIntoContainer
renderSubtreeIntoContainer as unstable_renderSubtreeIntoContainer,
// Disabled behind disableUnstableCreatePortal
// Temporary alias since we already shipped React 16 RC with it.
// TODO: remove in React 17.
ReactDOM.unstable_createPortal = function(...args) {
if (__DEV__) {
if (!didWarnAboutUnstableCreatePortal) {
didWarnAboutUnstableCreatePortal = true;
console.warn(
'The ReactDOM.unstable_createPortal() alias has been deprecated, ' +
'and will be removed in React 17+. Update your code to use ' +
'ReactDOM.createPortal() instead. It has the exact same API, ' +
'but without the "unstable_" prefix.',
);
}
}
return createPortal(...args);
};
}
unstable_createPortal,
};
const foundDevTools = injectIntoDevTools({
findFiberByHostInstance: getClosestInstanceFromNode,
@@ -252,9 +253,3 @@ if (__DEV__) {
}
}
}
if (isTestEnvironment) {
ReactDOM.act = act;
}
export default ReactDOM;
-36
View File
@@ -1,36 +0,0 @@
/**
* 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 {addUserTimingListener} from 'shared/ReactFeatureFlags';
import ReactDOM from './ReactDOM';
import {isEnabled} from '../events/ReactDOMEventListener';
import {getClosestInstanceFromNode} from './ReactDOMComponentTree';
if (__EXPERIMENTAL__) {
// This is a modern WWW build.
// It should be the same as open source. Don't add new things here.
} else {
// For classic WWW builds, include a few internals that are already in use.
Object.assign(
(ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: any),
{
ReactBrowserEventEmitter: {
isEnabled,
},
ReactDOMComponentTree: {
getClosestInstanceFromNode,
},
// Perf experiment
addUserTimingListener,
},
);
}
export default ReactDOM;
+2 -2
View File
@@ -101,8 +101,8 @@ export type EventTargetChildElement = {
...
};
export type Container =
| (Element & {_reactRootContainer: ?RootType, ...})
| (Document & {_reactRootContainer: ?RootType, ...});
| (Element & {_reactRootContainer?: RootType, ...})
| (Document & {_reactRootContainer?: RootType, ...});
export type Instance = Element;
export type TextInstance = Text;
export type SuspenseInstance = Comment & {_reactRetry?: () => void, ...};
+1
View File
@@ -370,6 +370,7 @@ export function unmountComponentAtNode(container: Container) {
// Unmount should not be batched.
unbatchedUpdates(() => {
legacyRenderSubtreeIntoContainer(null, null, container, false, () => {
// $FlowFixMe This should probably use `delete container._reactRootContainer`
container._reactRootContainer = null;
unmarkContainerAsRoot(container);
});
@@ -66,6 +66,11 @@ function dispatchClickEvent(element) {
describe('DOMEventResponderSystem', () => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
+11
View File
@@ -0,0 +1,11 @@
/**
* 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
*/
export * from './index.classic.fb.js';
export {act} from 'react-reconciler/inline.dom';
@@ -0,0 +1,11 @@
/**
* 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
*/
export * from './index.experimental.js';
export {act} from 'react-reconciler/inline.dom';
+2 -7
View File
@@ -7,10 +7,5 @@
* @flow
*/
'use strict';
const ReactDOM = require('./src/client/ReactDOM');
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = ReactDOM.default || ReactDOM;
export * from './index.js';
export {act} from 'react-reconciler/inline.dom';
+11
View File
@@ -0,0 +1,11 @@
/**
* 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
*/
export * from './index.modern.fb.js';
export {act} from 'react-reconciler/inline.dom';
+11
View File
@@ -0,0 +1,11 @@
/**
* 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
*/
export * from './index.stable.js';
export {act} from 'react-reconciler/inline.dom';
@@ -38,6 +38,11 @@ const table = [[forcePointerEvents], [!forcePointerEvents]];
describe.each(table)('ContextMenu responder', hasPointerEvents => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
initializeModules(hasPointerEvents);
container = document.createElement('div');
@@ -38,6 +38,11 @@ const table = [[forcePointerEvents], [!forcePointerEvents]];
describe.each(table)('Focus responder', hasPointerEvents => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
initializeModules(hasPointerEvents);
container = document.createElement('div');
@@ -37,6 +37,11 @@ const table = [[forcePointerEvents], [!forcePointerEvents]];
describe.each(table)('FocusWithin responder', hasPointerEvents => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
initializeModules();
container = document.createElement('div');
@@ -34,6 +34,11 @@ const table = [[forcePointerEvents], [!forcePointerEvents]];
describe.each(table)('Hover responder', hasPointerEvents => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
initializeModules(hasPointerEvents);
container = document.createElement('div');
@@ -45,6 +45,11 @@ const modulesInit = () => {
describe('Input event responder', () => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
jest.resetModules();
modulesInit();
@@ -28,6 +28,11 @@ function initializeModules(hasPointerEvents) {
describe('Keyboard responder', () => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
initializeModules();
container = document.createElement('div');
@@ -19,6 +19,11 @@ let Scheduler;
describe('mixing responders with the heritage event system', () => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
@@ -38,6 +38,11 @@ const pointerTypesTable = [['mouse'], ['touch']];
describeWithPointerEvent('Press responder', hasPointerEvents => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
initializeModules(hasPointerEvents);
container = document.createElement('div');
@@ -50,6 +50,11 @@ const pointerTypesTable = [['mouse'], ['touch']];
describe.each(environmentTable)('Press responder', hasPointerEvents => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
initializeModules(hasPointerEvents);
container = document.createElement('div');
@@ -73,6 +73,11 @@ function tapAndReleaseOutside({
describeWithPointerEvent('Tap responder', hasPointerEvents => {
let container;
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
beforeEach(() => {
initializeModules(hasPointerEvents);
container = document.createElement('div');
+1 -3
View File
@@ -13,8 +13,6 @@ let React;
let ReactDOM;
let ReactIs;
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
describe('ReactIs', () => {
beforeEach(() => {
jest.resetModules();
@@ -56,7 +54,7 @@ describe('ReactIs', () => {
expect(ReactIs.isValidElementType(MemoComponent)).toEqual(true);
expect(ReactIs.isValidElementType(Context.Provider)).toEqual(true);
expect(ReactIs.isValidElementType(Context.Consumer)).toEqual(true);
if (!ReactFeatureFlags.disableCreateFactory) {
if (!__EXPERIMENTAL__) {
let factory;
expect(() => {
factory = React.createFactory('div');
+2 -1
View File
@@ -9,6 +9,7 @@
import type {ReactFabricType, HostComponent} from './ReactNativeTypes';
import type {ReactNodeList} from 'shared/ReactTypes';
import type {ElementRef} from 'react';
import './ReactFabricInjection';
@@ -43,7 +44,7 @@ const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
function findHostInstance_DEPRECATED(
componentOrHandle: any,
): ?React$ElementRef<HostComponent<mixed>> {
): ?ElementRef<HostComponent<mixed>> {
if (__DEV__) {
const owner = ReactCurrentOwner.current;
if (owner !== null && owner.stateNode !== null) {
@@ -7,7 +7,9 @@
* @flow
*/
import type {ElementRef} from 'react';
import type {
HostComponent,
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
@@ -126,7 +128,7 @@ class ReactFabricHostComponent {
}
measureLayout(
relativeToNativeNode: number | ReactFabricHostComponent,
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void /* currently unused */,
) {
@@ -7,7 +7,9 @@
* @flow
*/
import type {ElementRef} from 'react';
import type {
HostComponent,
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
@@ -62,7 +64,7 @@ class ReactNativeFiberHostComponent {
}
measureLayout(
relativeToNativeNode: number | ReactNativeFiberHostComponent,
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void /* currently unused */,
) {
@@ -71,8 +73,11 @@ class ReactNativeFiberHostComponent {
if (typeof relativeToNativeNode === 'number') {
// Already a node handle
relativeNode = relativeToNativeNode;
} else if (relativeToNativeNode._nativeTag) {
relativeNode = relativeToNativeNode._nativeTag;
} else {
let nativeNode: ReactNativeFiberHostComponent = (relativeToNativeNode: any);
if (nativeNode._nativeTag) {
relativeNode = nativeNode._nativeTag;
}
}
if (relativeNode == null) {
@@ -7,8 +7,6 @@
* @flow
*/
import type {ReactNativeBaseComponentViewConfig} from './ReactNativeTypes';
import invariant from 'shared/invariant';
// Modules provided by RN:
@@ -31,12 +29,7 @@ const {get: getViewConfigForType} = ReactNativeViewConfigRegistry;
export type Type = string;
export type Props = Object;
export type Container = number;
export type Instance = {
_children: Array<Instance | number>,
_nativeTag: number,
viewConfig: ReactNativeBaseComponentViewConfig<>,
...
};
export type Instance = ReactNativeFiberHostComponent;
export type TextInstance = number;
export type HydratableInstance = Instance | TextInstance;
export type PublicInstance = Instance;
+3 -1
View File
@@ -126,7 +126,9 @@ export type ReactNativeType = {
};
export type ReactFabricType = {
findHostInstance_DEPRECATED(componentOrHandle: any): ?HostComponent<mixed>,
findHostInstance_DEPRECATED(
componentOrHandle: any,
): ?ElementRef<HostComponent<mixed>>,
findNodeHandle(componentOrHandle: any): ?number,
dispatchCommand(handle: any, command: string, args: Array<any>): void,
render(
@@ -50,6 +50,11 @@ function initReactDOMServer() {
}
describe('ReactFiberFundamental', () => {
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
describe('NoopRenderer', () => {
beforeEach(() => {
initNoopRenderer();
@@ -23,6 +23,11 @@ describe('ReactScope', () => {
React = require('react');
});
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
describe('ReactDOM', () => {
let ReactDOM;
let container;
+55
View File
@@ -0,0 +1,55 @@
/**
* 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
*/
export {
Children,
createRef,
Component,
PureComponent,
createContext,
forwardRef,
lazy,
memo,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useDebugValue,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
Fragment,
Profiler,
StrictMode,
Suspense,
createElement,
cloneElement,
isValidElement,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
createFactory,
// exposeConcurrentModeAPIs
useTransition,
useDeferredValue,
SuspenseList,
unstable_withSuspenseConfig,
// enableBlocksAPI
block,
// enableDeprecatedFlareAPI
DEPRECATED_useResponder,
DEPRECATED_createResponder,
// enableScopeAPI
unstable_createScope,
// enableJSXTransformAPI
jsx,
jsxs,
jsxDEV,
} from './src/React';
+46
View File
@@ -0,0 +1,46 @@
/**
* 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
*/
export {
Children,
createRef,
Component,
PureComponent,
createContext,
forwardRef,
lazy,
memo,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useDebugValue,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
Fragment,
Profiler,
StrictMode,
Suspense,
createElement,
cloneElement,
isValidElement,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
createFactory,
// exposeConcurrentModeAPIs
useTransition,
useDeferredValue,
SuspenseList,
unstable_withSuspenseConfig,
// enableBlocksAPI
block,
} from './src/React';
+70 -6
View File
@@ -7,10 +7,74 @@
* @flow
*/
'use strict';
// Keep in sync with https://github.com/facebook/flow/blob/master/lib/react.js
export type StatelessFunctionalComponent<
P,
> = React$StatelessFunctionalComponent<P>;
export type ComponentType<-P> = React$ComponentType<P>;
export type AbstractComponent<
-Config,
+Instance = mixed,
> = React$AbstractComponent<Config, Instance>;
export type ElementType = React$ElementType;
export type Element<+C> = React$Element<C>;
export type Key = React$Key;
export type Ref<C> = React$Ref<C>;
export type Node = React$Node;
export type Context<T> = React$Context<T>;
export type Portal = React$Portal;
export type ElementProps<C> = React$ElementProps<C>;
export type ElementConfig<C> = React$ElementConfig<C>;
export type ElementRef<C> = React$ElementRef<C>;
export type Config<Props, DefaultProps> = React$Config<Props, DefaultProps>;
export type ChildrenArray<+T> = $ReadOnlyArray<ChildrenArray<T>> | T;
export type Interaction = {
name: string,
timestamp: number,
...
};
const React = require('./src/React');
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = React.default || React;
// Export all exports so that they're available in tests.
// We can't use export * from in Flow for some reason.
export {
Children,
createRef,
Component,
PureComponent,
createContext,
forwardRef,
lazy,
memo,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useDebugValue,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
Fragment,
Profiler,
StrictMode,
Suspense,
createElement,
cloneElement,
isValidElement,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
createFactory,
useTransition,
useDeferredValue,
SuspenseList,
unstable_withSuspenseConfig,
block,
DEPRECATED_useResponder,
DEPRECATED_createResponder,
unstable_createFundamental,
unstable_createScope,
jsx,
jsxs,
jsxDEV,
} from './src/React';
+54
View File
@@ -0,0 +1,54 @@
/**
* 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
*/
export {
Children,
createRef,
Component,
PureComponent,
createContext,
forwardRef,
lazy,
memo,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useDebugValue,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
Fragment,
Profiler,
StrictMode,
Suspense,
createElement,
cloneElement,
isValidElement,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
// exposeConcurrentModeAPIs
useTransition,
useDeferredValue,
SuspenseList,
unstable_withSuspenseConfig,
// enableBlocksAPI
block,
// enableDeprecatedFlareAPI
DEPRECATED_useResponder,
DEPRECATED_createResponder,
// enableScopeAPI
unstable_createScope,
// enableJSXTransformAPI
jsx,
jsxs,
jsxDEV,
} from './src/React';
+39
View File
@@ -0,0 +1,39 @@
/**
* 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
*/
export {
Children,
createRef,
Component,
PureComponent,
createContext,
forwardRef,
lazy,
memo,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useDebugValue,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
Fragment,
Profiler,
StrictMode,
Suspense,
createElement,
cloneElement,
isValidElement,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
createFactory,
} from './src/React';
+55 -84
View File
@@ -18,11 +18,11 @@ import {Component, PureComponent} from './ReactBaseClasses';
import {createRef} from './ReactCreateRef';
import {forEach, map, count, toArray, only} from './ReactChildren';
import {
createElement,
createFactory,
cloneElement,
createElement as createElementProd,
createFactory as createFactoryProd,
cloneElement as cloneElementProd,
isValidElement,
jsx,
jsx as jsxProd,
} from './ReactElement';
import {createContext} from './ReactContext';
import {lazy} from './ReactLazy';
@@ -57,33 +57,35 @@ import ReactSharedInternals from './ReactSharedInternals';
import createFundamental from 'shared/createFundamentalComponent';
import createResponder from 'shared/createEventResponder';
import createScope from 'shared/createScope';
import {
enableJSXTransformAPI,
enableDeprecatedFlareAPI,
enableFundamentalAPI,
enableScopeAPI,
exposeConcurrentModeAPIs,
enableBlocksAPI,
disableCreateFactory,
} from 'shared/ReactFeatureFlags';
const React = {
Children: {
map,
forEach,
count,
toArray,
only,
},
// TODO: Move this branching into the other module instead and just re-export.
const createElement = __DEV__ ? createElementWithValidation : createElementProd;
const cloneElement = __DEV__ ? cloneElementWithValidation : cloneElementProd;
const createFactory = __DEV__ ? createFactoryWithValidation : createFactoryProd;
const jsxDEV = __DEV__ ? jsxWithValidation : undefined;
const jsx = __DEV__ ? jsxWithValidationDynamic : jsxProd;
// we may want to special case jsxs internally to take advantage of static children.
// for now we can ship identical prod functions
const jsxs = __DEV__ ? jsxWithValidationStatic : jsxProd;
const Children = {
map,
forEach,
count,
toArray,
only,
};
export {
Children,
createRef,
Component,
PureComponent,
createContext,
forwardRef,
lazy,
memo,
useCallback,
useContext,
useEffect,
@@ -94,65 +96,34 @@ const React = {
useReducer,
useRef,
useState,
Fragment: REACT_FRAGMENT_TYPE,
Profiler: REACT_PROFILER_TYPE,
StrictMode: REACT_STRICT_MODE_TYPE,
Suspense: REACT_SUSPENSE_TYPE,
createElement: __DEV__ ? createElementWithValidation : createElement,
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
isValidElement: isValidElement,
version: ReactVersion,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals,
REACT_FRAGMENT_TYPE as Fragment,
REACT_PROFILER_TYPE as Profiler,
REACT_STRICT_MODE_TYPE as StrictMode,
REACT_SUSPENSE_TYPE as Suspense,
createElement,
cloneElement,
isValidElement,
ReactVersion as version,
ReactSharedInternals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
// Deprecated behind disableCreateFactory
createFactory,
// Concurrent Mode
useTransition,
useDeferredValue,
REACT_SUSPENSE_LIST_TYPE as SuspenseList,
withSuspenseConfig as unstable_withSuspenseConfig,
// enableBlocksAPI
block,
// enableDeprecatedFlareAPI
useResponder as DEPRECATED_useResponder,
createResponder as DEPRECATED_createResponder,
// enableFundamentalAPI
createFundamental as unstable_createFundamental,
// enableScopeAPI
createScope as unstable_createScope,
// enableJSXTransformAPI
jsx,
jsxs,
// TODO: jsxDEV should not be exposed as a name. We might want to move it to a different entry point.
jsxDEV,
};
if (!disableCreateFactory) {
React.createFactory = __DEV__ ? createFactoryWithValidation : createFactory;
}
if (exposeConcurrentModeAPIs) {
React.useTransition = useTransition;
React.useDeferredValue = useDeferredValue;
React.SuspenseList = REACT_SUSPENSE_LIST_TYPE;
React.unstable_withSuspenseConfig = withSuspenseConfig;
}
if (enableBlocksAPI) {
React.block = block;
}
if (enableDeprecatedFlareAPI) {
React.DEPRECATED_useResponder = useResponder;
React.DEPRECATED_createResponder = createResponder;
}
if (enableFundamentalAPI) {
React.unstable_createFundamental = createFundamental;
}
if (enableScopeAPI) {
React.unstable_createScope = createScope;
}
// Note: some APIs are added with feature flags.
// Make sure that stable builds for open source
// don't modify the React object to avoid deopts.
// Also let's not expose their names in stable builds.
if (enableJSXTransformAPI) {
if (__DEV__) {
React.jsxDEV = jsxWithValidation;
React.jsx = jsxWithValidationDynamic;
React.jsxs = jsxWithValidationStatic;
} else {
React.jsx = jsx;
// we may want to special case jsxs internally to take advantage of static children.
// for now we can ship identical prod functions
React.jsxs = jsx;
}
}
export default React;
@@ -13,8 +13,6 @@ let React;
let ReactDOM;
let ReactTestUtils;
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
describe('ReactElement', () => {
let ComponentClass;
let originalSymbol;
@@ -312,7 +310,7 @@ describe('ReactElement', () => {
expect(React.isValidElement(true)).toEqual(false);
expect(React.isValidElement({})).toEqual(false);
expect(React.isValidElement('string')).toEqual(false);
if (!ReactFeatureFlags.disableCreateFactory) {
if (!__EXPERIMENTAL__) {
let factory;
expect(() => {
factory = React.createFactory('div');
@@ -481,7 +479,7 @@ describe('ReactElement', () => {
expect(React.isValidElement(true)).toEqual(false);
expect(React.isValidElement({})).toEqual(false);
expect(React.isValidElement('string')).toEqual(false);
if (!ReactFeatureFlags.disableCreateFactory) {
if (!__EXPERIMENTAL__) {
let factory;
expect(() => {
factory = React.createFactory('div');
@@ -31,7 +31,6 @@ describe('ReactElement.jsx', () => {
global.Symbol = undefined;
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableJSXTransformAPI = true;
ReactFeatureFlags.warnAboutSpreadingKeyToJSX = true;
React = require('react');
@@ -43,6 +42,11 @@ describe('ReactElement.jsx', () => {
global.Symbol = originalSymbol;
});
if (!__EXPERIMENTAL__) {
it("empty test so Jest doesn't complain", () => {});
return;
}
it('allows static methods to be called using the type property', () => {
class StaticMethodComponentClass extends React.Component {
render() {
@@ -69,7 +73,7 @@ describe('ReactElement.jsx', () => {
expect(React.isValidElement(true)).toEqual(false);
expect(React.isValidElement({})).toEqual(false);
expect(React.isValidElement('string')).toEqual(false);
if (!ReactFeatureFlags.disableCreateFactory) {
if (!__EXPERIMENTAL__) {
let factory;
expect(() => {
factory = React.createFactory('div');
@@ -292,9 +296,6 @@ describe('ReactElement.jsx', () => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableJSXTransformAPI = true;
React = require('react');
class Component extends React.Component {
@@ -310,7 +311,7 @@ describe('ReactElement.jsx', () => {
expect(React.isValidElement(true)).toEqual(false);
expect(React.isValidElement({})).toEqual(false);
expect(React.isValidElement('string')).toEqual(false);
if (!ReactFeatureFlags.disableCreateFactory) {
if (!__EXPERIMENTAL__) {
let factory;
expect(() => {
factory = React.createFactory('div');
@@ -439,7 +439,7 @@ describe('ReactElementValidator', () => {
);
});
if (!ReactFeatureFlags.disableCreateFactory) {
if (!__EXPERIMENTAL__) {
it('should warn when accessing .type on an element factory', () => {
function TestComponent() {
return <div />;
-20
View File
@@ -44,10 +44,6 @@ export function addUserTimingListener() {
// Disable javascript: URL strings in href for XSS protection.
export const disableJavaScriptURLs = false;
// These APIs will no longer be "unstable" in the upcoming 16.7 release,
// Control this behavior with a flag to support 16.6 minor releases in the meanwhile.
export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
// Warns when a combination of updates on a dom can cause a style declaration
// that clashes with a previous one https://github.com/facebook/react/pull/14181
export const warnAboutShorthandPropertyCollision = true;
@@ -62,7 +58,6 @@ export const enableFundamentalAPI = false;
export const enableScopeAPI = false;
// New API for JSX transforms to target - https://github.com/reactjs/rfcs/pull/107
export const enableJSXTransformAPI = false;
// We will enforce mocking scheduler with scheduler/unstable_mock at some point. (v17?)
// Till then, we warn about the missing mock, but still fallback to a legacy mode compatible version
@@ -108,10 +103,6 @@ export const runAllPassiveEffectDestroysBeforeCreates = false;
// WARNING This flag only has an affect if used with runAllPassiveEffectDestroysBeforeCreates.
export const deferPassiveEffectCleanupDuringUnmount = false;
// Use this flag to generate "testing" builds, that include APIs like act()
// and extra warnings/errors
export const isTestEnvironment = false;
// Enables a warning when trying to spread a 'key' to an element;
// a deprecated pattern we want to get rid of in the future
export const warnAboutSpreadingKeyToJSX = false;
@@ -128,25 +119,14 @@ export const warnAboutStringRefs = false;
export const disableLegacyContext = false;
// Disables React.createFactory
export const disableCreateFactory = false;
// Disables hydrate, render, findDOMNode, unmountComponentAtNode
export const disableLegacyReactDOMAPIs = false;
// Disables children for <textarea> elements
export const disableTextareaChildren = false;
// Disables Maps as ReactElement children
export const disableMapsAsChildren = false;
// Disables ReactDOM.unstable_renderSubtreeIntoContainer
export const disableUnstableRenderSubtreeIntoContainer = false;
// We should remove this flag once the above flag becomes enabled
export const warnUnstableRenderSubtreeIntoContainer = false;
// Disables ReactDOM.unstable_createPortal
export const disableUnstableCreatePortal = false;
// Modern event system where events get registered at roots
export const enableModernEventSystem = false;
+2
View File
@@ -3,6 +3,8 @@
*
* 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 React from 'react';
@@ -24,7 +24,6 @@ export const enableSchedulerTracing = __PROFILE__;
export const enableSuspenseServerRenderer = false;
export const enableSelectiveHydration = false;
export const enableBlocksAPI = false;
export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
export const warnAboutShorthandPropertyCollision = true;
export const enableSchedulerDebugging = false;
export const debugRenderPhaseSideEffectsForStrictMode = true;
@@ -35,7 +34,6 @@ export const warnAboutDeprecatedLifecycles = true;
export const enableDeprecatedFlareAPI = false;
export const enableFundamentalAPI = false;
export const enableScopeAPI = false;
export const enableJSXTransformAPI = false;
export const warnAboutUnmockedScheduler = true;
export const flushSuspenseFallbacksInTests = true;
export const enableSuspenseCallback = false;
@@ -45,16 +43,11 @@ export const disableLegacyContext = false;
export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
export const enableTrainModelFix = true;
export const enableTrustedTypesIntegration = false;
export const disableCreateFactory = false;
export const disableLegacyReactDOMAPIs = false;
export const disableTextareaChildren = false;
export const disableMapsAsChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
export const deferPassiveEffectCleanupDuringUnmount = false;
export const runAllPassiveEffectDestroysBeforeCreates = false;
export const isTestEnvironment = false;
export const enableModernEventSystem = false;
export const warnAboutSpreadingKeyToJSX = false;
@@ -23,13 +23,11 @@ export const enableSelectiveHydration = false;
export const enableBlocksAPI = false;
export const disableJavaScriptURLs = false;
export const disableInputAttributeSyncing = false;
export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
export const warnAboutShorthandPropertyCollision = true;
export const enableSchedulerDebugging = false;
export const enableDeprecatedFlareAPI = false;
export const enableFundamentalAPI = false;
export const enableScopeAPI = false;
export const enableJSXTransformAPI = false;
export const warnAboutUnmockedScheduler = false;
export const flushSuspenseFallbacksInTests = true;
export const enableSuspenseCallback = false;
@@ -40,16 +38,11 @@ export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
export const enableTrainModelFix = true;
export const enableTrustedTypesIntegration = false;
export const enableNativeTargetAsInstance = false;
export const disableCreateFactory = false;
export const disableLegacyReactDOMAPIs = false;
export const disableTextareaChildren = false;
export const disableMapsAsChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
export const deferPassiveEffectCleanupDuringUnmount = false;
export const runAllPassiveEffectDestroysBeforeCreates = false;
export const isTestEnvironment = false;
export const enableModernEventSystem = false;
export const warnAboutSpreadingKeyToJSX = false;
@@ -23,13 +23,11 @@ export const enableSelectiveHydration = false;
export const enableBlocksAPI = false;
export const disableJavaScriptURLs = false;
export const disableInputAttributeSyncing = false;
export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
export const warnAboutShorthandPropertyCollision = true;
export const enableSchedulerDebugging = false;
export const enableDeprecatedFlareAPI = false;
export const enableFundamentalAPI = false;
export const enableScopeAPI = false;
export const enableJSXTransformAPI = false;
export const warnAboutUnmockedScheduler = true;
export const flushSuspenseFallbacksInTests = true;
export const enableSuspenseCallback = false;
@@ -40,16 +38,11 @@ export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
export const enableTrainModelFix = true;
export const enableTrustedTypesIntegration = false;
export const enableNativeTargetAsInstance = false;
export const disableCreateFactory = false;
export const disableLegacyReactDOMAPIs = false;
export const disableTextareaChildren = false;
export const disableMapsAsChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
export const deferPassiveEffectCleanupDuringUnmount = false;
export const runAllPassiveEffectDestroysBeforeCreates = false;
export const isTestEnvironment = false;
export const enableModernEventSystem = false;
export const warnAboutSpreadingKeyToJSX = false;
@@ -23,13 +23,11 @@ export const enableSelectiveHydration = false;
export const enableBlocksAPI = false;
export const disableJavaScriptURLs = false;
export const disableInputAttributeSyncing = false;
export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
export const warnAboutShorthandPropertyCollision = true;
export const enableSchedulerDebugging = false;
export const enableDeprecatedFlareAPI = false;
export const enableFundamentalAPI = false;
export const enableScopeAPI = false;
export const enableJSXTransformAPI = false;
export const warnAboutUnmockedScheduler = false;
export const flushSuspenseFallbacksInTests = true;
export const enableSuspenseCallback = false;
@@ -40,16 +38,11 @@ export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
export const enableTrainModelFix = true;
export const enableTrustedTypesIntegration = false;
export const enableNativeTargetAsInstance = false;
export const disableCreateFactory = false;
export const disableLegacyReactDOMAPIs = false;
export const disableTextareaChildren = false;
export const disableMapsAsChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
export const deferPassiveEffectCleanupDuringUnmount = false;
export const runAllPassiveEffectDestroysBeforeCreates = false;
export const isTestEnvironment = true; // this should probably *never* change
export const enableModernEventSystem = false;
export const warnAboutSpreadingKeyToJSX = false;
@@ -21,7 +21,6 @@ export const enableSchedulerTracing = __PROFILE__;
export const enableSuspenseServerRenderer = false;
export const enableSelectiveHydration = false;
export const enableBlocksAPI = false;
export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
export const warnAboutShorthandPropertyCollision = true;
export const enableSchedulerDebugging = false;
export const disableJavaScriptURLs = false;
@@ -29,7 +28,6 @@ export const disableInputAttributeSyncing = false;
export const enableDeprecatedFlareAPI = true;
export const enableFundamentalAPI = false;
export const enableScopeAPI = true;
export const enableJSXTransformAPI = true;
export const warnAboutUnmockedScheduler = true;
export const flushSuspenseFallbacksInTests = true;
export const enableSuspenseCallback = true;
@@ -40,16 +38,11 @@ export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
export const enableTrainModelFix = true;
export const enableTrustedTypesIntegration = false;
export const enableNativeTargetAsInstance = false;
export const disableCreateFactory = false;
export const disableLegacyReactDOMAPIs = false;
export const disableTextareaChildren = false;
export const disableMapsAsChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
export const deferPassiveEffectCleanupDuringUnmount = false;
export const runAllPassiveEffectDestroysBeforeCreates = false;
export const isTestEnvironment = true; // this should probably *never* change
export const enableModernEventSystem = false;
export const warnAboutSpreadingKeyToJSX = false;
@@ -23,13 +23,11 @@ export const enableSelectiveHydration = false;
export const enableBlocksAPI = false;
export const disableJavaScriptURLs = false;
export const disableInputAttributeSyncing = false;
export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
export const warnAboutShorthandPropertyCollision = true;
export const enableSchedulerDebugging = false;
export const enableDeprecatedFlareAPI = false;
export const enableFundamentalAPI = false;
export const enableScopeAPI = false;
export const enableJSXTransformAPI = false;
export const warnAboutUnmockedScheduler = false;
export const flushSuspenseFallbacksInTests = true;
export const enableSuspenseCallback = false;
@@ -40,16 +38,11 @@ export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
export const enableTrainModelFix = true;
export const enableTrustedTypesIntegration = false;
export const enableNativeTargetAsInstance = false;
export const disableCreateFactory = false;
export const disableLegacyReactDOMAPIs = false;
export const disableTextareaChildren = false;
export const disableMapsAsChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
export const deferPassiveEffectCleanupDuringUnmount = false;
export const runAllPassiveEffectDestroysBeforeCreates = false;
export const isTestEnvironment = true;
export const enableModernEventSystem = false;
export const warnAboutSpreadingKeyToJSX = false;
@@ -23,13 +23,11 @@ export const enableSelectiveHydration = true;
export const enableBlocksAPI = true;
export const disableJavaScriptURLs = true;
export const disableInputAttributeSyncing = false;
export const exposeConcurrentModeAPIs = true;
export const warnAboutShorthandPropertyCollision = true;
export const enableSchedulerDebugging = false;
export const enableDeprecatedFlareAPI = true;
export const enableFundamentalAPI = false;
export const enableScopeAPI = true;
export const enableJSXTransformAPI = true;
export const warnAboutUnmockedScheduler = true;
export const flushSuspenseFallbacksInTests = true;
export const enableSuspenseCallback = true;
@@ -40,16 +38,11 @@ export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
export const enableTrainModelFix = true;
export const enableTrustedTypesIntegration = false;
export const enableNativeTargetAsInstance = false;
export const disableCreateFactory = __EXPERIMENTAL__;
export const disableLegacyReactDOMAPIs = __EXPERIMENTAL__;
export const disableTextareaChildren = __EXPERIMENTAL__;
export const disableMapsAsChildren = __EXPERIMENTAL__;
export const disableUnstableRenderSubtreeIntoContainer = __EXPERIMENTAL__;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = __EXPERIMENTAL__;
export const deferPassiveEffectCleanupDuringUnmount = false;
export const runAllPassiveEffectDestroysBeforeCreates = false;
export const isTestEnvironment = true;
export const enableModernEventSystem = false;
export const warnAboutSpreadingKeyToJSX = false;
@@ -45,8 +45,6 @@ export const warnAboutDefaultPropsOnFunctionComponents = false;
export const enableTrainModelFix = true;
export const exposeConcurrentModeAPIs = true;
export const enableSuspenseServerRenderer = true;
export const enableSelectiveHydration = true;
@@ -87,8 +85,6 @@ export const enableFundamentalAPI = false;
export const enableScopeAPI = true;
export const enableJSXTransformAPI = true;
export const warnAboutUnmockedScheduler = true;
export const enableSuspenseCallback = true;
@@ -97,22 +93,12 @@ export const flushSuspenseFallbacksInTests = true;
export const enableNativeTargetAsInstance = false;
export const disableCreateFactory = __EXPERIMENTAL__;
export const disableLegacyReactDOMAPIs = __EXPERIMENTAL__;
export const disableTextareaChildren = __EXPERIMENTAL__;
export const disableMapsAsChildren = __EXPERIMENTAL__;
export const disableUnstableRenderSubtreeIntoContainer = __EXPERIMENTAL__;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = __EXPERIMENTAL__;
export const isTestEnvironment = false;
export const enableModernEventSystem = false;
// Flow magic to verify the exports of this file match the original version.
+21
View File
@@ -2,7 +2,28 @@
const baseConfig = require('./config.base');
const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL;
// Default to building in experimental mode. If the release channel is set via
// an environment variable, then check if it's "experimental".
const __EXPERIMENTAL__ =
typeof RELEASE_CHANNEL === 'string'
? RELEASE_CHANNEL === 'experimental'
: true;
const preferredExtension = __EXPERIMENTAL__ ? '.js' : '.stable.js';
const moduleNameMapper = {};
moduleNameMapper[
'^react$'
] = `<rootDir>/packages/react/index${preferredExtension}`;
moduleNameMapper[
'^react-dom$'
] = `<rootDir>/packages/react-dom/index${preferredExtension}`;
module.exports = Object.assign({}, baseConfig, {
// Prefer the stable forks for tests.
moduleNameMapper,
modulePathIgnorePatterns: [
...baseConfig.modulePathIgnorePatterns,
'packages/react-devtools-shared',
+21
View File
@@ -2,7 +2,28 @@
const baseConfig = require('./config.base');
const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL;
// Default to building in experimental mode. If the release channel is set via
// an environment variable, then check if it's "experimental".
const __EXPERIMENTAL__ =
typeof RELEASE_CHANNEL === 'string'
? RELEASE_CHANNEL === 'experimental'
: true;
const preferredExtension = __EXPERIMENTAL__ ? '.js' : '.stable.js';
const moduleNameMapper = {};
moduleNameMapper[
'^react$'
] = `<rootDir>/packages/react/index${preferredExtension}`;
moduleNameMapper[
'^react-dom$'
] = `<rootDir>/packages/react-dom/index${preferredExtension}`;
module.exports = Object.assign({}, baseConfig, {
// Prefer the stable forks for tests.
moduleNameMapper,
modulePathIgnorePatterns: [
...baseConfig.modulePathIgnorePatterns,
'packages/react-devtools-shared',
+49 -19
View File
@@ -188,18 +188,16 @@ function getRollupOutputOptions(
) {
const isProduction = isProductionBundleType(bundleType);
return Object.assign(
{},
{
file: outputPath,
format,
globals,
freeze: !isProduction,
interop: false,
name: globalName,
sourcemap: false,
}
);
return {
file: outputPath,
format,
globals,
freeze: !isProduction,
interop: false,
name: globalName,
sourcemap: false,
esModule: false,
};
}
function getFormat(bundleType) {
@@ -479,6 +477,40 @@ function shouldSkipBundle(bundle, bundleType) {
return false;
}
function resolveEntryFork(resolvedEntry, isFBBundle) {
// Pick which entry point fork to use:
// .modern.fb.js
// .classic.fb.js
// .fb.js
// .stable.js
// .experimental.js
// .js
if (isFBBundle) {
const resolvedFBEntry = resolvedEntry.replace(
'.js',
__EXPERIMENTAL__ ? '.modern.fb.js' : '.classic.fb.js'
);
if (fs.existsSync(resolvedFBEntry)) {
return resolvedFBEntry;
}
const resolvedGenericFBEntry = resolvedEntry.replace('.js', '.fb.js');
if (fs.existsSync(resolvedGenericFBEntry)) {
return resolvedGenericFBEntry;
}
// Even if it's a FB bundle we fallthrough to pick stable or experimental if we don't have an FB fork.
}
const resolvedForkedEntry = resolvedEntry.replace(
'.js',
__EXPERIMENTAL__ ? '.experimental.js' : '.stable.js'
);
if (fs.existsSync(resolvedForkedEntry)) {
return resolvedForkedEntry;
}
// Just use the plain .js one.
return resolvedEntry;
}
async function createBundle(bundle, bundleType) {
if (shouldSkipBundle(bundle, bundleType)) {
return;
@@ -490,17 +522,15 @@ async function createBundle(bundle, bundleType) {
const format = getFormat(bundleType);
const packageName = Packaging.getPackageName(bundle.entry);
let resolvedEntry = require.resolve(bundle.entry);
const isFBBundle =
bundleType === FB_WWW_DEV ||
bundleType === FB_WWW_PROD ||
bundleType === FB_WWW_PROFILING;
if (isFBBundle) {
const resolvedFBEntry = resolvedEntry.replace('.js', '.fb.js');
if (fs.existsSync(resolvedFBEntry)) {
resolvedEntry = resolvedFBEntry;
}
}
let resolvedEntry = resolveEntryFork(
require.resolve(bundle.entry),
isFBBundle
);
const shouldBundleDependencies =
bundleType === UMD_DEV ||