-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Always use custom EventEmitter implementation to fix webpack/nextjs/w…
…hatever being dumb Fixes #65
- Loading branch information
1 parent
8db0221
commit 1f86352
Showing
1 changed file
with
84 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,121 +1,109 @@ | ||
type EventEmitter = import("node:events"); | ||
let EventEmitter: typeof import("node:events"); | ||
type NodeEventEmitter = import("node:events"); | ||
|
||
try { | ||
EventEmitter = require("node:events"); | ||
if (!("EventEmitter" in EventEmitter)) | ||
// force an error if the module isn't as expected | ||
throw new Error(); | ||
type Listener = (...args: any[]) => void; | ||
const EMPTY: Listener[] = []; | ||
|
||
} catch { | ||
class EventEmitter implements NodeEventEmitter { | ||
|
||
type Listener = (...args: any[]) => void; | ||
const EMPTY: Listener[] = []; | ||
private _maxListeners = 10; | ||
private readonly _listeners: Record<string | symbol, Listener[]> = {}; | ||
|
||
class EventEmitterAlternative implements EventEmitter { | ||
|
||
private _maxListeners = 10; | ||
private readonly _listeners: Record<string | symbol, Listener[]> = {}; | ||
|
||
public addListener (eventName: string | symbol, listener: Listener): this { | ||
const listeners = this._listeners[eventName] ??= []; | ||
listeners.push(listener); | ||
if (listeners.length > this._maxListeners) | ||
console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${listeners.length} ${eventName.toString()} listeners added. Use emitter.setMaxListeners() to increase limit`); | ||
return this; | ||
} | ||
public addListener (eventName: string | symbol, listener: Listener): this { | ||
const listeners = this._listeners[eventName] ??= []; | ||
listeners.push(listener); | ||
if (listeners.length > this._maxListeners) | ||
console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${listeners.length} ${eventName.toString()} listeners added. Use emitter.setMaxListeners() to increase limit`); | ||
return this; | ||
} | ||
|
||
public prependListener (eventName: string | symbol, listener: Listener): this { | ||
const listeners = this._listeners[eventName] ??= []; | ||
listeners.unshift(listener); | ||
if (listeners.length > this._maxListeners) | ||
console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${listeners.length} ${eventName.toString()} listeners added. Use emitter.setMaxListeners() to increase limit`); | ||
return this; | ||
} | ||
public prependListener (eventName: string | symbol, listener: Listener): this { | ||
const listeners = this._listeners[eventName] ??= []; | ||
listeners.unshift(listener); | ||
if (listeners.length > this._maxListeners) | ||
console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${listeners.length} ${eventName.toString()} listeners added. Use emitter.setMaxListeners() to increase limit`); | ||
return this; | ||
} | ||
|
||
public removeListener (eventName: string | symbol, listener: Listener): this { | ||
const listeners = this._listeners[eventName]; | ||
if (listeners) { | ||
const index = listeners.indexOf(listener); | ||
if (index >= 0) { | ||
if (listeners.length === 1) | ||
delete this._listeners[eventName]; | ||
else | ||
listeners.splice(index, 1); | ||
} | ||
public removeListener (eventName: string | symbol, listener: Listener): this { | ||
const listeners = this._listeners[eventName]; | ||
if (listeners) { | ||
const index = listeners.indexOf(listener); | ||
if (index >= 0) { | ||
if (listeners.length === 1) | ||
delete this._listeners[eventName]; | ||
else | ||
listeners.splice(index, 1); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
public on (eventName: string | symbol, listener: Listener): this { | ||
this.addListener(eventName, listener); | ||
return this; | ||
} | ||
return this; | ||
} | ||
|
||
public once (eventName: string | symbol, listener: Listener): this { | ||
const realListener: Listener = (...args) => { | ||
this.removeListener(eventName, realListener); | ||
listener(...args); | ||
}; | ||
this.addListener(eventName, realListener); | ||
return this; | ||
} | ||
public on (eventName: string | symbol, listener: Listener): this { | ||
this.addListener(eventName, listener); | ||
return this; | ||
} | ||
|
||
public prependOnceListener (eventName: string | symbol, listener: Listener): this { | ||
const realListener: Listener = (...args) => { | ||
this.removeListener(eventName, realListener); | ||
listener(...args); | ||
}; | ||
this.prependListener(eventName, realListener); | ||
return this; | ||
} | ||
public once (eventName: string | symbol, listener: Listener): this { | ||
const realListener: Listener = (...args) => { | ||
this.removeListener(eventName, realListener); | ||
listener(...args); | ||
}; | ||
this.addListener(eventName, realListener); | ||
return this; | ||
} | ||
|
||
public off (eventName: string | symbol, listener: Listener): this { | ||
this.removeListener(eventName, listener); | ||
return this; | ||
} | ||
public prependOnceListener (eventName: string | symbol, listener: Listener): this { | ||
const realListener: Listener = (...args) => { | ||
this.removeListener(eventName, realListener); | ||
listener(...args); | ||
}; | ||
this.prependListener(eventName, realListener); | ||
return this; | ||
} | ||
|
||
public removeAllListeners (event?: string | symbol | undefined): this { | ||
if (event !== undefined) | ||
delete this._listeners[event]; | ||
return this; | ||
} | ||
public off (eventName: string | symbol, listener: Listener): this { | ||
this.removeListener(eventName, listener); | ||
return this; | ||
} | ||
|
||
public emit (eventName: string | symbol, ...args: any[]): boolean { | ||
for (const listener of this._listeners[eventName]) | ||
listener(...args); | ||
return true; | ||
} | ||
public removeAllListeners (event?: string | symbol | undefined): this { | ||
if (event !== undefined) | ||
delete this._listeners[event]; | ||
return this; | ||
} | ||
|
||
public setMaxListeners (n: number): this { | ||
this._maxListeners = n; | ||
return this; | ||
} | ||
public emit (eventName: string | symbol, ...args: any[]): boolean { | ||
for (const listener of this._listeners[eventName]) | ||
listener(...args); | ||
return true; | ||
} | ||
|
||
public getMaxListeners (): number { | ||
return this._maxListeners; | ||
} | ||
public setMaxListeners (n: number): this { | ||
this._maxListeners = n; | ||
return this; | ||
} | ||
|
||
public listeners (eventName: string | symbol): Function[] { | ||
const listeners = this._listeners[eventName]; | ||
return listeners ? [...listeners] : EMPTY; | ||
} | ||
public getMaxListeners (): number { | ||
return this._maxListeners; | ||
} | ||
|
||
public rawListeners (eventName: string | symbol): Function[] { | ||
throw new Error("The rawListeners method is not available using this polyfill"); | ||
} | ||
public listeners (eventName: string | symbol): Function[] { | ||
const listeners = this._listeners[eventName]; | ||
return listeners ? [...listeners] : EMPTY; | ||
} | ||
|
||
public listenerCount (eventName: string | symbol): number { | ||
return this._listeners[eventName]?.length ?? 0; | ||
} | ||
public rawListeners (eventName: string | symbol): Function[] { | ||
throw new Error("The rawListeners method is not available using this polyfill"); | ||
} | ||
|
||
public eventNames (): (string | symbol)[] { | ||
return Object.keys(this._listeners); | ||
} | ||
public listenerCount (eventName: string | symbol): number { | ||
return this._listeners[eventName]?.length ?? 0; | ||
} | ||
|
||
EventEmitter = EventEmitterAlternative as any; | ||
public eventNames (): (string | symbol)[] { | ||
return Object.keys(this._listeners); | ||
} | ||
} | ||
|
||
export default EventEmitter; |