-
Notifications
You must be signed in to change notification settings - Fork 30k
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
Package.json exports
field: Differentiate between ./*
and ./*/
#39994
Comments
Current options: Only resolve indexCannot import from "exports": {
"./package.json": "./package.json",
".": "./dist/index.js",
"./*": "./dist/*/index.js"
}, import 'my-package/path/to/dir'
// resolves to `my-package/path/to/dir/index.js`
import 'my-package/path/to/dir/test.js'
// fails, tries to resolve to `my-package/path/to/dir/test.js/index.js`
// would otherwise be a perfectly valid import source Only resolve non-index (fine for now)This approach means it is not possible to export members from some "exports": {
"./package.json": "./package.json",
".": "./dist/index.js",
"./*": "./dist/*.js"
}, import 'my-package/path/to/source'
// resolves to `my-package/path/to/source.js`
import 'my-package/path/to/source/index'
// only way to import from an index |
Tbh, it is clear that the trailing slash has an effect on the logic, but not the desired one. It's possible that this may be possible, but as far as I can tell, it is not (even if you combine different specifications, like Maybe @ljharb can add thoughts? |
Having reviewed the related discussions and specification a bit, I can tell the request for trailing slash support will be rejected out of hand since removing that seems to have been a core feature of ES imports. However, we should still think about how to achieve the setup described here. Interestingly, using a prefix works, though is super unintuitive? "exports": {
"./package.json": "./package.json",
".": "./dist/index.js",
"./*": "./dist/*.js",
"./index/*": "./dist/*/index.js"
}, import { test } from 'my-package/test'
// resolves to `./dist/test.js'
import { test } from 'my-package/index/path/to/module'
// resolves to `my-package/path/to/module/index.js` This is a potential solution for now, but perhaps a better long-term solution would be allowing multiple match attempts:
|
If you're looking to auto-resolve to |
@ljharb Not auto-resolve, but manually configure to achieve this. I have found a workaround, it is just highly un-ergonomic (see last comment). Also, just theoretically, 100% of existing ESM imports right now resolve on the first try (by definition). Allowing an opt-in for a second try on the first failure in order to achieve this result directly would be well-worth the trade-off IMO. I am not saying we change how ESM resolution happens. I am saying we consider allowing opt-in behavior that could achieve this, or examine the current logic for a way to achieve something similar. Right now, it is possible via the example above: import { test } from 'my-package/test'
// resolves to `./dist/test.js'
import { test } from 'my-package/index/path/to/module'
// resolves to `my-package/path/to/module/index.js` But it's pretty confusing. My original concept of having a trailing slash was a way to specify it statically on the first try, but that is also ruled out. This is the only way that it is currently possible and, based on the response, the only way it would ever be possible. |
I have decided on the |
The idea behind this design decision IIRC was to allow someone to create a tool that reads a Not sure if that helps, but you can make export * from './dir/index.js';
export { default } from './dir/index.js'; |
Thanks @aduh95—I've decided to embrace it instead, and am exporting only index resolvers. Under this paradigm, As a final note, under a proposal where we recognize the trailing slash, there would be no need for multiple resolution attempts. |
@ctjlewis i'm confused why you'd ever want |
@ljharb I don't, it's explicitly what I want to avoid. When I say "I have decided on the "exports": {
"./*": "./dist/*/index.js"
} // resolves to my-package/dist/a/index.js
import { something } from 'my-package/a' This is actually the only logic that lets me avoid having consumers ever manually type This is all work related to a TS-ESM compiler I'm building, a TSDX fork at @tszip/tszip. From the README:
|
Specifically, the first example in this issue now works: "exports": {
"./package.json": "./package.json",
".": "./dist/index.js",
"./*/": "./dist/*/index.js",
"./*": "./dist/*.js"
}, |
The problem with the trailing slash pattern though is that it is not supported in import maps per the issue linked above. For this reason I'd strongly discourage using the trailing slash here, and I'm considering if it might be worth a follow-up PR to ban this. |
Why should node limit itself just because browsers haven't decided to support it? It's a common pattern in the JS ecosystem, and we should support it. |
We do support it - via require. We haven't supported it for ES modules at any point until trailing patterns were added and released two days ago. Correction: Actually this was supported in patterns of the form |
Thanks for clarifying. Why wouldn't we want to support it in ESM, since we support it in require? |
I've corrected my comment above, there was a previous patterns edge case that did support this as well, although I don't expect it would have been widely known. This discussion is off-topic for this thread at this point, I'm going to post up a PR shortly with the motivation and we can continue discussion there. |
Absolutely astounding work @guybedford, crazy this just landed two days ago, had no idea! Thank you also @ljharb for your input, I agree. I'm just trying to standardize subdir imports for ES modules compiled from TS with If it were possible to resolve It does seem based off your response though Guy that, on Node 16.9+, we could export |
Is your feature request related to a problem? Please describe.
Yes. I would like to be able to statically resolve entry points to
path/*/index.js
andpath/*.js
, similar to how is done in CJS, e.g. by adding a trailing slash to the match pattern like so:This would allow interop with traditional indexing:
This is currently not feasible as I understand it, and it would be necessary to import via
import '.../index.js'
regardless of how theexports
field is configured.Describe the solution you'd like
Modifyexports
field logic to differentiate between./*
and./*/
.Allow a single pattern to have multiple matches, either via:
Or:
The text was updated successfully, but these errors were encountered: