-
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
ESM "exports" field disables "main" lookup #29932
Comments
That does sound like a bug. |
Thanks to @tpoisseau for reporting it to me 😉 |
Is it? I was under the impression that |
Is there a clear reason it needs to be ignored? If you want them to differ, it already works; if you want one to be unresolvable, you can assign main/dot to false or similar; what’s the use case where you want to force an explicit (non backwards compatible, if someone changes main) dot? |
The way I think it was supposed to work is, in pseudo-code and ignoring some sugar: isTopLevelMapping = (e) => typeof e === 'string' || Array.isArray(e);
desuragedExports = isTopLevelMapping(e) ?
{ ".": pkg.exports } : pkg.exports;
exports = { ".": pkg.main, ...desuragedExports }; So the |
That sounds exactly like the way I'd expect it to work (modulo, useful error messages when things are invalid). |
Agreed this is a bug and that the logic should explicitly be that we only use the main if I do feel like this makes the distinction to users for when "main" applies quite complex to understand though, as some uses of the "exports" field allow it, while other uses of the "exports" field do not. That we overlooked it is also a bad sign. |
The point is that Eg - |
If you want that case tho, then you can do something like this, no? "exports": {
".": false,
"./": "./features/"
} which imo is a more explicit indication of that intention. |
@ljharb I also thought the intent was for "exports" to become the new main in Node.js, whereas supporting both very much keeps "main" around. |
when dot is present, it is the new main - but when not, it seems like supporting null is the better approach. |
The following works if you want to actively prevent a "exports": {
".": [],
"./": "./features/"
} But I would argue that this is a very uncommon case and usually you'd... just not create a file called exactly "index" in the root of your package and you'd be good. |
I think forcing people to repeat the same string twice for the next 2+ years isn't worth the win that most packages will get from locking down. Especially if they anyhow need to support users that don't respect lockdowns (that's why they still set "main": "./foo.js",
"exports": {} // reuse main but lock down in modern node, alternatively false Once pre-exports node cycles out of LTS, those package authors could switch to: "exports": "./foo.js" If they also have subpaths they need to map: "main": "./foo.js",
"exports": {
"./sub": "/lib/sub.js"
} After dropping support for pre-export node: "exports": {
".": "./foo.js",
"./sub": "/lib/sub.js"
} And then they'd also delete the top-level I believe "exports is the new main" is a valuable aspiration but I don't think that making the transitional period more painful for people trying to use exports while still supporting valid LTS releases of node is how we'll make it more likely. I'd much rather make it less painful to add exports to a package than more painful to keep main. |
If there is an "exports" field in the package.json file of a module, the "main" field becomes ignored by the resolver and if one tries to
import something from 'package'
where there is no'.'
export, it throws an error:Cannot resolve package exports target 'undefined' matched for '.' in /home/mzasso/test/bug-exports/node_modules/my-module/package.json, imported from /home/mzasso/test/bug-exports/test.mjs
Is this the expected behavior? If so, the documentation is not clear about that.
By the way, the exports resolver could probably be improved, saying that there was no matching key instead of trying to use
"undefined"
as the value.Repro: https://github.com/targos/bug-esm-exports
@nodejs/modules-active-members
The text was updated successfully, but these errors were encountered: