Skip to content
This repository has been archived by the owner on Sep 2, 2023. It is now read-only.

Define differential mapping support in exports #357

Closed
jkrems opened this issue Jul 23, 2019 · 12 comments
Closed

Define differential mapping support in exports #357

jkrems opened this issue Jul 23, 2019 · 12 comments

Comments

@jkrems
Copy link
Contributor

jkrems commented Jul 23, 2019

Right now exports only supports simple strings. Arguably it should also support arrays of strings just like import maps.

A stretch goal would to also support additional signals for differential mappings. E.g. having a mapping based on platform/OS or a production and a development build.

Since we're using main as an extension of the exports mechanism, this would potentially also affect main values.

@jkrems jkrems created this issue from a note in Support "exports" in package.json (To do) Jul 23, 2019
@ljharb
Copy link
Member

ljharb commented Jul 23, 2019

Why arguably? The reason for import maps in browsers to support that is because it's loading things over the network, which isn't what node will be doing.

@jkrems
Copy link
Contributor Author

jkrems commented Jul 23, 2019

Network errors are more of an anti-feature of import maps. I genuinely hope that support for handling network errors is removed from import maps. What it does allow is to say "I'm a polyfill for a built-in module, only load me if the native implementation doesn't exist". Or hopefully in the future true differential serving, e.g. based on platform or production/development as mentioned above.

@ljharb
Copy link
Member

ljharb commented Jul 23, 2019

ah - ok, so i can see optional deps working like this, like ['chokidar', './watcher-mock.js'] or something. is that what you had in mind?

@jkrems
Copy link
Contributor Author

jkrems commented Jul 23, 2019

There's some finer details when it comes to bare specifiers in values (since the resolution is generally not recursive). But assuming we'd have a new built-in module for mime, you could do something like ['nodejs:mime-types', './index.js'].

The more exciting thing would be if the array would support guards beyond "standard module with this URL exists". E.g. with strawman syntax:

[
  // "Load only if env is set to development"
  { env: 'development', path: './dist/dev.js' },
  // "Load if none of the entries above matched"
  './dist/prod.js'
]

This solves one important gap in ESM which is the absence of a way to load modules based on the environment. Top-level await with dynamic import still requires a lot of boilerplate to make that work, especially if there's more than one exported binding.

@ljharb
Copy link
Member

ljharb commented Jul 23, 2019

It might be useful to defer arrays, and objects in them, to future proposals/PRs - but ensure that they're errors right now, so that nobody starts using them in the meantime.

@guybedford
Copy link
Contributor

@ljharb if we were to throw for arrays / objects in exports, then that would effectively stop any backwards compat for these being supported in future though.

@bmeck
Copy link
Member

bmeck commented Jul 23, 2019

@guybedford can you explain? I took the comment to mean that it would ensure versions not supporting the Object/Array forms wouldn't silently ignore those values. If we silently ignore values that means that users can come to rely on that noop.

@guybedford
Copy link
Contributor

When the matched target is an unknown value / type, yes the only thing we'd want to do is likely throw. There are a few cases in play here, and the cases to reason about more graceful handling require exact proposals in mind - I will spare the process of going through all the examples, but the important thing is that where possible, backwards compat can be as graceful as possible as opposed to blocked.

@jkrems
Copy link
Contributor Author

jkrems commented Jul 23, 2019

We'd definitely want to support arrays asap because otherwise any library trying to use fallbacks would have to wait until node 12 is completely out of support. The general design of import maps suggest to me:

  • Step 1: Support arrays, ignore any non-strings, accept first string that resolves to a URL with a supported protocol (e.g. file:).
  • Step 2: In addition to the above, also accept nodejs: URLs as long as the built-in exists.
  • Step 3: In addition to the above, also accept std: URLs as long as the built-in exists.
  • etc.

Throwing means not being backwards-compatible in this case. Because the point is that earlier entries win and new features can only be introduced if they are ignored on older versions.

@jkrems
Copy link
Contributor Author

jkrems commented Jul 23, 2019

To illustrate how those steps help, here's a package published just after the latest version of node added support for std: URLs:

[
  'std:fetch', // versions that don't support std: URLs will skip this. latest node and browsers will use this one!
  'nodejs:fetch', // versions that don't support nodejs: URLs will skip this. versions that do support this URL will use this one!
  './fetch-polyfill.js', // any version with step 1 support will reach this one and - since it resolves to a file URL - will use it.
]

@jkrems jkrems moved this from To do to In progress in Support "exports" in package.json Aug 13, 2019
@jkrems
Copy link
Contributor Author

jkrems commented Aug 13, 2019

There's some improvements of the base array syntax that @guybedford wrote up in https://github.com/guybedford/proposal-pkg-targets.

@jkrems
Copy link
Contributor Author

jkrems commented Oct 29, 2019

Replaced with #401

@jkrems jkrems closed this as completed Oct 29, 2019
Support "exports" in package.json automation moved this from In progress to Done Oct 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests

4 participants