Don't use EventListener Fork in Modern WWW Builds (#18333)
* Move unsubscribe fork to EventListener That way we can statically compile out more of these indirections. * Don't use the EventListener fork for Modern WWW builds
Sebastian Markbåge committed
Mar 18, 2020 at 06:13 UTC
94505b961332d9295c3f6da33d51219d126bf04f
4 files changed
+60
-44
packages/react-dom/src/events/EventListener.js
+17
-4
@@ -11,16 +11,18 @@ export function addEventBubbleListener(
11
target: EventTarget,
12
eventType: string,
13
listener: Function,
14
-): void {
14
+): Function {
15
target.addEventListener(eventType, listener, false);
16
+ return listener;
17
}
18
19
export function addEventCaptureListener(
20
target: EventTarget,
21
eventType: string,
22
listener: Function,
22
-): void {
23
+): Function {
24
target.addEventListener(eventType, listener, true);
25
+ return listener;
26
}
27
28
export function addEventCaptureListenerWithPassiveFlag(
@@ -28,11 +30,12 @@ export function addEventCaptureListenerWithPassiveFlag(
30
eventType: string,
31
listener: Function,
32
passive: boolean,
31
-): void {
33
+): Function {
34
target.addEventListener(eventType, listener, {
35
capture: true,
36
passive,
37
});
38
+ return listener;
39
}
40
41
export function addEventBubbleListenerWithPassiveFlag(
@@ -40,8 +43,18 @@ export function addEventBubbleListenerWithPassiveFlag(
43
eventType: string,
44
listener: Function,
45
passive: boolean,
43
-): void {
46
+): Function {
47
target.addEventListener(eventType, listener, {
48
passive,
49
});
50
+ return listener;
51
+}
52
+
53
+export function removeEventListener(
54
+ target: EventTarget,
55
+ eventType: string,
56
+ listener: Function,
57
+ capture: boolean,
58
+): void {
59
+ target.removeEventListener(eventType, listener, capture);
60
}
packages/react-dom/src/events/ReactDOMEventListener.js
+18
-38
@@ -49,6 +49,7 @@ import {
49
addEventCaptureListener,
50
addEventCaptureListenerWithPassiveFlag,
51
addEventBubbleListenerWithPassiveFlag,
52
+ removeEventListener,
53
} from './EventListener';
54
import getEventTarget from './getEventTarget';
55
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
@@ -108,7 +109,6 @@ export function addResponderEventSystemEvent(
109
} else {
110
eventFlags |= IS_ACTIVE;
111
}
111
- let fbListener;
112
// Check if interactive and wrap in discreteUpdates
113
const listener = dispatchEvent.bind(
114
null,
@@ -117,19 +117,15 @@ export function addResponderEventSystemEvent(
117
document,
118
);
119
if (passiveBrowserEventsSupported) {
120
- fbListener = addEventCaptureListenerWithPassiveFlag(
120
+ return addEventCaptureListenerWithPassiveFlag(
121
document,
122
topLevelType,
123
listener,
124
passive,
125
);
126
} else {
127
- fbListener = addEventCaptureListener(document, topLevelType, listener);
127
+ return addEventCaptureListener(document, topLevelType, listener);
128
}
129
- // If we have an fbListener, then use that.
130
- // We'll only have one if we use the forked
131
- // EventListener-www module in FB builds.
132
- return fbListener || listener;
129
}
130
131
export function addTrappedEventListener(
@@ -184,8 +180,8 @@ export function addTrappedEventListener(
180
const validTargetContainer = ((targetContainer: any): EventTarget);
181
182
const rawEventName = getRawEventName(topLevelType);
187
- let fbListener;
183
184
+ let unsubscribeListener;
185
// When legacyFBSupport is enabled, it's for when we
186
// want to add a one time event listener to a container.
187
// This should only be used with enableLegacyFBPrimerSupport
@@ -203,28 +199,26 @@ export function addTrappedEventListener(
199
try {
200
return originalListener.apply(this, p);
201
} finally {
206
- if (fbListener) {
207
- fbListener.remove();
208
- } else {
209
- validTargetContainer.removeEventListener(
210
- ((rawEventName: any): string),
211
- (listener: any),
212
- );
213
- }
202
+ removeEventListener(
203
+ validTargetContainer,
204
+ rawEventName,
205
+ unsubscribeListener,
206
+ capture,
207
+ );
208
}
209
};
210
}
211
if (capture) {
212
if (enableUseEventAPI && passive !== undefined) {
213
// This is only used with passive is either true or false.
220
- fbListener = addEventCaptureListenerWithPassiveFlag(
214
+ unsubscribeListener = addEventCaptureListenerWithPassiveFlag(
215
validTargetContainer,
216
rawEventName,
217
listener,
218
passive,
219
);
220
} else {
227
- fbListener = addEventCaptureListener(
221
+ unsubscribeListener = addEventCaptureListener(
222
validTargetContainer,
223
rawEventName,
224
listener,
@@ -233,24 +227,21 @@ export function addTrappedEventListener(
227
} else {
228
if (enableUseEventAPI && passive !== undefined) {
229
// This is only used with passive is either true or false.
236
- fbListener = addEventBubbleListenerWithPassiveFlag(
230
+ unsubscribeListener = addEventBubbleListenerWithPassiveFlag(
231
validTargetContainer,
232
rawEventName,
233
listener,
234
passive,
235
);
236
} else {
243
- fbListener = addEventBubbleListener(
237
+ unsubscribeListener = addEventBubbleListener(
238
validTargetContainer,
239
rawEventName,
240
listener,
241
);
242
}
243
}
250
- // If we have an fbListener, then use that.
251
- // We'll only have one if we use the forked
252
- // EventListener-www module in FB builds.
253
- return fbListener || listener;
244
+ return unsubscribeListener;
245
}
246
247
export function removeTrappedEventListener(
@@ -259,20 +250,9 @@ export function removeTrappedEventListener(
250
capture: boolean,
251
listener: any => void,
252
passive: void | boolean,
262
-) {
263
- if (listener.remove != null) {
264
- listener.remove();
265
- } else {
266
- const rawEventName = getRawEventName(topLevelType);
267
- if (passiveBrowserEventsSupported) {
268
- targetContainer.removeEventListener(rawEventName, listener, {
269
- capture,
270
- passive,
271
- });
272
- } else {
273
- targetContainer.removeEventListener(rawEventName, listener, capture);
274
- }
275
- }
253
+): void {
254
+ const rawEventName = getRawEventName(topLevelType);
255
+ removeEventListener(targetContainer, rawEventName, listener, capture);
256
}
257
258
function dispatchDiscreteEvent(
packages/react-dom/src/events/forks/EventListener-www.js
+9
@@ -56,6 +56,15 @@ export function addEventBubbleListenerWithPassiveFlag(
56
);
57
}
58
59
+export function removeEventListener(
60
+ target: EventTarget,
61
+ eventType: string,
62
+ listener: Function,
63
+ capture: boolean,
64
+) {
65
+ listener.remove();
66
+}
67
+
68
// Flow magic to verify the exports of this file match the original version.
69
// eslint-disable-next-line no-unused-vars
70
type Check<_X, Y: _X, X: Y = _X> = null;
scripts/rollup/forks.js
+16
-2
@@ -19,6 +19,15 @@ const {
19
} = bundleTypes;
20
const {RENDERER, RECONCILER} = moduleTypes;
21
22
+const RELEASE_CHANNEL = process.env.RELEASE_CHANNEL;
23
+
24
+// Default to building in experimental mode. If the release channel is set via
25
+// an environment variable, then check if it's "experimental".
26
+const __EXPERIMENTAL__ =
27
+ typeof RELEASE_CHANNEL === 'string'
28
+ ? RELEASE_CHANNEL === 'experimental'
29
+ : true;
30
+
31
// If you need to replace a file with another file for a specific environment,
32
// add it to this list with the logic for choosing the right replacement.
33
const forks = Object.freeze({
@@ -442,8 +451,13 @@ const forks = Object.freeze({
451
case FB_WWW_DEV:
452
case FB_WWW_PROD:
453
case FB_WWW_PROFILING:
445
- // Use the www fork which is integrated with TimeSlice profiling.
446
- return 'react-dom/src/events/forks/EventListener-www.js';
454
+ if (__EXPERIMENTAL__) {
455
+ // In modern builds we don't use the indirection. We just use raw DOM.
456
+ return null;
457
+ } else {
458
+ // Use the www fork which is integrated with TimeSlice profiling.
459
+ return 'react-dom/src/events/forks/EventListener-www.js';
460
+ }
461
default:
462
return null;
463
}