Repository navigation
Empty path matching in patterns #49447
Description
Activity
I will throw in that if we make
./sub/*not matchpkg/sub/, then we should also make./sub/not matchpkg/sub/(assuming that's still possible which I think it is). If we want to encourage people to always use patterns even when prefix would technically also work, it feels weird if there's this one case where an exports can be expressed using prefix but not using pattern.@jkrems we were discussing a multi-major deprecation of path exports. At the current rate of progress on anyone having a clue how to build a standard around
import.meta.resolvethis is the time frame we are looking for that landing too!Remember as well that these paths are also used for CJS, and
require('pkg/')with CJS's automatic resolution is supremely useful.Ah that's an interesting case. Does that work currently with exports resolution to resolve eg index? If so, I'm not sure the group as a whole made a decision to support that explicitly.
- addedmodules-agendaIssues and PRs to discuss during Modules team meetings.Issues and PRs to discuss during Modules team meetings.
on Sep 18, 2020 Yes, it does (for CJS), and yes, we definitely did. Only ESM has limited resolution inside a
/export.@ljharb I wrote the PR and I didn't know about this case! I disagree in thinking the answer to the fact that
require('pkg/')with an"exports": { "./": "./" }entry will resolvepkg/index.jswas formerly understood all members of this group let alone explicitly endorsed.Here is an example of a case where empty string matches might unintentially expose modules:
{ "exports": { "./*": "./*/main.js } }Where there exist subfolders like
"feature1","feature2"etc to supportimport 'pkg/feature1'.I do not think it would be obvious that
import 'pkg/'would resolve topkg/main.jsin this case. This is because it resolves to.//main.jswhich resolves in the URL resolver to dedupe the double//.You can run
npx ls-exportsin a package if you'd like to see how many CJS entrypoints are exposed in post-ESM node, for a given package/dir. Clearly everyone wasn't aware of it, but we explicitly discussed it in the modules meeting on more than one occasion, to my recollection.@ljharb what is exposed and what is actually used are two different things though. We still have an opportunity to fix minor issues like this that may have slipped through.
- addedmoduleIssues and PRs related to the module subsystem.Issues and PRs related to the module subsystem.and removedmodules-agendaIssues and PRs to discuss during Modules team meetings.Issues and PRs to discuss during Modules team meetings.
on Sep 1, 2023 github-actions commented
on Jun 27, 2026 on Jun 27, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jun 27, 2026 github-actions commented
on Jul 28, 2026 on Jul 28, 2026 – with GitHub ActionsContributorMore actionsThis issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 120 days).
If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.
@ljharb brought up in the exports patterns PR that it would be worthwhile to ensure the
*matching in exports patterns permits empty matches to ensure consistency with all other wildcard schemes.I agree this conceptual integrity could make sense, and in addition such a feature could be added as a fully backwards compatible change to exports patterns so I would be glad to see this land either way.
One benefit I really liked of not matching the null match is that currently:
will cause
import.meta.resolve('pkg/')to resolve into thesub/folder. As a result this meansimport.meta.resolve('pkg/')is not a reliable way to get a package root (and also relates to the package.json resolution discussion previously).If we now use patterns here:
then as currently written,
import.meta.resolve('pkg/')will throw aPACKAGE_PATH_NOT_EXPORTEDerror because the empty string match is not permitted and thus this "reserves" this space for us to treat it as a special package base resolution case which seems a really useful property for a resolver to have to me in being able to resolve the base of any package this way.On the other hand I do not have any conceptual arguments against matching the empty string pattern other than that I simply can't think of a single use case in which it is useful. If the argument is purely one of conceptual consistency being important I'm all for that though, but would be concerned about invalidating a perfectly good use case in the name of that.