Repository: webpack/enhanced-resolve
Pull request #301 (2021-09-02 20:35:14)

fix: find the `pnpapi` the `issuer` belongs to
**What's the problem this PR addresses?**

- In some cases `enhanced-resolve` is outside the control of the `pnpapi` and can't require it
- The `issuer` might not belong to the same `pnpapi` as `enhanced-resolve`
- The `issuer` might not belong to a `pnpapi` at all and should use the `node_modules` resolution instead

Fixes https://github.com/arcanis/pnp-webpack-plugin/issues/32 for Webpack 5

**How did you fix it?**

Use `module.findPnpApi` to locate the correct `pnpapi` for the `issuer`, if a `pnpapi` isn't found continue the normal resolution

linux-foundation-easycla[bot]: <a href="https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/18915764/5400204/301/#/?version=2"><img src="https://s3.amazonaws.com/cla-project-logo-prod/cla-not-signed.svg" alt="CLA Not Signed" align="left" height="28" width="328" ></a><br/><br /><ul><li><a href='https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/18915764/5400204/301/#/?version=2' target='_blank'>:x:</a> - Kristoffer K. The commit (05d77ef3dbb294aac22dd50565ed69d89f0b9c95) is not authorized under a signed CLA. <a href='https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/18915764/5400204/301/#/?version=2' target='_blank'>Please click here to be authorized</a>. For further assistance with EasyCLA, <a href='https://jira.linuxfoundation.org/servicedesk/customer/portal/4' target='_blank'>please submit a support request ticket</a>.</li></ul>
alexander-akait: I think better to fix it on yarn side?
jgornick: > I think better to fix it on yarn side?

@alexander-akait Can you elaborate on this how it could be fixed on the yarn side? Thank you for your input!
merceyz: It's not really a bug on our side, `require('pnpapi')` is supposed to return the `pnpapi` that the `issuer` (`enhanced-resolve` in this case) belongs to so it's working as intended
jgornick: @sokra @alexander-akait  ^^^ Bump 😄 
codecov[bot]: # [Codecov](https://codecov.io/gh/webpack/enhanced-resolve/pull/301?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack) Report
> Merging [#301](https://codecov.io/gh/webpack/enhanced-resolve/pull/301?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack) (05d77ef) into [main](https://codecov.io/gh/webpack/enhanced-resolve/commit/60d79f3c93304ce5ecbbe0127aa583d4a73bf1a1?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack) (60d79f3) will **decrease** coverage by `0.40%`.
> The diff coverage is `33.33%`.

[![Impacted file tree graph](https://codecov.io/gh/webpack/enhanced-resolve/pull/301/graphs/tree.svg?width=650&height=150&src=pr&token=tgdM0Gr6Ub&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack)](https://codecov.io/gh/webpack/enhanced-resolve/pull/301?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack)

```diff
@@            Coverage Diff             @@
##             main     #301      +/-   ##
==========================================
- Coverage   94.93%   94.53%   -0.41%     
==========================================
  Files          39       39              
  Lines        1580     1591      +11     
==========================================
+ Hits         1500     1504       +4     
- Misses         80       87       +7     
```


| [Impacted Files](https://codecov.io/gh/webpack/enhanced-resolve/pull/301?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack) | Coverage Δ | |
|---|---|---|
| [lib/ResolverFactory.js](https://codecov.io/gh/webpack/enhanced-resolve/pull/301/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack#diff-bGliL1Jlc29sdmVyRmFjdG9yeS5qcw==) | `93.92% <12.50%> (-3.21%)` | :arrow_down: |
| [lib/PnpPlugin.js](https://codecov.io/gh/webpack/enhanced-resolve/pull/301/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack#diff-bGliL1BucFBsdWdpbi5qcw==) | `86.11% <75.00%> (-1.39%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/webpack/enhanced-resolve/pull/301?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/webpack/enhanced-resolve/pull/301?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack). Last update [60d79f3...05d77ef](https://codecov.io/gh/webpack/enhanced-resolve/pull/301?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=webpack).

jgornick: @alexander-akait @sokra Just wanted to check-in again if you could help provide any insight on how to approach a fix for this issue? Again, I'm more than willing to help fix it too.

I've tried digging into this to figure out another way to help fallback to alternatives, but with the plugin system, I was getting lost as to how the flow of resolution works and where one might be able to intersect and fallback. I've also reached out to @arcanis to help provide any insight, and I think we're all kind of stuck.

Anything would be greatly appreciated! Thank you!
alexander-akait: Let's wait @arcanis answer, I am not against these changes
sokra: How to reproduce a scenario where you have packages that are yarn managed and packages that are non-yarn managed?
jgornick: > How to reproduce a scenario where you have packages that are yarn managed and packages that are non-yarn managed?

@sokra I'm sorry for not including that. Here's a link to a repo to reproduce that's using this patch as the fix: https://github.com/jgornick/yarn-webpack-node-modules-to-pnp
jgornick: > > How to reproduce a scenario where you have packages that are yarn managed and packages that are non-yarn managed?
> 
> @sokra I'm sorry for not including that. Here's a link to a repo to reproduce that's using this patch as the fix: https://github.com/jgornick/yarn-webpack-node-modules-to-pnp

@sokra Please let me know if there's anything else I can provide or help with 😄 
jgornick: @sokra @alexander-akait ^^^ Bump again 😄 

Specifically looking for any information with how to resolve https://github.com/webpack/enhanced-resolve/pull/301#discussion_r701406073. I have a reproducible repository setup at https://github.com/jgornick/yarn-webpack-node-modules-to-pnp

Thank you!
arcanis: > Let's wait @arcanis answer, I am not against these changes

Those changes seem reasonable to me (note that @merceyz is a core contributor on Yarn 🙂).
alexander-akait: @jgornick Can you fix lint?
jgornick: I'll try to look at adding tests sometime today. 

Is it fair to say that out of the `PnpPlugin`, if it can't resolve a module that it should indeed [call the callback without any arguments](https://github.com/webpack/enhanced-resolve/pull/301/files#diff-484df5a516d012258b8eb71e51625ef132b1c571ef3756b7c45433f4365e2e69R64)? Or is there a better way we can tell enhanced-resolve to try fallbacks?

cc @sokra @alexander-akait 
jgornick: @sokra and @alexander-akait ... There should be a commit coming from @merceyz that should fix this issue so that if PnP is available, but still can't resolve a module, it'll fallback to trying node_modules again.

The only question I have is how can I satisfy the code coverage issues, especially in [ResolverFactory](https://github.com/webpack/enhanced-resolve/pull/301/files#diff-7038853204325667ba3c6bff3b947028d7b2bf7a137cfc8074b87ca033dc0a67R121)? In order to test this, we'd have to mock a module so that the `findPnpApi` method is available. However, I don't see any other examples of that in the codebase, which makes me think it's an anti-pattern too 😄 

One option I was thinking of is what if we made the `findPnpApi` an `option` coming into the resolver factory so that it could be provided too? Please let me know what you think so I can finish this PR up 😄 

Thank you!

- Joe
webpack-bot: <!-- identifier: review-outdated -->

@merceyz Thanks for your update.

I labeled the Pull Request so reviewers will review it again.

@alexander-akait Please review the new changes.
jgornick: For what it's worth @sokra, we've been using @merceyz's fix since October and haven't run into any issues. Is there any chance this can make it in?
jgornick: Bump @sokra and @alexander-akait 

My understanding is that we're only waiting on approvals? Any help or guidance to get this moving forward and merged into a release would be greatly appreciated!
jgornick: Bump @sokra and @alexander-akait 

Any chance we can get guidance on next steps here?
jgornick: @sokra, @alexander-akait or @vankop Can you provide any sort of feedback for this PR? As mentioned above, we've been using @merceyz's branch build of enhanced-resolve for over a year and fixed the particular issue described in this PR.

Again, if there's anything I can do to help merge this in, I'm more than willing to help! 

Please let me know either way.
jgornick: Bump @sokra, @alexander-akait or @vankop

Just wanting to know next steps for us here. 
jgornick: Thank you @alexander-akait for resetting this PR. I'm taking a look at the failing lint/tests.
alexander-akait: Tests failed, can someone take a look and fix it?
alexander-akait: @merceyz @jgornick Friendly ping :smile: 
jgornick: @alexander-akait Thank you! I’ll make some time this weekend. 
webpack-bot: <!-- identifier: review-outdated -->

@merceyz Thanks for your update.

I labeled the Pull Request so reviewers will review it again.

@TheLarkInn Please review the new changes.
jgornick: @merceyz You're too quick 😛 Thank you very much for getting this squared away!
alexander-akait: @TheLarkInn Ready to review
alexander-akait: @merceyz Sorry again and again, let's rebase, thank you very much

Patch:
diff --git a/lib/PnpPlugin.js b/lib/PnpPlugin.js
index 36f4e3d..d3d98ba 100644
--- a/lib/PnpPlugin.js
+++ b/lib/PnpPlugin.js
@@ -10,7 +10,7 @@
 /** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */
 /**
  * @typedef {Object} PnpApiImpl
- * @property {function(string, string, object): string} resolveToUnqualified
+ * @property {function(string, string, object): string | null} resolveToUnqualified
  */
 
 module.exports = class PnpPlugin {
@@ -18,11 +18,13 @@ module.exports = class PnpPlugin {
 	 * @param {string | ResolveStepHook} source source
 	 * @param {PnpApiImpl} pnpApi pnpApi
 	 * @param {string | ResolveStepHook} target target
+	 * @param {string | ResolveStepHook} alternateTarget alternateTarget
 	 */
-	constructor(source, pnpApi, target) {
+	constructor(source, pnpApi, target, alternateTarget) {
 		this.source = source;
 		this.pnpApi = pnpApi;
 		this.target = target;
+		this.alternateTarget = alternateTarget;
 	}
 
 	/**
@@ -32,6 +34,7 @@ module.exports = class PnpPlugin {
 	apply(resolver) {
 		/** @type {ResolveStepHook} */
 		const target = resolver.ensureHook(this.target);
+		const alternateTarget = resolver.ensureHook(this.alternateTarget);
 		resolver
 			.getHook(this.source)
 			.tapAsync("PnpPlugin", (request, resolveContext, callback) => {
@@ -47,14 +50,33 @@ module.exports = class PnpPlugin {
 				const packageName = packageMatch[0];
 				const innerRequest = `.${req.slice(packageName.length)}`;
 
-				/** @type {string|undefined} */
+				/** @type {string|undefined|null} */
 				let resolution;
-				/** @type {string|undefined} */
+				/** @type {string|undefined|null} */
 				let apiResolution;
 				try {
 					resolution = this.pnpApi.resolveToUnqualified(packageName, issuer, {
 						considerBuiltins: false
 					});
+
+					if (resolution === null) {
+						// This is either not a PnP managed issuer or it's a Node builtin
+						// Try to continue resolving with our alternatives
+						resolver.doResolve(
+							alternateTarget,
+							request,
+							"issuer is not managed by a pnpapi",
+							resolveContext,
+							(err, result) => {
+								if (err) return callback(err);
+								if (result) return callback(null, result);
+								// Skip alternatives
+								return callback(null, null);
+							}
+						);
+						return;
+					}
+
 					if (resolveContext.fileDependencies) {
 						apiResolution = this.pnpApi.resolveToUnqualified("pnpapi", issuer, {
 							considerBuiltins: false
diff --git a/lib/ResolverFactory.js b/lib/ResolverFactory.js
index 037567b..59558c7 100644
--- a/lib/ResolverFactory.js
+++ b/lib/ResolverFactory.js
@@ -125,8 +125,27 @@ function processPnpApiOption(option) {
 		option === undefined &&
 		/** @type {NodeJS.ProcessVersions & {pnp: string}} */ versions.pnp
 	) {
-		// @ts-ignore
-		return require("pnpapi"); // eslint-disable-line node/no-missing-require
+		const _findPnpApi =
+			/** @type {function(string): PnpApi | null}} */
+			(
+				// @ts-ignore
+				require("module").findPnpApi
+			);
+
+		if (_findPnpApi) {
+			return {
+				resolveToUnqualified(request, issuer, opts) {
+					const pnpapi = _findPnpApi(issuer);
+
+					if (!pnpapi) {
+						// Issuer isn't managed by PnP
+						return null;
+					}
+
+					return pnpapi.resolveToUnqualified(request, issuer, opts);
+				}
+			};
+		}
 	}
 
 	return option || null;
@@ -305,6 +324,7 @@ exports.createResolver = function (options) {
 	resolver.ensureHook("normalResolve");
 	resolver.ensureHook("internal");
 	resolver.ensureHook("rawModule");
+	resolver.ensureHook("alternateRawModule");
 	resolver.ensureHook("module");
 	resolver.ensureHook("resolveAsModule");
 	resolver.ensureHook("undescribedResolveInPackage");
@@ -446,7 +466,20 @@ exports.createResolver = function (options) {
 					)
 				);
 				plugins.push(
-					new PnpPlugin("raw-module", pnpApi, "undescribed-resolve-in-package")
+					new PnpPlugin(
+						"raw-module",
+						pnpApi,
+						"undescribed-resolve-in-package",
+						"alternate-raw-module"
+					)
+				);
+
+				plugins.push(
+					new ModulesInHierarchicalDirectoriesPlugin(
+						"alternate-raw-module",
+						["node_modules"],
+						"module"
+					)
 				);
 			} else {
 				plugins.push(
diff --git a/lib/util/module-browser.js b/lib/util/module-browser.js
new file mode 100644
index 0000000..1258c22
--- /dev/null
+++ b/lib/util/module-browser.js
@@ -0,0 +1,8 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+module.exports = {};
diff --git a/package.json b/package.json
index c08417c..c2c5a40 100644
--- a/package.json
+++ b/package.json
@@ -9,8 +9,8 @@
     "LICENSE"
   ],
   "browser": {
-    "pnpapi": false,
-    "process": "./lib/util/process-browser.js"
+    "process": "./lib/util/process-browser.js",
+    "module": "./lib/util/module-browser.js"
   },
   "dependencies": {
     "graceful-fs": "^4.2.4",
diff --git a/types.d.ts b/types.d.ts
index e88d59c..431b42e 100644
--- a/types.d.ts
+++ b/types.d.ts
@@ -289,7 +289,11 @@ type Plugin =
 	| { apply: (arg0: Resolver) => void }
 	| ((this: Resolver, arg1: Resolver) => void);
 declare interface PnpApiImpl {
-	resolveToUnqualified: (arg0: string, arg1: string, arg2: object) => string;
+	resolveToUnqualified: (
+		arg0: string,
+		arg1: string,
+		arg2: object
+	) => null | string;
 }
 declare interface PossibleFileSystemError {
 	code?: string;
diff --git a/yarn.lock b/yarn.lock
index 17abd8d..0a1eb04 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -34,14 +34,6 @@
   dependencies:
     "@babel/highlight" "^7.18.6"
 
-"@babel/code-frame@^7.22.13":
-  version "7.22.13"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
-  integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
-  dependencies:
-    "@babel/highlight" "^7.22.13"
-    chalk "^2.4.2"
-
 "@babel/compat-data@^7.21.5":
   version "7.21.7"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.7.tgz#61caffb60776e49a57ba61a88f02bedd8714f6bc"
@@ -78,16 +70,6 @@
     "@jridgewell/trace-mapping" "^0.3.17"
     jsesc "^2.5.1"
 
-"@babel/generator@^7.23.0":
-  version "7.23.0"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
-  integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
-  dependencies:
-    "@babel/types" "^7.23.0"
-    "@jridgewell/gen-mapping" "^0.3.2"
-    "@jridgewell/trace-mapping" "^0.3.17"
-    jsesc "^2.5.1"
-
 "@babel/helper-compilation-targets@^7.21.5":
   version "7.21.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz#631e6cc784c7b660417421349aac304c94115366"
@@ -104,25 +86,20 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz#c769afefd41d171836f7cb63e295bedf689d48ba"
   integrity sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ==
 
-"@babel/helper-environment-visitor@^7.22.20":
-  version "7.22.20"
-  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
-  integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
-
-"@babel/helper-function-name@^7.23.0":
-  version "7.23.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
-  integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
+"@babel/helper-function-name@^7.21.0":
+  version "7.21.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4"
+  integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==
   dependencies:
-    "@babel/template" "^7.22.15"
-    "@babel/types" "^7.23.0"
+    "@babel/template" "^7.20.7"
+    "@babel/types" "^7.21.0"
 
-"@babel/helper-hoist-variables@^7.22.5":
-  version "7.22.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
-  integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+"@babel/helper-hoist-variables@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
+  integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
   dependencies:
-    "@babel/types" "^7.22.5"
+    "@babel/types" "^7.18.6"
 
 "@babel/helper-module-imports@^7.21.4":
   version "7.21.4"
@@ -164,33 +141,16 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
-"@babel/helper-split-export-declaration@^7.22.6":
-  version "7.22.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
-  integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
-  dependencies:
-    "@babel/types" "^7.22.5"
-
 "@babel/helper-string-parser@^7.21.5":
   version "7.21.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz#2b3eea65443c6bdc31c22d037c65f6d323b6b2bd"
   integrity sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==
 
-"@babel/helper-string-parser@^7.22.5":
-  version "7.22.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
-  integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
-
 "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
   version "7.19.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
   integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
 
-"@babel/helper-validator-identifier@^7.22.20":
-  version "7.22.20"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
-  integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
-
 "@babel/helper-validator-option@^7.21.0":
   version "7.21.0"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180"
@@ -214,25 +174,11 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
-"@babel/highlight@^7.22.13":
-  version "7.22.20"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
-  integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.22.20"
-    chalk "^2.4.2"
-    js-tokens "^4.0.0"
-
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.8":
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.5", "@babel/parser@^7.21.8":
   version "7.21.8"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.8.tgz#642af7d0333eab9c0ad70b14ac5e76dbde7bfdf8"
   integrity sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==
 
-"@babel/parser@^7.22.15", "@babel/parser@^7.23.0":
-  version "7.23.0"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
-  integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
-
 "@babel/plugin-syntax-async-generators@^7.8.4":
   version "7.8.4"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@@ -333,32 +279,23 @@
     "@babel/parser" "^7.20.7"
     "@babel/types" "^7.20.7"
 
-"@babel/template@^7.22.15":
-  version "7.22.15"
-  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
-  integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
-  dependencies:
-    "@babel/code-frame" "^7.22.13"
-    "@babel/parser" "^7.22.15"
-    "@babel/types" "^7.22.15"
-
 "@babel/traverse@^7.21.5", "@babel/traverse@^7.7.2":
-  version "7.23.2"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
-  integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
-  dependencies:
-    "@babel/code-frame" "^7.22.13"
-    "@babel/generator" "^7.23.0"
-    "@babel/helper-environment-visitor" "^7.22.20"
-    "@babel/helper-function-name" "^7.23.0"
-    "@babel/helper-hoist-variables" "^7.22.5"
-    "@babel/helper-split-export-declaration" "^7.22.6"
-    "@babel/parser" "^7.23.0"
-    "@babel/types" "^7.23.0"
+  version "7.21.5"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.5.tgz#ad22361d352a5154b498299d523cf72998a4b133"
+  integrity sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==
+  dependencies:
+    "@babel/code-frame" "^7.21.4"
+    "@babel/generator" "^7.21.5"
+    "@babel/helper-environment-visitor" "^7.21.5"
+    "@babel/helper-function-name" "^7.21.0"
+    "@babel/helper-hoist-variables" "^7.18.6"
+    "@babel/helper-split-export-declaration" "^7.18.6"
+    "@babel/parser" "^7.21.5"
+    "@babel/types" "^7.21.5"
     debug "^4.1.0"
     globals "^11.1.0"
 
-"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
+"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.4", "@babel/types@^7.21.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
   version "7.21.5"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.5.tgz#18dfbd47c39d3904d5db3d3dc2cc80bedb60e5b6"
   integrity sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==
@@ -367,15 +304,6 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
-"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0":
-  version "7.23.0"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
-  integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
-  dependencies:
-    "@babel/helper-string-parser" "^7.22.5"
-    "@babel/helper-validator-identifier" "^7.22.20"
-    to-fast-properties "^2.0.0"
-
 "@bcoe/v8-coverage@^0.2.3":
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@@ -1217,7 +1145,7 @@ caniuse-lite@^1.0.30001449:
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001488.tgz#d19d7b6e913afae3e98f023db97c19e9ddc5e91f"
   integrity sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==
 
-chalk@^2.0.0, chalk@^2.4.2:
+chalk@^2.0.0:
   version "2.4.2"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
   integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -3516,14 +3444,14 @@ semver-compare@^1.0.0:
   integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==
 
 semver@^6.0.0, semver@^6.1.0, semver@^6.3.0:
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
-  integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
 
 semver@^7.2.1, semver@^7.3.2, semver@^7.3.4:
-  version "7.5.4"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
-  integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+  version "7.5.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.1.tgz#c90c4d631cf74720e46b21c1d37ea07edfab91ec"
+  integrity sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==
   dependencies:
     lru-cache "^6.0.0"
 
@@ -3815,9 +3743,9 @@ tooling@webpack/tooling#v1.14.0:
     yargs "^16.1.1"
 
 tough-cookie@^4.0.0:
-  version "4.1.3"
-  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
-  integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874"
+  integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==
   dependencies:
     psl "^1.1.33"
     punycode "^2.1.1"
@@ -4006,9 +3934,9 @@ which@^2.0.1:
     isexe "^2.0.0"
 
 word-wrap@^1.2.3, word-wrap@~1.2.3:
-  version "1.2.4"
-  resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
-  integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
+  integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
 
 wrap-ansi@^6.2.0:
   version "6.2.0"


Test patch:
diff --git a/test/pnp.test.js b/test/pnp.test.js
index 5a98953..28280ff 100644
--- a/test/pnp.test.js
+++ b/test/pnp.test.js
@@ -35,8 +35,11 @@ describe("pnp", () => {
 	beforeEach(() => {
 		pnpApi = /** @type {any} */ ({
 			mocks: new Map(),
+			ignoredIssuers: new Set(),
 			resolveToUnqualified(request, issuer) {
-				if (pnpApi.mocks.has(request)) {
+				if (pnpApi.ignoredIssuers.has(issuer)) {
+					return null;
+				} else if (pnpApi.mocks.has(request)) {
 					return pnpApi.mocks.get(request);
 				} else {
 					const err = /** @type {any} */ (new Error(`No way`));
@@ -250,6 +253,24 @@ describe("pnp", () => {
 			}
 		);
 	});
+	it("should fallback to alternatives when pnp doesn't manage the issuer", done => {
+		pnpApi.ignoredIssuers.add(path.resolve(__dirname, "fixtures") + "/");
+		// Add the wrong path on purpose to make sure the issuer is ignored
+		pnpApi.mocks.set("m2", path.resolve(fixture, "pkg"));
+		resolver.resolve(
+			{},
+			path.resolve(__dirname, "fixtures"),
+			"m2/b.js",
+			{},
+			(err, result) => {
+				if (err) return done(err);
+				expect(result).toEqual(
+					path.resolve(__dirname, "fixtures/node_modules/m2/b.js")
+				);
+				done();
+			}
+		);
+	});
 	it("should handle the exports field when using PnP", done => {
 		pnpApi.mocks.set("m1", path.resolve(fixture, "pkg3"));
 		resolver.resolve(