Skip to content
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

doc: endorse "worker" and "dom" conditions #40914

Closed
wants to merge 1 commit into from
Closed

doc: endorse "worker" and "dom" conditions #40914

wants to merge 1 commit into from

Conversation

wooorm
Copy link

@wooorm wooorm commented Nov 21, 2021

This adds two new conditions to the endorsed conditions list in the Node.js documentation.

Their goal is to be more specific that the browser condition (and its predecessor, the browser field), around DOM APIs, specifically for web workers and non-web-workers.

The problem this solves is that most bundlers have a switch that is either browser or node, but this switch is not specific enough for web workers (or their alternative, “normal” web scripts/modules), which don’t have access to most importantly the DOM, but don’t have access to Node modules such as path or crypto or you name it. Folks (or tooling), typically pick the browser condition for web workers, but I as a package maintainer use browser to choose code that uses DOM APIs *(which is explicitly mentioned as a valid use case by the browser field spec).

A practical example is: https://github.com/wooorm/parse-entities/blob/6d7cef95baa04c3430f929cb017b541f54b9e863/package.json#L28-L40, although there isn’t a worker field, so that isn’t supported there. But what it does is: Use the full package by default, switch to the DOM version (which is very small because it uses DOM APIs) in browsers, and switch back to the default in places that don’t have a DOM (react-native, which is currently mentioned on the latest website but not in this file I changed).

This is why I propose a worker condition, which is already supported in webpack. But also it’s inverse (dom), because I think similar to dev/prod, it makes sense to have both.

Currently, webpack supports worker, and esbuild and rollup don’t (but then again webpack does workers out of the box and the rest allows arbitrary conditions). dom is a name I made up myself.

Here are links to the relevant code in what I believe are the primary bundlers for the web and where they handle conditions:

Qs:

  • worker has support in webpack, but on the other hand, it seems similar to the react-native field that is currently on the website but no longer in the source files, in that it means “no dom”. Open to alternatives
  • dom has no existing support, but i think it makes sense to provide an antonym to worker, because otherwise I as a package maintainer have to list all the platforms that have no DOM (worker, react-native, etc)

/cc @guybedford @defunctzombie @alexander-akait
Related-to: GH-40708 (in that this is my first PR to Node and I modelled it after a similar PR)

Can someone ping @nodejs/modules I guess?

@nodejs-github-bot nodejs-github-bot added the doc Issues and PRs related to the documentations. label Nov 21, 2021
@Trott
Copy link
Member

Trott commented Nov 21, 2021

Can someone ping @nodejs/modules I guess?

@nodejs/modules

@ljharb
Copy link
Member

ljharb commented Nov 21, 2021

It seems best that this page document things the community has actually already adopted, instead of suggesting things for the community to adopt.

@wooorm
Copy link
Author

wooorm commented Nov 21, 2021

I have no opinions on where this discussion is had or where the list is maintained, but I want to stress that the previous discussion, and the docs, and the lack of alternatives, seems to indicate that should raise discussions here currently. Feel free to point me and future contributors elsewhere for what the proper avenue is.

For 'worker' specifically, precedence is set by including angular's 'types' 2 weeks ago, compared to what I deem more popular, webpack supporting it already. If your comment is about 'dom', sure, but I mentioned that, I think it'd be good to not just include 'worker', but also an antonym.

@DerekNonGeneric
Copy link
Contributor

Feel free to point me and future contributors elsewhere for what the proper avenue is.

@wooorm, thank you for the PR.

You are on the right track and modifying this list in the core repo is most likely the way to go about doing this today. By making this PR, you seem to have expressed an interest (your response would be appreciated at the link below).

nodejs/loaders#52

@guybedford
Copy link
Contributor

Thanks for putting some coordination effort together here @wooorm. In general the requirements for listing conditions are quite tough and I think they have to be to avoid ending up with a mess of a conditions buffet.

Can definitely see the merit of these, but have to try and think about process too. Here's some feedback -

The guidelines for a new condition as listed in the docs state:

There should exist sufficient existing implementation usage.

So I think the "dom" condition would fail that check right now.

The definition of "worker" would need to be clear and aligned to with Webpack to land such a suggestion I think. In many cases pkg/worker as a separate export can fit the use cases fine as well since the worker entry is separately requested anyway which would fail the check of there needing to be a clear ecosystem benefit that isn't possible without the condition.

@ljharb
Copy link
Member

ljharb commented Nov 22, 2021

It seems important that something have interoperability - webpack is the most-used bundler, but it's only one. It seems like it'd be good for multiple popular bundlers to agree on the condition name.

@wooorm
Copy link
Author

wooorm commented Nov 23, 2021

In many cases pkg/worker as a separate export can fit the use cases fine as well since the worker entry is separately requested anyway which would fail the check of there needing to be a clear ecosystem benefit that isn't possible without the condition.
@guybedford

I don’t think so. Similar to how it’s not viable to start each package with pkg/node.js and pkg/development/node.js, and pkg/node/development/import.js or so. The file system or export maps work for their direct users. Conditions are about all users.

To explain the problem in other words:

  • I have a package that is 12kb minzipped by default, and less that 2kb using DOM APIs.
  • The package has about 30m downloads each month. It’s low level, somewhere in your node_modules. Let’s say it’s only used on a couple thousand websites, with each several thousand visitors every day. Sending the 12kb to every client means 100s of GBs each day extra compared to 2kb.
  • I’d rather not do that. So I use a browser field or condition to switch to the DOM API
  • The problem is that bundlers choose browser for React Native and for Web Workers because they’re more like browsers than Node.js
  • This is what a worker condition (and react-native conditions) “solve”.
  • …which in turn illustrates the need for DOM:
    "imports": {
      "#decode": {
        "every-time-something-browserlike-comes-out-i-need-to-add-exceptions": "./lib/decode.js",
        "react-native": "./lib/decode.js",
        "worker": "./lib/decode.js",
        "browser": "./lib/decode.dom.js",
        "default": "./lib/decode.js"
      }
    },
    vs.
    "imports": {
      "#decode": {
        "dom": "./lib/decode.dom.js",
        "default": "./lib/decode.js"
      }
    },

webpack is the most-used bundler, but it's only one. It seems like it'd be good for multiple popular bundlers to agree on the condition name.
@ljharb

Agreed. I think the place to discuss and agree on condition names is, well, this issue tracker. I suffixed my original comment with two questions.
For worker, that already has a (popular) implementation, which I think is similar in reason to why types and deno were added.

@guybedford
Copy link
Contributor

@wooorm I definitely agree there is utility here in the "dom" case... again there is a tough question of how to clearly define the condition. For example, does using JS Dom count? Does Deno implement any DOM APIs and how to draw the line between real ones? Or is it as simple as document existing as a global?

Does !"dom" not solve the worker needs for the most part?

The way to move forward would be to get Webpack or other bundlers interested in implementing this first before getting it further defined here.

If and when we move this listing to a new repo we could investigate more process around having stages of condition definitions, but right now this is only supposed to be a stable listing.

@wooorm
Copy link
Author

wooorm commented Nov 24, 2021

I agree on the need to get folks implementing it before listing it, but I also want to stress the need to first discuss it before anyone implements things. For example, webpack implemented worker, but in Node.js, worker is a term that could reference cloudflare workers or other things too, and hence webworker would perhaps be better. And I agree with you that !dom solves most react-native and worker cases, but we only know that when implementers discuss it.

@guybedford
Copy link
Contributor

@wooorm I was not aware Webpack have already implemented "worker" that's definitely interesting to know! Yes I see your point re guidance. I've tried to bootstrap more process in nodejs/loaders#52 but so far there hasn't been much interest. I do think we would need to first move to another repo to handle staged processes.

@wooorm
Copy link
Author

wooorm commented Nov 24, 2021

Yep, they do, see the OP. I found that out, and based on the issue there and the precedence set by types and deno, we thought it’d be good to add it here. Hence this PR. Which is especially why I think the pushback is weird.

The question then is (whether it’s maintained here or not), what this list is:

  • this list reflects what’s being supported by tools in the wild (i.e., worker is merged, dom isn‘t)
  • this list reflects recommendations for package publishers (because many tools support it)? (i.e., nothing is merged, multiple implementations are needed first)
  • is it a place where tool and package developers discuss how to solve a problem, to come and standardize a condition? (this PR)

@guybedford
Copy link
Contributor

@wooorm this list is basically the next step after bundler implementation - if eg Webpack has implemented but then is wanting to make sure there is clear guidance for other bundlers beyond its own documentation, and to help clarify where coordination between bundlers is needed to move to a place of stability for the meaning of a condition. For example, having it listed here might encourage other bundlers to more easily follow.

Worker could possibly fit the definition to be used further, but there is another confusion here and that is if Node.js would be expected to implement this condition for its worker threads?

@wooorm
Copy link
Author

wooorm commented Nov 26, 2021

I think the first is true: worker is in webpack (for 2 years it seems, see webpack/webpack#10953), I raised this here to semi-standardize it for others. I still agree that worker conflicts with other workers

/cc @alexander-akait @sokra from webpack

@ljharb
Copy link
Member

ljharb commented Nov 29, 2021

@wooorm have other bundlers also added support for it, or been asked to do so?

@wooorm
Copy link
Author

wooorm commented Nov 29, 2021

@ljharb No.
Partially because I’m unsure what this list is (currently, or when it’s in a different repo): is it a place to propose things before implementation? Is it a place to propose things after one implementation? Is it a place to document things implemented everywhere? I’ve opted for the middle ground but also see some problems that might be best discussed first before use grows.
But practically also: webpack has a specific worker feature. Other bundlers are agnostic to it.
As an analogy, say webpack had a specific development option, so it adds a development condition when that’s used. esbuild/Rollup are like: pass the conditions you want to use! YMMV!

@ljharb
Copy link
Member

ljharb commented Nov 29, 2021

@wooorm it does not feel appropriate to me for node to document anything before it gains widespread community adoption (multiple implementations) - that's prescriptive, and node's community docs should be descriptive.

@wooorm
Copy link
Author

wooorm commented Nov 29, 2021

I understand that. I’m open to it (when maintained here). Though from the rest of the conversation it sounds to me like other people see this list differently, and importantly it’s documented differently: “endorsed” and “user conditions”.
The current wording around the endorsed list and how it’s used tells a different story. development and production were added before conditions were a thing I believe. types and deno were added with one implementation. worker has much more weight behind them with 2 years of backing in the biggest bundler.

Maybe good to try and change the recommendation in the docs? Either to make it clear that you don’t want things like worker, or that Node.js does not prescribe it.

@guybedford
Copy link
Contributor

@wooorm the conditions requirements clearly state:

There should exist sufficient existing implementation usage.

"dom" simply does not fulfill that requirement as discussed.

The other requirement I'm calling out here is:

The definition should be clear and unambiguous for all implementers.

I have specifically asked if Node.js should implement the "worker" condition itself and there has been no clear response on that - thus this requirement is not currently being met either.

@wooorm
Copy link
Author

wooorm commented Nov 29, 2021

I have specifically asked if Node.js should implement the "worker"

This patch is the “user conditions” list, endorsed but not supported by Node.js. I believe you’re looking for the answer “no”.

"dom" simply does not fulfill that requirement as discussed.

I expressed that from the start. The reason I think it’s wise to discuss things beforehand is exactly the problems with worker. Can you please explain what would make dom or worker acceptable for you?

@guybedford
Copy link
Contributor

I have specifically asked if Node.js should implement the "worker"

Why would Node.js workers not be included? Would Deno be expected to support the "worker" condition? What about other JS environments? The guidance must be clear to all implementers.

Can you please explain what would make dom or worker acceptable for you?

It's not about what I find acceptable - it's about meeting the requirements for listing a condition which clearly state there must be existing prior implementation. If you want to change to do something that goes against the current guidance, then a new issue should be created to change the current guidance first.

@wooorm
Copy link
Author

wooorm commented Nov 29, 2021

  1. Neither deno nor node.js support the 'browser', or 'types' userland condition, and 'deno' isn't supported by many places either, so I don't expect them to support webpack's (Web)worker condition either, when it's listed in an optional endorsed userland condition list. Why are things on this list suddenly a requirement?
  2. Okay, ill try to get other folks to implement

@guybedford
Copy link
Contributor

@wooorm the "browser" condition is implemented by multiple bundlers, and the "types" condition is implemented by angular tooling as well as with support from TypeScript. Thus both conditions have support from multiple implementers. "deno" is platform specific so only has a single implementer but it is implemented.

The documentation is very clear on this:

New conditions definitions may be added to this list by creating a pull request to the Node.js documentation for this section. The requirements for listing a new condition definition here are that:
The definition should be clear and unambiguous for all implementers.
The use case for why the condition is needed should be clearly justified.
There should exist sufficient existing implementation usage.
The condition name should not conflict with another condition definition or condition in wide usage.
The listing of the condition definition should provide a coordination benefit to the ecosystem that wouldn't otherwise be possible. For example, this would not necessarily be the case for company-specific or application-specific conditions.

I'm specifically calling out with the "worker" condition that you are not fulfilling the requirements of:

The definition should be clear and unambiguous for all implementers.

To fulfill that requirement means making the answer to the question "does Node.js or Deno or another JS platform implement the worker condition" absolutely clear in the condition definition.

@wooorm
Copy link
Author

wooorm commented Nov 30, 2021

the "types" condition is implemented by angular tooling as well as with support from TypeScript

Can you provide proof that TS supports the types condition? I can’t find it your PR.

"deno" is platform specific so only has a single implementer but it is implemented.

worker is implemented for 2 years already. In something much more popular in the package ecosystem compared to deno.

To fulfill that requirement means making the answer to the question "does Node.js or Deno or another JS platform implement the worker condition" absolutely clear in the condition definition.

The description I provided seems crystal clear to me. Does Node.js/Deno/whatever implement “web workers (scripts that run in browser background threads)”? Are these platforms browsers? Do they support web workers? Could you perhaps suggest an edit to that line with actionable feedback on what you find vague and how that can be solved?


I’m stuck in a catch-22 here.

  1. I as a maintainer experience a problem in the ecosystem and I raise this PR to discuss a solution with the community
  2. I propose worker because it’s implemented even though it has problems, due to the term not having been discussed with the community
  3. I propose discussing dom because I think it’s a better solution, especially because it’s not implemented yet.

1 is being ignored, 2 is being rejecting on the grounds that it wasn’t discussed first, and 3 because it isn’t implemented 🤷‍♂️

I care about the problem: Some bundlers are picking the 10kb extra in browsers. Other bundlers are sending document.createElement to react-native, web workers, and Deno, because they‘re more like browsers than Node.js

@guybedford
Copy link
Contributor

@wooorm I'm trying to understand what you'd like to achieve here, it's just important to ensure it can fit into a clear conditions definition for all environments. These definitions can never be removed once added - their meanings are permanent. So definition friction and discussion is critical. I'm not just trying to give you a hard time, honest.

I agree with you that "dom" is a better solution to this problem, because a definition like:

{
  "exports": {
    "dom": "./lib-dom.js",
    "default": "./lib-nodom.js"
  }
}

seems like it will be much more widely supportable than even having to use the "worker" condition at all. Since you probably do want lib-nodom.js to be used in say Node.js and serverless runtimes like cloudflare workers etc.

My concerns around specifying "worker" is that web workers are and will continue to be implemented in non-browsers (I'm not sure if they are in cloudflare workers yet, but they may well be in platform variations in future), so the definition in its current form doesn't clearly deal with these situations. We also need to think about the scalability of this condition with respect to other types of worklet or worker-like environments. We can certainly continue this discussion, but those are the definition edge cases that need ironing out still.

Then in terms of building workflows around a "dom" condition, what exactly is holding you back here? All bundlers support a "browser" condition, so implementing a "dom" condition would involve getting one or two of those bundlers to support having the "browser" condition automatically also enable and resolve a "dom" condition in their implementations, which sounds to me like that is what would achieve what you are after?

Perhaps create a new PR for the "dom" condition, mark it as "pending implementation" and then you can link to that in any bundler PRs noting this can be coordinated once bundlers demonstrate interest.

@wooorm
Copy link
Author

wooorm commented Nov 30, 2021

I agree with you that "dom" is a better solution to this problem, because a definition like:

Glad to hear! Indeed. The list of exceptions is becoming long (I need to add deno there too, because esm.sh and skypack, that are often used for deno, even though they don’t support deno yet, are currently failing here and bringing DOM code to deno).

[on worker] We can certainly continue this discussion

The reason I added worker here is because it allows my to hack around part of my problem. Webpack folks told me about it and suggested I add it here. I agree with the problems.

[on dom] what exactly is holding you back here

Nothing. I consider this PR “pending implementation” and a place to discuss how it should be called before implementations.
I raised a questions around dom as a term earlier, maybe there’s something better. And (perhaps dangerously, perhaps a great idea), it would set precent for feature flags?

But I don’t think, just like with worker, that the biggest player should implement a condition, and then well, the rest just has to follow, without any discussion, even though the name might not make sense. The current centralized place to talk about it seems, well, here?


Perhaps a way to unblock this, is to add some separate lists.

  • One list (current) for “endorsed by Node.js”, for whatever reason y’all decide
  • Another list for: backed by one implementation: looking for feedback ('worker')
  • Last: Experimental/idea/vague/danger: see issue GH-XYZ ('dom')

Maybe this makes more sense for for when this list is moved elsewhere. But that might just take a lot of time?

@jasnell
Copy link
Member

jasnell commented Nov 30, 2021

My concerns around specifying "worker" is that web workers are and will continue to be implemented in non-browsers (I'm not sure if they are in cloudflare workers yet,

No they are not and likely won't be in current sense of the term. That said, I definitely agree that 'worker' is far too generic of a term. Aside from the "web worker" "worker_threads" ambiguity, "worker" could also be used by stuff specific to cloudflare workers. It's just not meaningful enough. A "dom" condition sounds reasonable.

@guybedford
Copy link
Contributor

Cloudflare are now using the "worker" condition for cloudflare workers - cloudflare/workers-sdk#93.

I believe this extends the definition of "worker" in this PR beyond simply web workers to any "worker-like" environment. @jasnell do you think we should land a definition of the "worker" condition now that we have multiple implementations on the table?

@wooorm
Copy link
Author

wooorm commented Dec 16, 2021

Reading that issue though, it seems that the dom condition mentioned here might be a better solution

@stevemk14ebr
Copy link

This is why I propose a worker condition, which is already supported in webpack. But also it’s inverse (dom), because I think similar to dev/prod, it makes sense to have both

Your original reasoning seems sound to me honestly. 'Worker' defining an environment without DOM - ie. worker like (cloudflare worker, web worker, etc). And 'dom' as the catch all antonym. Both seem useful and don't conflict.

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc Issues and PRs related to the documentations.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants