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

Proposal: Expand usage of package.json exports and engines fields for runtimes #36

Closed
Ethan-Arrowood opened this issue Sep 21, 2022 · 13 comments

Comments

@Ethan-Arrowood
Copy link
Contributor

Ethan-Arrowood commented Sep 21, 2022

In short, I propose that we expand on the usage of the exports and engines fields in package.json to support our various runtime environments. This would enable package authors to export their code to multiple runtimes simultaneously and have it all be defined from the same package.json.


This idea stems from the current browser and engine property in package.json allowing Node.js package authors to specify (a) if their package can be used in a given browser environment, and (b) what version of node.js/npm the package works with.

I'm not aware how all of the various runtimes currently handle dependency resolution, but at least for Vercel's edge runtime, we would like package authors to be able to specify that their package works with our runtime.

Here is an example. Given a (fake) package vercel-sdk, it is able to be used in both Node.js and Vercel Edge Runtime. For Node.js it relies upon APIs only available in v16.8+. For Vercel Edge Runtime, it works with v1. The exports for each runtime are also different. Based on the proposal I'd like to implement here is what the package.json might look like.

{
  "name": "vercel-sdk",
  "exports": {
    "node": "./dist/index.node.js",
    "edge-runtime": "./dist/index.edge-runtime.js",
  },
  "engines": {
    "node": ">=16.8.0",
    "edge-runtime": ">=1.0.0"
  }
}

Vercel has a weighted interest in this feature as we look to further expand usage of Edge Runtime. No strict timeline, but I will be happy to do the work and push this through. Let me know what y'all think!

@Ethan-Arrowood Ethan-Arrowood changed the title Proposal: Expand usage of package.json exports and engine fields for runtimes Proposal: Expand usage of package.json exports and engines fields for runtimes Sep 21, 2022
@ljharb
Copy link
Member

ljharb commented Sep 21, 2022

I think wintercg can and should set up an "official" list of engine names (like "edge-runtime", "node", etc), and as long as each platform that has a mechanism for specifying an engine combined with a semver range uses those engine names, it should be compliant.

That way, the requirement wouldn't need to be "a package.json with an engines field", it'd just be "if you have a map of engine to semver range, here's what the names mean"

@Ethan-Arrowood
Copy link
Contributor Author

Ethan-Arrowood commented Sep 21, 2022

👍 on "official" list of engine names.

Ideally, I'd like us to also specify how they may be used in various contexts. I understand Deno does some fairly unique things with modules, but that Node, Edge Runtime, Bun, and Workers could all potentially share through the use of package.json. Furthermore, I'd want the various ecosystems to have some consensus. At a minimum, if Node.js and Edge Runtime are using package.json I'd like there to be some spec/docs somewhere that indicate correct usage for both platforms.


Follow up: discussion and thinking about this some more; I agree we shouldn't attempt to create some specification for package.json. It has always been a shared project definition file and we should not change that. It will be more valuable if all the runtimes had some encouragement to (like what @ljharb said) use a defined set of keys to represent themselves and other runtimes in various toolings. Prime example would be Node.js using "node" within packge.json. Similarly, Vercel Edge Runtime can use "edge-runtime" within package.json too.

@phoddie
Copy link

phoddie commented Sep 21, 2022

It sounds like this could also be useful for embedded, so that a package could be tagged as compatible with embedded JavaScript engines and runtimes. Currently there's no definitive way to know an npm package can be used on embedded (many can) short of giving it a try.

@Ethan-Arrowood
Copy link
Contributor Author

More concrete thoughts based on further disucssions:

  • specified list of keys associated with runtimes
    • we should launch the specification with keys for all runtimes in WinterCG
    • the function of this list is mainly to prevent conflicts in developer tooling between runtimes
    • the specification should not specify how the keys are to be used in a literal sense (i.e. "use this key in the engines field in package.json"). It should specify that the keys are the be used within package configuration/definition files (regardless of format).
    • Further communicate that runtimes are responsible for documenting correct usage of the key however it applies to them. For example, Node.js already does this with the "node" key in the exports documentation
  • standardized process to create/modify/remove keys (need to be cognizant of name squatting)
    • membership / participation in WinterCG required for having a key? (my opinion is no, as long as the a representative of that runtime is present to propose what key they want)
    • what does it take for a key to be removed?
    • what does it take for a key to be modified?
      • Which is essentially remove old key and add new one if its the actual key name that is changing
      • Maybe simpler process for modifying a description associated with the key?

@Ethan-Arrowood
Copy link
Contributor Author

Ethan-Arrowood commented Sep 26, 2022

When discussing internally, someone mentioned an example package that is already making use of quite a few unique keys in the package.json file. https://unpkg.com/browse/jose@4.9.3/package.json

Under exports it is using deno and worker in addition to the more regular types, browser, import, and require. Additionally, it has top level types, browser, main, and deno fields.

This leads me to believe that many of the existing runtimes already have their key of choice. Can I draft something that documents these all in one place?

  • Node.js = node
  • Deno = deno
  • Cloudflare Workers = worker Based on webpack docs, it looks like worker is meant for WebWorkers

Vercel is agreeing internally what we want our key to be; when I draft the standard document I'll include Vercel's decision

@legendecas
Copy link
Member

Are there any (official) references on those runtimes (other than node) utilizing the exports fields? Would be great to link the identifier to their official references in the draft.

@ljharb
Copy link
Member

ljharb commented Sep 26, 2022

worker seems a bit too generic given that browsers have workers too.

@Ethan-Arrowood
Copy link
Contributor Author

I couldn't find unfortunately (hence apart of the problem I'm trying to solve here).

And I think you're right @ljharb - i just found the Webpack docs which reference worker as not Cloudflare but for WebWorkers (https://webpack.js.org/guides/package-exports/#target-environment)... And it also lists more! Like electron and react-native

@panva
Copy link

panva commented Sep 29, 2022

  • Cloudflare Workers = worker Based on webpack docs, it looks like worker is meant for WebWorkers

This worker target came from this PR, it may give you a few details on the bundler that was used.

@jasnell
Copy link
Contributor

jasnell commented Oct 3, 2022

For Cloudflare Workers the name should be workerd (note the d at the end)

@jasnell
Copy link
Contributor

jasnell commented Jan 26, 2023

This was done!

@jasnell jasnell closed this as completed Jan 26, 2023
@styfle
Copy link

styfle commented Jan 26, 2023

Lets get this added to the website:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants