Skip to content

Commit 46f7b0d

Browse files
authored
Fix dead code elimination for feature flags (#11453)
* Fix dead code elimination for feature flags Turning flags into named exports fixes dead code elimination. This required some restructuring of how we verify that flag types match up. I used the Check<> trick combined with import typeof, as suggested by @calebmer. For www, we can no longer re-export `require('ReactFeatureFlags')` directly, and instead destructure it. This means flags have to be known at init time. This is already the case so it's not a problem. In fact it may be better since it removes extra property access in tight paths. For things that we *want* to be dynamic on www (currently, only performance flag) we can export a function to toggle it, and then put it on the secret exports. In fact this is better than just letting everyone mutate the flag at arbitrary times since we can provide, e.g., a ref counting interface to it. * Record sizes
1 parent b6a7bee commit 46f7b0d

File tree

18 files changed

+189
-139
lines changed

18 files changed

+189
-139
lines changed

.flowconfig

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22

33
<PROJECT_ROOT>/fixtures/.*
44
<PROJECT_ROOT>/build/.*
5-
<PROJECT_ROOT>/scripts/.*
5+
<PROJECT_ROOT>/scripts/bench/.*
6+
7+
# These shims are copied into external projects:
8+
<PROJECT_ROOT>/scripts/rollup/shims/facebook-www/.*
9+
<PROJECT_ROOT>/scripts/rollup/shims/react-native/.*
10+
11+
# Note: intentionally *don't* ignore /scripts/rollup/shims/rollup/
12+
# because it is part of the build and isn't external.
13+
614
<PROJECT_ROOT>/.*/node_modules/y18n/.*
715
<PROJECT_ROOT>/node_modules/chrome-devtools-frontend/.*
816
<PROJECT_ROOT>/node_modules/devtools-timeline-model/.*

packages/react-cs-renderer/src/ReactNativeCSFeatureFlags.js

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,21 @@
77
* @flow
88
*/
99

10-
import type {FeatureFlags} from 'shared/ReactFeatureFlags';
10+
import typeof * as FeatureFlagsType from 'shared/ReactFeatureFlags';
11+
import typeof * as CSFeatureFlagsType from './ReactNativeCSFeatureFlags';
1112

12-
var ReactNativeCSFeatureFlags: FeatureFlags = {
13-
enableAsyncSubtreeAPI: true,
14-
enableAsyncSchedulingByDefaultInReactDOM: false,
15-
enableReactFragment: false,
16-
enableCreateRoot: false,
17-
// React Native CS uses persistent reconciler.
18-
enableMutatingReconciler: false,
19-
enableNoopReconciler: false,
20-
enablePersistentReconciler: true,
21-
};
13+
export const enableAsyncSubtreeAPI = true;
14+
export const enableAsyncSchedulingByDefaultInReactDOM = false;
15+
export const enableReactFragment = false;
16+
export const enableCreateRoot = false;
2217

23-
export default ReactNativeCSFeatureFlags;
18+
// React Native CS uses persistent reconciler.
19+
export const enableMutatingReconciler = false;
20+
export const enableNoopReconciler = false;
21+
export const enablePersistentReconciler = true;
22+
23+
// Flow magic to verify the exports of this file match the original version.
24+
// eslint-disable-next-line no-unused-vars
25+
type Check<_X, Y: _X, X: Y=_X> = null;
26+
// eslint-disable-next-line no-unused-expressions
27+
(null: Check<CSFeatureFlagsType, FeatureFlagsType>);

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ import * as EventPluginHub from 'events/EventPluginHub';
2323
import * as EventPluginRegistry from 'events/EventPluginRegistry';
2424
import * as EventPropagators from 'events/EventPropagators';
2525
import * as ReactInstanceMap from 'shared/ReactInstanceMap';
26-
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
26+
import {
27+
enableAsyncSchedulingByDefaultInReactDOM,
28+
enableCreateRoot,
29+
} from 'shared/ReactFeatureFlags';
2730
import ReactVersion from 'shared/ReactVersion';
2831
import * as ReactDOMFrameScheduling from 'shared/ReactDOMFrameScheduling';
2932
import {ReactCurrentOwner} from 'shared/ReactGlobalSharedState';
@@ -631,7 +634,7 @@ const DOMRenderer = ReactFiberReconciler({
631634

632635
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
633636

634-
useSyncScheduling: !ReactFeatureFlags.enableAsyncSchedulingByDefaultInReactDOM,
637+
useSyncScheduling: !enableAsyncSchedulingByDefaultInReactDOM,
635638
});
636639

637640
ReactGenericBatching.injection.injectFiberBatchedUpdates(
@@ -944,7 +947,7 @@ const ReactDOM: Object = {
944947
},
945948
};
946949

947-
if (ReactFeatureFlags.enableCreateRoot) {
950+
if (enableCreateRoot) {
948951
ReactDOM.createRoot = function createRoot(
949952
container: DOMContainer,
950953
options?: RootOptions,

packages/react-noop-renderer/src/ReactNoop.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import type {UpdateQueue} from 'react-reconciler/src/ReactFiberUpdateQueue';
2121
import ReactFiberInstrumentation
2222
from 'react-reconciler/src/ReactFiberInstrumentation';
2323
import ReactFiberReconciler from 'react-reconciler';
24-
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
24+
import {enablePersistentReconciler} from 'shared/ReactFeatureFlags';
2525
import * as ReactInstanceMap from 'shared/ReactInstanceMap';
2626
import emptyObject from 'fbjs/lib/emptyObject';
2727
import expect from 'expect';
@@ -213,7 +213,7 @@ var NoopRenderer = ReactFiberReconciler({
213213
},
214214
});
215215

216-
var PersistentNoopRenderer = ReactFeatureFlags.enablePersistentReconciler
216+
var PersistentNoopRenderer = enablePersistentReconciler
217217
? ReactFiberReconciler({
218218
...SharedHostConfig,
219219
persistence: {

packages/react-reconciler/src/ReactChildFiber.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type {
1414
ExpirationTime,
1515
} from 'react-reconciler/src/ReactFiberExpirationTime';
1616

17-
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
17+
import {enableReactFragment} from 'shared/ReactFeatureFlags';
1818
import {NoEffect, Placement, Deletion} from 'shared/ReactTypeOfSideEffect';
1919
import {
2020
FunctionalComponent,
@@ -1426,7 +1426,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
14261426
// This leads to an ambiguity between <>{[...]}</> and <>...</>.
14271427
// We treat the ambiguous cases above the same.
14281428
if (
1429-
ReactFeatureFlags.enableReactFragment &&
1429+
enableReactFragment &&
14301430
typeof newChild === 'object' &&
14311431
newChild !== null &&
14321432
newChild.type === REACT_FRAGMENT_TYPE &&

packages/react-reconciler/src/ReactFiberClassComponent.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {Fiber} from './ReactFiber';
1111
import type {ExpirationTime} from './ReactFiberExpirationTime';
1212

1313
import {Update} from 'shared/ReactTypeOfSideEffect';
14-
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
14+
import {enableAsyncSubtreeAPI} from 'shared/ReactFeatureFlags';
1515
import {isMounted} from 'shared/ReactFiberTreeReflection';
1616
import * as ReactInstanceMap from 'shared/ReactInstanceMap';
1717
import emptyObject from 'fbjs/lib/emptyObject';
@@ -450,7 +450,7 @@ export default function(
450450
instance.context = getMaskedContext(workInProgress, unmaskedContext);
451451

452452
if (
453-
ReactFeatureFlags.enableAsyncSubtreeAPI &&
453+
enableAsyncSubtreeAPI &&
454454
workInProgress.type != null &&
455455
workInProgress.type.prototype != null &&
456456
workInProgress.type.prototype.unstable_isAsyncReactComponent === true

packages/react-reconciler/src/ReactFiberCommitWork.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
import type {HostConfig} from 'react-reconciler';
1111
import type {Fiber} from './ReactFiber';
1212

13-
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
13+
import {
14+
enableMutatingReconciler,
15+
enableNoopReconciler,
16+
enablePersistentReconciler,
17+
} from 'shared/ReactFeatureFlags';
1418
import {
1519
ClassComponent,
1620
HostRoot,
@@ -218,12 +222,9 @@ export default function<T, P, I, TI, PI, C, CC, CX, PL>(
218222
// TODO: this is recursive.
219223
// We are also not using this parent because
220224
// the portal will get pushed immediately.
221-
if (ReactFeatureFlags.enableMutatingReconciler && mutation) {
225+
if (enableMutatingReconciler && mutation) {
222226
unmountHostComponents(current);
223-
} else if (
224-
ReactFeatureFlags.enablePersistentReconciler &&
225-
persistence
226-
) {
227+
} else if (enablePersistentReconciler && persistence) {
227228
emptyPortalContainer(current);
228229
}
229230
return;
@@ -324,10 +325,7 @@ export default function<T, P, I, TI, PI, C, CC, CX, PL>(
324325
// Noop
325326
};
326327
}
327-
if (
328-
ReactFeatureFlags.enablePersistentReconciler ||
329-
ReactFeatureFlags.enableNoopReconciler
330-
) {
328+
if (enablePersistentReconciler || enableNoopReconciler) {
331329
return {
332330
commitResetTextContent(finishedWork: Fiber) {},
333331
commitPlacement(finishedWork: Fiber) {},
@@ -660,7 +658,7 @@ export default function<T, P, I, TI, PI, C, CC, CX, PL>(
660658
resetTextContent(current.stateNode);
661659
}
662660

663-
if (ReactFeatureFlags.enableMutatingReconciler) {
661+
if (enableMutatingReconciler) {
664662
return {
665663
commitResetTextContent,
666664
commitPlacement,

packages/react-reconciler/src/ReactFiberCompleteWork.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ import type {HostContext} from './ReactFiberHostContext';
1515
import type {HydrationContext} from './ReactFiberHydrationContext';
1616
import type {FiberRoot} from './ReactFiberRoot';
1717

18-
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
18+
import {
19+
enableMutatingReconciler,
20+
enablePersistentReconciler,
21+
enableNoopReconciler,
22+
} from 'shared/ReactFeatureFlags';
1923
import {
2024
IndeterminateComponent,
2125
FunctionalComponent,
@@ -180,7 +184,7 @@ export default function<T, P, I, TI, PI, C, CC, CX, PL>(
180184
let updateHostComponent;
181185
let updateHostText;
182186
if (mutation) {
183-
if (ReactFeatureFlags.enableMutatingReconciler) {
187+
if (enableMutatingReconciler) {
184188
// Mutation mode
185189
updateHostContainer = function(workInProgress: Fiber) {
186190
// Noop
@@ -217,7 +221,7 @@ export default function<T, P, I, TI, PI, C, CC, CX, PL>(
217221
invariant(false, 'Mutating reconciler is disabled.');
218222
}
219223
} else if (persistence) {
220-
if (ReactFeatureFlags.enablePersistentReconciler) {
224+
if (enablePersistentReconciler) {
221225
// Persistent host tree mode
222226
const {
223227
cloneInstance,
@@ -354,7 +358,7 @@ export default function<T, P, I, TI, PI, C, CC, CX, PL>(
354358
invariant(false, 'Persistent reconciler is disabled.');
355359
}
356360
} else {
357-
if (ReactFeatureFlags.enableNoopReconciler) {
361+
if (enableNoopReconciler) {
358362
// No host operations
359363
updateHostContainer = function(workInProgress: Fiber) {
360364
// Noop

packages/react-reconciler/src/ReactFiberReconciler.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {Fiber} from './ReactFiber';
1111
import type {FiberRoot} from './ReactFiberRoot';
1212
import type {ReactNodeList} from 'shared/ReactTypes';
1313

14-
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
14+
import {enableAsyncSubtreeAPI} from 'shared/ReactFeatureFlags';
1515
import {
1616
findCurrentHostFiber,
1717
findCurrentHostFiberWithNoPortals,
@@ -322,7 +322,7 @@ export default function<T, P, I, TI, PI, C, CC, CX, PL>(
322322
// treat updates to the root as async. This is a bit weird but lets us
323323
// avoid a separate `renderAsync` API.
324324
if (
325-
ReactFeatureFlags.enableAsyncSubtreeAPI &&
325+
enableAsyncSubtreeAPI &&
326326
element != null &&
327327
element.type != null &&
328328
element.type.prototype != null &&

packages/react/src/React.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import assign from 'object-assign';
99
import ReactVersion from 'shared/ReactVersion';
10-
import ReactFeatureFlags from 'shared/ReactFeatureFlags';
10+
import {enableReactFragment} from 'shared/ReactFeatureFlags';
1111

1212
import {Component, PureComponent, AsyncComponent} from './ReactBaseClasses';
1313
import {forEach, map, count, toArray, only} from './ReactChildren';
@@ -58,7 +58,7 @@ var React = {
5858
},
5959
};
6060

61-
if (ReactFeatureFlags.enableReactFragment) {
61+
if (enableReactFragment) {
6262
React.Fragment = REACT_FRAGMENT_TYPE;
6363
}
6464

0 commit comments

Comments
 (0)