-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
events,bootstrap: make globalThis extend EventTarget #45993
base: main
Are you sure you want to change the base?
Conversation
Fixes nodejs#45981 Changes: - Moves all EventTarget symbols to one symbol, to prevent exposing 4 symbols to globalThis. - Fallback to `globalThis` as the this value in EventTarget if this is null or undefined. This is needed to make the "floating" methods work (ie. `addEventListener(...)`).
Review requested:
|
We can enable certain web platform tests with this, right? @KhafraDev |
If we are going to do this, and if this is a breaking change, I believe a flag is needed to enable this experimental feature |
I don't think so, I'm pretty sure the WPT runner will throw an error if previously failing tests started passing. edit: one test was enabled actually. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd need to forbid their use in lib/
as we do with other browser globals:
Lines 155 to 156 in 3ce4cef
- name: console | |
message: Use `const { console } = require('internal/console/global');` instead of the global. |
@joyeecheung does this have an impact on the snapshotting effort? |
I updated the eslint config but I wasn't sure what they should be replaced with. |
Do we feel like this is something we want in Node.js? I understand that this is something that other platforms do, but those platforms aren't Node.js and didn't have things like the I'm not even sure that browsers would do this nowadays with the benefit of hindsight in how JS developed as a language. But yeah, either way, definitely a significant breaking change, probably one where it's worth pinging @nodejs/collaborators. |
Tagging it tsc-agenda for awareness. |
I'm not convinced we should land this change. None of the cases mentioned in the linked issues are applicable to Node. Most of the useful cases are already handled by Node.js |
I'd say no right now. If we do ever make globalThis emit events then yes it should be EventTarget and not EventEmitter but I don't think there's enough justification for this now. |
I'm also -1 on this for the previously mentioned reasons. |
I'm neutral at the moment. |
Is this something that perhaps users could opt into? Like a method on |
Currently? No, because node doesn't implement it. In the future I can see libraries adopting it to emit events, rather than using the node-only process/EventEmitter combo. It helps writing isomorphic libraries, in a way that build tools (such as typescript, linters, etc) will be fine with. It should also be pointed out that both process and globalThis EventTarget can exist separately, without causing issues. globalThis doesn't need to re-implement all of process' events. Although I assume if this landed it would be requested.
I would say that this change isn't applicable because node doesn't implement it. If node's global object always extended EventTarget, there would undoubtedly be libraries/apps/scripts using it, rather than using process. The same argument could probably be used for any web standard - "x isn't applicable to node, you can use y instead" (even when the proposed alternative is a very loose fit IMO).
If there's not enough reason to add it now, I doubt there ever will be 😅. People aren't writing code that will hopefully work in node one day. |
My two cents: libraries emitting global events make the ecosystem more brittle. Sometimes certain behaviors must be global, but it's essentially a pattern to avoid whenever possible. I'm loosely -1, but I might be convinced to approve it if there is a fundamental use case to cover. |
I don't think so, as long as no events are emitted/handlers are added during bootstrap (I don't see any here). I am +1 to the idea of making |
Here are the events Deno has https://deno.land/manual@v1.29.1/runtime/program_lifecycle#program-lifecycle (load, beforeunload, unload, and unhandledrejection). |
Just so that my question doesn’t get lost, is there a way to opt into this? So that the default behavior doesn’t change, but users who want this can enable it. I think that might make it much more palatable, and we can defer the decision on whether it should be enabled by default. |
Question. Is there any hope/request that the browsers, deno, etc would move these out of global and into some proper scope? like Edit: per #45993 (comment)
this. (if you'll pardon the pun). What would they do? Probably something different, putting these events into a different scope than globalThis. |
No, there's no feasible way of adding EventTarget methods onto fetch (etc.). Deno has recently added events to globalThis, so it's unlikely they're gonna change anything either. Specs that were planning on emitting events already extend EventTarget, such as WebSocket, XMLHttpRequest, FileReader, and others. Plus, there are global events for fetch that work in service workers.
It could be done in a future PR, this PR doesn't change how events are emitted. |
We discussed in the TSC meeting today, at this point the consensus seems to be that value |
It would be handy to implement things like Main thread: const fetchWorker = new FetchWorker('my-fetch-worker', {
port: 1234
}) Worker thread: addEventListener('fetch', event => {
return event.respondWith(new Response('Hello!'));
}); I feel like most of the interop cases where we'd benefit from having globalThis extend EventTarget are related to ServiceWorker features. Can anyone think of a case where we'd actually want that in the main thread? |
Same uses as process emitting events. I wouldn't call process a good alternative though, considering only one platform supports it. It could technically be used as an alternative to diagnostics_channel as well (FetchEvent is a good example of being able to use the global event listener to debug/log/intercept requests made). |
to listen to any of this events:
|
What's |
Many of these events are questionable in the context of Node.js (e.g., |
I think I mentioned it in the PR, but the only events node would probably want to add would be the same as Deno: https://deno.com/manual@v1.34.0/runtime/program_lifecycle#program-lifecycle |
To quote myself from #45981 for those who are subscribed to this PR thread:
|
This comment was marked as off-topic.
This comment was marked as off-topic.
That link doesn't mention any |
(fwiw: There existed such an event in some spec drafts and discussions "back then" around 2015-2017 and I was curious if browsers ended up adding some sort of promise tracking eventually (which they were opposed to)). I am happy to hide these comments as off topic and I also think we need to open an issue or discussion rather than having this discussion in the PR since none of it is about the actual code in the PR edit: here: #45981 |
I'm still generally -1 on this given the confusion it is likely to cause with |
How about being able to opt into it like two have already suggested? Having it behind a flag and potentially only try it out in a un-even NodeJS release... import `node:util/attach-eventtarget-to-global`
/*
Would basically change the prototype of globalThis with Object.setPrototypeOf(...)
and add postMessage, addEventListener, removeEventListener, dispatchEvent
doing globalThis instanceof EventTarget would also be true then after importing this util
*/ but this seems very unconventional and weird? think a flag would be better to have |
If someone really wanted to opt in to that they could fairly easily do...
|
The |
Yes, somewhere in the webidl spec ( // Emits an event in browsers/Deno/etc., but does nothing in node.
EventTarget.prototype.dispatchEvent.call(globalThis, new Event('fetch')) |
This is probably a breaking change. I will add tests once the actual implementation's been approved just so I don't waste time writing tests for a feature that won't land 😄. Same with docs.
Changes:
symbols to globalThis.
globalThis
as the this value in EventTarget if this isnull or undefined. This is needed to make the "floating" methods work
(ie.
addEventListener(...)
). It's also a webidl thing,https://webidl.spec.whatwg.org/#dfn-create-operation-function
dispatchEvent
,addEventListener
,removeEventListener
.Fixes: #45981