Skip to content

Commit c28283f

Browse files
author
Brian Vaughn
committed
Inlined DevTools event emitter
DevTools previously used the NPM events package for dispatching events. This package has an unfortunate flaw though- if a listener throws during event dispatch, no subsequent listeners are called. I've replaced that event dispatcher with my own implementation that ensures all listeners are called before it re-throws an error. This commit replaces that event emitter with a custom implementation that calls all listeners before re-throwing an error.
1 parent a600408 commit c28283f

File tree

7 files changed

+72
-21
lines changed

7 files changed

+72
-21
lines changed

packages/react-devtools-shared/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
"@reach/menu-button": "^0.1.17",
1212
"@reach/tooltip": "^0.2.2",
1313
"clipboard-js": "^0.3.6",
14-
"events": "^3.0.0",
1514
"local-storage-fallback": "^4.1.1",
1615
"lodash.throttle": "^4.1.1",
1716
"memoize-one": "^3.1.1",

packages/react-devtools-shared/src/backend/agent.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow
88
*/
99

10-
import EventEmitter from 'events';
10+
import EventEmitter from '../events';
1111
import throttle from 'lodash.throttle';
1212
import {
1313
SESSION_STORAGE_LAST_SELECTION_KEY,

packages/react-devtools-shared/src/bridge.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow
88
*/
99

10-
import EventEmitter from 'events';
10+
import EventEmitter from './events';
1111

1212
import type {ComponentFilter, Wall} from './types';
1313
import type {

packages/react-devtools-shared/src/devtools/ProfilerStore.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow
88
*/
99

10-
import EventEmitter from 'events';
10+
import EventEmitter from '../events';
1111
import {prepareProfilingDataFrontendFromBackendAndStore} from './views/Profiler/utils';
1212
import ProfilingCache from './ProfilingCache';
1313
import Store from './store';

packages/react-devtools-shared/src/devtools/store.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow
88
*/
99

10-
import EventEmitter from 'events';
10+
import EventEmitter from '../events';
1111
import {inspect} from 'util';
1212
import {
1313
TREE_OPERATION_ADD,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
export default class EventEmitter<Events: Object> {
11+
listenersMap: Map<string, Set<Function>> = new Map();
12+
13+
addListener<Event: $Keys<Events>>(
14+
event: Event,
15+
listener: (...$ElementType<Events, Event>) => any,
16+
): void {
17+
let listeners = this.listenersMap.get(event);
18+
if (listeners === undefined) {
19+
listeners = new Set();
20+
21+
this.listenersMap.set(event, listeners);
22+
}
23+
24+
listeners.add(listener);
25+
}
26+
27+
emit<Event: $Keys<Events>>(
28+
event: Event,
29+
...args: $ElementType<Events, Event>
30+
): void {
31+
const listeners = this.listenersMap.get(event);
32+
if (listeners !== undefined) {
33+
let didThrow = false;
34+
let caughtError = null;
35+
36+
listeners.forEach(listener => {
37+
try {
38+
listener.apply(null, args);
39+
} catch (error) {
40+
if (caughtError === null) {
41+
didThrow = true;
42+
caughtError = error;
43+
}
44+
}
45+
});
46+
47+
if (didThrow) {
48+
throw caughtError;
49+
}
50+
}
51+
}
52+
53+
removeAllListeners(event?: $Keys<Events>): void {
54+
if (event != null) {
55+
this.listenersMap.delete(event);
56+
} else {
57+
this.listenersMap.clear();
58+
}
59+
}
60+
61+
removeListener(event: $Keys<Events>, listener: Function): void {
62+
const listeners = this.listenersMap.get(event);
63+
if (listeners !== undefined) {
64+
listeners.delete(listener);
65+
}
66+
}
67+
}

scripts/flow/react-devtools.js

+1-16
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,4 @@
77
* @flow
88
*/
99

10-
declare module 'events' {
11-
declare class EventEmitter<Events: Object> {
12-
addListener<Event: $Keys<Events>>(
13-
event: Event,
14-
listener: (...$ElementType<Events, Event>) => any,
15-
): void;
16-
emit: <Event: $Keys<Events>>(
17-
event: Event,
18-
...$ElementType<Events, Event>
19-
) => void;
20-
removeListener(event: $Keys<Events>, listener: Function): void;
21-
removeAllListeners(event?: $Keys<Events>): void;
22-
}
23-
24-
declare export default typeof EventEmitter;
25-
}
10+
// No types

0 commit comments

Comments
 (0)