Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit e606fca

Browse files
committed
Allow add/removeEventListener/dispatchEvent in modules, closes #207
1 parent b3e187d commit e606fca

File tree

2 files changed

+40
-52
lines changed

2 files changed

+40
-52
lines changed

packages/core/src/standards/event.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
MiniflareError,
66
ThrowingEventTarget,
77
TypedEventListener,
8-
ValueOf,
98
prefixError,
109
} from "@miniflare/shared";
1110
import { Response as BaseResponse } from "undici";
@@ -177,6 +176,15 @@ export type WorkerGlobalScopeEventMap = {
177176
rejectionhandled: PromiseRejectionEvent;
178177
};
179178

179+
function isSpecialEventType(type: string) {
180+
return (
181+
type === "fetch" ||
182+
type === "scheduled" ||
183+
type === "trace" ||
184+
type === "queue"
185+
);
186+
}
187+
180188
export class WorkerGlobalScope extends ThrowingEventTarget<WorkerGlobalScopeEventMap> {}
181189

182190
// true will be added to this set if #logUnhandledRejections is true so we
@@ -269,10 +277,9 @@ export class ServiceWorkerGlobalScope extends WorkerGlobalScope {
269277
listener: TypedEventListener<WorkerGlobalScopeEventMap[Type]> | null,
270278
options?: AddEventListenerOptions | boolean
271279
): void => {
272-
if (this.#modules) {
273-
throw new TypeError(
274-
"Global addEventListener() cannot be used in modules. Instead, event " +
275-
"handlers should be declared as exports on the root module."
280+
if (this.#modules && isSpecialEventType(type)) {
281+
return this.#log.warn(
282+
`When using module syntax, the '${type}' event handler should be declared as an exported function on the root module as opposed to using the global addEventListener().`
276283
);
277284
}
278285

@@ -295,12 +302,7 @@ export class ServiceWorkerGlobalScope extends WorkerGlobalScope {
295302
listener: TypedEventListener<WorkerGlobalScopeEventMap[Type]> | null,
296303
options?: EventListenerOptions | boolean
297304
): void => {
298-
if (this.#modules) {
299-
throw new TypeError(
300-
"Global removeEventListener() cannot be used in modules. Instead, event " +
301-
"handlers should be declared as exports on the root module."
302-
);
303-
}
305+
if (this.#modules && isSpecialEventType(type)) return;
304306

305307
// Unregister process wide rejectionHandled/unhandledRejection listeners if
306308
// no longer needed and not already done so
@@ -314,16 +316,6 @@ export class ServiceWorkerGlobalScope extends WorkerGlobalScope {
314316
super.removeEventListener(type, listener, options);
315317
};
316318

317-
dispatchEvent = (event: ValueOf<WorkerGlobalScopeEventMap>): boolean => {
318-
if (this.#modules) {
319-
throw new TypeError(
320-
"Global dispatchEvent() cannot be used in modules. Instead, event " +
321-
"handlers should be declared as exports on the root module."
322-
);
323-
}
324-
return super.dispatchEvent(event);
325-
};
326-
327319
[kAddModuleFetchListener](listener: ModuleFetchListener): void {
328320
this.#calledAddFetchEventListener = true;
329321
super.addEventListener("fetch", (e) => {

packages/core/test/standards/event.spec.ts

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
kDispatchFetch,
1414
kDispatchScheduled,
1515
} from "@miniflare/core";
16-
import { NoOpLog } from "@miniflare/shared";
16+
import { LogLevel, NoOpLog } from "@miniflare/shared";
1717
import {
1818
TestLog,
1919
getObjectProperties,
@@ -66,42 +66,38 @@ test("ServiceWorkerGlobalScope: includes environment in globals if modules disab
6666
/^env is not defined\.\nAttempted to access binding using global in modules/,
6767
});
6868
});
69-
test("ServiceWorkerGlobalScope: addEventListener: disabled if modules enabled", (t) => {
70-
const globalScope = new ServiceWorkerGlobalScope(new NoOpLog(), {}, {}, true);
71-
t.throws(() => globalScope.addEventListener("fetch", () => {}), {
72-
instanceOf: TypeError,
73-
message:
74-
"Global addEventListener() cannot be used in modules. Instead, event " +
75-
"handlers should be declared as exports on the root module.",
76-
});
77-
});
78-
test("ServiceWorkerGlobalScope: removeEventListener: disabled if modules enabled", (t) => {
79-
const globalScope = new ServiceWorkerGlobalScope(new NoOpLog(), {}, {}, true);
80-
t.throws(() => globalScope.removeEventListener("fetch", () => {}), {
81-
instanceOf: TypeError,
82-
message:
83-
"Global removeEventListener() cannot be used in modules. Instead, event " +
84-
"handlers should be declared as exports on the root module.",
85-
});
86-
});
87-
test("ServiceWorkerGlobalScope: dispatchEvent: disabled if modules enabled", (t) => {
88-
const globalScope = new ServiceWorkerGlobalScope(new NoOpLog(), {}, {}, true);
89-
const event = new FetchEvent("fetch", {
90-
request: new Request("http://localhost"),
91-
});
92-
t.throws(() => globalScope.dispatchEvent(event), {
93-
instanceOf: TypeError,
94-
message:
95-
"Global dispatchEvent() cannot be used in modules. Instead, event " +
96-
"handlers should be declared as exports on the root module.",
97-
});
69+
test("ServiceWorkerGlobalScope: addEventListener: warns for special events if modules enabled", async (t) => {
70+
let customEvents = 0;
71+
const customEventListener = () => customEvents++;
72+
73+
const log = new TestLog();
74+
const globalScope = new ServiceWorkerGlobalScope(log, {}, {}, true);
75+
76+
globalScope.addEventListener("fetch", () => {});
77+
globalScope.addEventListener("scheduled", () => {});
78+
globalScope.addEventListener("trace" as any, () => {});
79+
globalScope.addEventListener("queue" as any, () => {});
80+
globalScope.addEventListener("custom" as any, customEventListener);
81+
const warningMessage = (type: string) =>
82+
`When using module syntax, the '${type}' event handler should be declared as an exported function on the root module as opposed to using the global addEventListener().`;
83+
t.deepEqual(log.logsAtLevel(LogLevel.WARN), [
84+
warningMessage("fetch"),
85+
warningMessage("scheduled"),
86+
warningMessage("trace"),
87+
warningMessage("queue"),
88+
]);
89+
90+
globalScope.dispatchEvent(new Event("custom") as any);
91+
t.is(customEvents, 1);
92+
globalScope.removeEventListener("custom" as any, customEventListener);
93+
globalScope.dispatchEvent(new Event("custom") as any);
94+
t.is(customEvents, 1);
9895
});
9996
test("ServiceWorkerGlobalScope: hides implementation details", (t) => {
10097
const { globalScope } = t.context;
10198
t.deepEqual(getObjectProperties(globalScope), [
10299
"KEY", // binding
103100
"addEventListener",
104-
"dispatchEvent",
105101
"global",
106102
"removeEventListener",
107103
"self",

0 commit comments

Comments
 (0)