Skip to content

Fix exact "exports" and "imports" keys with no target falling back to a pattern - #1987

Merged
robhogan merged 3 commits into
react:mainfrom
kwy404:fix/exact-exports-key-no-pattern-fallback
Sep 27, 2026
Merged

robhogan merged 3 commits into
react:mainfrom
kwy404:fix/exact-exports-key-no-pattern-fallback

Conversation

@kwy404

@kwy404 kwy404 commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

Summary

matchSubpathFromExportsLike, used for both "exports" and "imports", looks up the exact subpath key first and only tries subpath patterns when there is no exact match. But it detects "no exact match" with target == null, so an exact key that exists but has no target is treated like a missing key. That happens when the value is null, or when it is a conditions object with no matching condition and no default (reduceExportsLikeMap reduces that to null). Metro then goes on to match a less specific pattern.

With this package:

"exports": {
  "./*": "./lib/*.js",
  "./internal": null,
  "./server": {"browser": "./server-browser.js"}
}

test-pkg/internal and test-pkg/server resolve to lib/internal.js and lib/server.js through ./*, with no warning. Node.js only tries patterns when there is no exact key, so it throws ERR_PACKAGE_PATH_NOT_EXPORTED for both. For the same shape in "imports" it throws ERR_PACKAGE_IMPORT_NOT_DEFINED (checked with require.resolve on Node 24.16). Metro already handles null pattern keys this way.

The fix checks whether the exact key exists (has) instead of whether its target is null. These subpaths are now reported as not exported or not resolved, with the usual warning and file-based fallback.

Changelog: [Fix] An exact "exports" or "imports" subpath with a null or unmatched target no longer resolves through a less specific subpath pattern

Test plan

Added a test to packages/metro-resolver/src/__tests__/package-imports-test.js. It uses "#features/*" plus an exact "#features/foo": null and an exact "#features/bar": {"browser": ...}.

  • Before the fix it fails: #features/foo and #features/bar resolve to src/features/foo.js and src/features/bar.js through the pattern.
  • After the fix both log the "could not be resolved" warning and then fail to resolve, as in Node.js.
  • yarn jest packages/metro-resolver passes. scripts/jestFilter.js skips package-exports-test.js and most other resolver suites on Windows, so I also ran all 8 resolver suites with the Windows test fixes from Fix Windows-incompatible Jest tests #1937 applied locally: 125 tests passed. There, the "exports" example above resolved to lib/internal.js and lib/server.js before the fix, and to the warning plus the file-based fallback after it.
  • flow focus-check, eslint and prettier --check on both changed files: clean.

… a pattern

matchSubpathFromExportsLike only tried subpath patterns when the exact
key lookup returned null, so an exact key whose value is null, or a
conditions object with no matching condition, fell through to a less
specific pattern such as "./*". Node.js only tries patterns when there
is no exact key, and reports these subpaths as not exported.

Check whether the exact key exists instead of whether its target is
null.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 26, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Sep 26, 2026
Covers the "exports" side of the fix: an exact key with a null target, and one with no matching condition, alongside a "./*" pattern. Both now warn and fall back to file-based resolution instead of resolving through the pattern.
Comment thread packages/metro-resolver/src/utils/matchSubpathFromExportsLike.js Outdated

@robhogan robhogan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again!

@robhogan
robhogan merged commit f8269d5 into react:main Sep 27, 2026
15 checks passed
kwy404 added a commit to kwy404/kwy404 that referenced this pull request Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants