Skip to content

Commit b1a56ab

Browse files
committed
Fork ReactFiberScheduler with feature flag
Adds a feature flag `enableNewScheduler` that toggles between two implementations of ReactFiberScheduler. This will let us land changes in master while preserving the ability to quickly rollback. Ideally this will be a short-lived fork. Once we've tested the new scheduler for a week or so without issues, we will get rid of it. Until then, we'll need to maintain two parallel implementations and run tests against both of them. We rarely land changes to ReactFiberScheduler, so I don't expect this will be a huge burden. This commit does not implement anything new. The flag is still off and tests run against the existing implementation. Use `yarn test-new-scheduler` to run tests against the new one.
1 parent 45f5717 commit b1a56ab

19 files changed

+202
-9
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"test": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source.js",
103103
"test-persistent": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-persistent.js",
104104
"test-fire": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-fire.js",
105+
"test-new-scheduler": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source-new-scheduler.js",
105106
"test-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source.js",
106107
"test-fire-prod": "cross-env NODE_ENV=production jest --config ./scripts/jest/config.source-fire.js",
107108
"test-prod-build": "yarn test-build-prod",

packages/react-reconciler/src/ReactFiberBeginWork.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ import {
144144
createWorkInProgress,
145145
isSimpleFunctionComponent,
146146
} from './ReactFiber';
147-
import {requestCurrentTime, retryTimedOutBoundary} from './ReactFiberScheduler.old';
147+
import {requestCurrentTime, retryTimedOutBoundary} from './ReactFiberScheduler';
148148

149149
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
150150

packages/react-reconciler/src/ReactFiberClassComponent.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import {
5353
computeExpirationForFiber,
5454
scheduleWork,
5555
flushPassiveEffects,
56-
} from './ReactFiberScheduler.old';
56+
} from './ReactFiberScheduler';
5757

5858
const fakeInternalInstance = {};
5959
const isArray = Array.isArray;

packages/react-reconciler/src/ReactFiberCommitWork.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import type {ExpirationTime} from './ReactFiberExpirationTime';
2121
import type {CapturedValue, CapturedError} from './ReactCapturedValue';
2222
import type {SuspenseState} from './ReactFiberSuspenseComponent';
2323
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';
24-
import type {Thenable} from './ReactFiberScheduler.old';
24+
import type {Thenable} from './ReactFiberScheduler';
2525

2626
import {unstable_wrap as Schedule_tracing_wrap} from 'scheduler/tracing';
2727
import {
@@ -95,7 +95,7 @@ import {
9595
captureCommitPhaseError,
9696
requestCurrentTime,
9797
resolveRetryThenable,
98-
} from './ReactFiberScheduler.old';
98+
} from './ReactFiberScheduler';
9999
import {
100100
NoEffect as NoHookEffect,
101101
UnmountSnapshot,

packages/react-reconciler/src/ReactFiberHooks.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
computeExpirationForFiber,
3535
flushPassiveEffects,
3636
requestCurrentTime,
37-
} from './ReactFiberScheduler.old';
37+
} from './ReactFiberScheduler';
3838

3939
import invariant from 'shared/invariant';
4040
import warning from 'shared/warning';

packages/react-reconciler/src/ReactFiberReconciler.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import {
5454
interactiveUpdates,
5555
flushInteractiveUpdates,
5656
flushPassiveEffects,
57-
} from './ReactFiberScheduler.old';
57+
} from './ReactFiberScheduler';
5858
import {createUpdate, enqueueUpdate} from './ReactUpdateQueue';
5959
import ReactFiberInstrumentation from './ReactFiberInstrumentation';
6060
import {

packages/react-reconciler/src/ReactFiberRoot.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import type {Fiber} from './ReactFiber';
1111
import type {ExpirationTime} from './ReactFiberExpirationTime';
1212
import type {TimeoutHandle, NoTimeout} from './ReactFiberHostConfig';
13-
import type {Thenable} from './ReactFiberScheduler.old';
13+
import type {Thenable} from './ReactFiberScheduler';
1414
import type {Interaction} from 'scheduler/src/Tracing';
1515

1616
import {noTimeout} from './ReactFiberHostConfig';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its 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 {enableNewScheduler} from 'shared/ReactFeatureFlags';
11+
12+
import {
13+
requestCurrentTime as requestCurrentTime_old,
14+
computeExpirationForFiber as computeExpirationForFiber_old,
15+
captureCommitPhaseError as captureCommitPhaseError_old,
16+
onUncaughtError as onUncaughtError_old,
17+
renderDidSuspend as renderDidSuspend_old,
18+
renderDidError as renderDidError_old,
19+
pingSuspendedRoot as pingSuspendedRoot_old,
20+
retryTimedOutBoundary as retryTimedOutBoundary_old,
21+
resolveRetryThenable as resolveRetryThenable_old,
22+
markLegacyErrorBoundaryAsFailed as markLegacyErrorBoundaryAsFailed_old,
23+
isAlreadyFailedLegacyErrorBoundary as isAlreadyFailedLegacyErrorBoundary_old,
24+
scheduleWork as scheduleWork_old,
25+
requestWork as requestWork_old,
26+
flushRoot as flushRoot_old,
27+
batchedUpdates as batchedUpdates_old,
28+
unbatchedUpdates as unbatchedUpdates_old,
29+
flushSync as flushSync_old,
30+
flushControlled as flushControlled_old,
31+
deferredUpdates as deferredUpdates_old,
32+
syncUpdates as syncUpdates_old,
33+
interactiveUpdates as interactiveUpdates_old,
34+
flushInteractiveUpdates as flushInteractiveUpdates_old,
35+
computeUniqueAsyncExpiration as computeUniqueAsyncExpiration_old,
36+
flushPassiveEffects as flushPassiveEffects_old,
37+
warnIfNotCurrentlyBatchingInDev as warnIfNotCurrentlyBatchingInDev_old,
38+
} from './ReactFiberScheduler.old';
39+
40+
import {
41+
requestCurrentTime as requestCurrentTime_new,
42+
computeExpirationForFiber as computeExpirationForFiber_new,
43+
captureCommitPhaseError as captureCommitPhaseError_new,
44+
onUncaughtError as onUncaughtError_new,
45+
renderDidSuspend as renderDidSuspend_new,
46+
renderDidError as renderDidError_new,
47+
pingSuspendedRoot as pingSuspendedRoot_new,
48+
retryTimedOutBoundary as retryTimedOutBoundary_new,
49+
resolveRetryThenable as resolveRetryThenable_new,
50+
markLegacyErrorBoundaryAsFailed as markLegacyErrorBoundaryAsFailed_new,
51+
isAlreadyFailedLegacyErrorBoundary as isAlreadyFailedLegacyErrorBoundary_new,
52+
scheduleWork as scheduleWork_new,
53+
requestWork as requestWork_new,
54+
flushRoot as flushRoot_new,
55+
batchedUpdates as batchedUpdates_new,
56+
unbatchedUpdates as unbatchedUpdates_new,
57+
flushSync as flushSync_new,
58+
flushControlled as flushControlled_new,
59+
deferredUpdates as deferredUpdates_new,
60+
syncUpdates as syncUpdates_new,
61+
interactiveUpdates as interactiveUpdates_new,
62+
flushInteractiveUpdates as flushInteractiveUpdates_new,
63+
computeUniqueAsyncExpiration as computeUniqueAsyncExpiration_new,
64+
flushPassiveEffects as flushPassiveEffects_new,
65+
warnIfNotCurrentlyBatchingInDev as warnIfNotCurrentlyBatchingInDev_new,
66+
} from './ReactFiberScheduler.new';
67+
68+
export let requestCurrentTime = requestCurrentTime_old;
69+
export let computeExpirationForFiber = computeExpirationForFiber_old;
70+
export let captureCommitPhaseError = captureCommitPhaseError_old;
71+
export let onUncaughtError = onUncaughtError_old;
72+
export let renderDidSuspend = renderDidSuspend_old;
73+
export let renderDidError = renderDidError_old;
74+
export let pingSuspendedRoot = pingSuspendedRoot_old;
75+
export let retryTimedOutBoundary = retryTimedOutBoundary_old;
76+
export let resolveRetryThenable = resolveRetryThenable_old;
77+
export let markLegacyErrorBoundaryAsFailed = markLegacyErrorBoundaryAsFailed_old;
78+
export let isAlreadyFailedLegacyErrorBoundary = isAlreadyFailedLegacyErrorBoundary_old;
79+
export let scheduleWork = scheduleWork_old;
80+
export let requestWork = requestWork_old;
81+
export let flushRoot = flushRoot_old;
82+
export let batchedUpdates = batchedUpdates_old;
83+
export let unbatchedUpdates = unbatchedUpdates_old;
84+
export let flushSync = flushSync_old;
85+
export let flushControlled = flushControlled_old;
86+
export let deferredUpdates = deferredUpdates_old;
87+
export let syncUpdates = syncUpdates_old;
88+
export let interactiveUpdates = interactiveUpdates_old;
89+
export let flushInteractiveUpdates = flushInteractiveUpdates_old;
90+
export let computeUniqueAsyncExpiration = computeUniqueAsyncExpiration_old;
91+
export let flushPassiveEffects = flushPassiveEffects_old;
92+
export let warnIfNotCurrentlyBatchingInDev = warnIfNotCurrentlyBatchingInDev_old;
93+
94+
if (enableNewScheduler) {
95+
requestCurrentTime = requestCurrentTime_new;
96+
computeExpirationForFiber = computeExpirationForFiber_new;
97+
captureCommitPhaseError = captureCommitPhaseError_new;
98+
onUncaughtError = onUncaughtError_new;
99+
renderDidSuspend = renderDidSuspend_new;
100+
renderDidError = renderDidError_new;
101+
pingSuspendedRoot = pingSuspendedRoot_new;
102+
retryTimedOutBoundary = retryTimedOutBoundary_new;
103+
resolveRetryThenable = resolveRetryThenable_new;
104+
markLegacyErrorBoundaryAsFailed = markLegacyErrorBoundaryAsFailed_new;
105+
isAlreadyFailedLegacyErrorBoundary = isAlreadyFailedLegacyErrorBoundary_new;
106+
scheduleWork = scheduleWork_new;
107+
requestWork = requestWork_new;
108+
flushRoot = flushRoot_new;
109+
batchedUpdates = batchedUpdates_new;
110+
unbatchedUpdates = unbatchedUpdates_new;
111+
flushSync = flushSync_new;
112+
flushControlled = flushControlled_new;
113+
deferredUpdates = deferredUpdates_new;
114+
syncUpdates = syncUpdates_new;
115+
interactiveUpdates = interactiveUpdates_new;
116+
flushInteractiveUpdates = flushInteractiveUpdates_new;
117+
computeUniqueAsyncExpiration = computeUniqueAsyncExpiration_new;
118+
flushPassiveEffects = flushPassiveEffects_new;
119+
warnIfNotCurrentlyBatchingInDev = warnIfNotCurrentlyBatchingInDev_new;
120+
}
121+
122+
export type Thenable = {
123+
then(resolve: () => mixed, reject?: () => mixed): mixed,
124+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its 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+
8+
function notYetImplemented() {
9+
throw new Error('Not yet implemented.');
10+
}
11+
12+
export const requestCurrentTime = notYetImplemented;
13+
export const computeExpirationForFiber = notYetImplemented;
14+
export const captureCommitPhaseError = notYetImplemented;
15+
export const onUncaughtError = notYetImplemented;
16+
export const renderDidSuspend = notYetImplemented;
17+
export const renderDidError = notYetImplemented;
18+
export const pingSuspendedRoot = notYetImplemented;
19+
export const retryTimedOutBoundary = notYetImplemented;
20+
export const resolveRetryThenable = notYetImplemented;
21+
export const markLegacyErrorBoundaryAsFailed = notYetImplemented;
22+
export const isAlreadyFailedLegacyErrorBoundary = notYetImplemented;
23+
export const scheduleWork = notYetImplemented;
24+
export const requestWork = notYetImplemented;
25+
export const flushRoot = notYetImplemented;
26+
export const batchedUpdates = notYetImplemented;
27+
export const unbatchedUpdates = notYetImplemented;
28+
export const flushSync = notYetImplemented;
29+
export const flushControlled = notYetImplemented;
30+
export const deferredUpdates = notYetImplemented;
31+
export const syncUpdates = notYetImplemented;
32+
export const interactiveUpdates = notYetImplemented;
33+
export const flushInteractiveUpdates = notYetImplemented;
34+
export const computeUniqueAsyncExpiration = notYetImplemented;
35+
export const flushPassiveEffects = notYetImplemented;
36+
export const warnIfNotCurrentlyBatchingInDev = notYetImplemented;

packages/react-reconciler/src/ReactFiberUnwindWork.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type {FiberRoot} from './ReactFiberRoot';
1212
import type {ExpirationTime} from './ReactFiberExpirationTime';
1313
import type {CapturedValue} from './ReactCapturedValue';
1414
import type {Update} from './ReactUpdateQueue';
15-
import type {Thenable} from './ReactFiberScheduler.old';
15+
import type {Thenable} from './ReactFiberScheduler';
1616
import type {SuspenseState} from './ReactFiberSuspenseComponent';
1717

1818
import {unstable_wrap as Schedule_tracing_wrap} from 'scheduler/tracing';
@@ -67,7 +67,7 @@ import {
6767
isAlreadyFailedLegacyErrorBoundary,
6868
pingSuspendedRoot,
6969
resolveRetryThenable,
70-
} from './ReactFiberScheduler.old';
70+
} from './ReactFiberScheduler';
7171

7272
import invariant from 'shared/invariant';
7373
import maxSigned31BitInt from './maxSigned31BitInt';

packages/shared/ReactFeatureFlags.js

+4
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,7 @@ export const warnAboutDeprecatedSetNativeProps = false;
6464

6565
// Experimental React Events support. Only used in www builds for now.
6666
export const enableEventAPI = false;
67+
68+
// Enables rewritten version of ReactFiberScheduler. Added in case we need to
69+
// quickly revert it.
70+
export const enableNewScheduler = false;

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

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
3131
export const warnAboutDeprecatedLifecycles = true;
3232
export const warnAboutDeprecatedSetNativeProps = true;
3333
export const enableEventAPI = false;
34+
export const enableNewScheduler = false;
3435

3536
// Only used in www builds.
3637
export function addUserTimingListener() {

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

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const warnAboutShorthandPropertyCollision = false;
2828
export const enableSchedulerDebugging = false;
2929
export const warnAboutDeprecatedSetNativeProps = false;
3030
export const enableEventAPI = false;
31+
export const enableNewScheduler = false;
3132

3233
// Only used in www builds.
3334
export function addUserTimingListener() {

packages/shared/forks/ReactFeatureFlags.persistent.js

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const warnAboutShorthandPropertyCollision = false;
2828
export const enableSchedulerDebugging = false;
2929
export const warnAboutDeprecatedSetNativeProps = false;
3030
export const enableEventAPI = false;
31+
export const enableNewScheduler = false;
3132

3233
// Only used in www builds.
3334
export function addUserTimingListener() {

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

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const warnAboutShorthandPropertyCollision = false;
2828
export const enableSchedulerDebugging = false;
2929
export const warnAboutDeprecatedSetNativeProps = false;
3030
export const enableEventAPI = false;
31+
export const enableNewScheduler = false;
3132

3233
// Only used in www builds.
3334
export function addUserTimingListener() {

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

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export const warnAboutDeprecatedSetNativeProps = false;
2626
export const disableJavaScriptURLs = false;
2727
export const disableYielding = false;
2828
export const enableEventAPI = true;
29+
export const enableNewScheduler = false;
2930

3031
// Only used in www builds.
3132
export function addUserTimingListener() {

packages/shared/forks/ReactFeatureFlags.www.js

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ export const enableStableConcurrentModeAPIs = false;
3939

4040
export const enableSuspenseServerRenderer = true;
4141

42+
// I've chosen to make this a static flag instead of a dynamic flag controlled
43+
// by a GK so that it doesn't increase bundle size. It should still be easy
44+
// to rollback by reverting the commit that turns this on.
45+
export const enableNewScheduler = false;
46+
4247
let refCount = 0;
4348
export function addUserTimingListener() {
4449
if (__DEV__) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use strict';
2+
3+
const baseConfig = require('./config.base');
4+
5+
module.exports = Object.assign({}, baseConfig, {
6+
setupFiles: [
7+
...baseConfig.setupFiles,
8+
require.resolve('./setupNewScheduler.js'),
9+
require.resolve('./setupHostConfigs.js'),
10+
],
11+
});

scripts/jest/setupNewScheduler.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
3+
jest.mock('shared/ReactFeatureFlags', () => {
4+
const ReactFeatureFlags = require.requireActual('shared/ReactFeatureFlags');
5+
ReactFeatureFlags.enableNewScheduler = true;
6+
return ReactFeatureFlags;
7+
});

0 commit comments

Comments
 (0)