From c040ad8f30b88cb5723a821deb9ee19ade53644a Mon Sep 17 00:00:00 2001 From: merceyz Date: Thu, 2 Sep 2021 22:22:59 +0200 Subject: [PATCH 01/10] fix: find the `pnpapi` the `issuer` belongs to --- lib/PnpPlugin.js | 15 ++++++++++++++- lib/ResolverFactory.js | 17 +++++++++++++++-- lib/util/module-browser.js | 8 ++++++++ package.json | 4 ++-- test/pnp.test.js | 21 ++++++++++++++++++++- types.d.ts | 2 +- 6 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 lib/util/module-browser.js diff --git a/lib/PnpPlugin.js b/lib/PnpPlugin.js index 36f4e3d8..770afe60 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 { @@ -55,6 +55,19 @@ module.exports = class PnpPlugin { 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 + if (resolveContext.log) { + resolveContext.log(`issuer is not managed by the pnpapi`); + } + // FIXME: In Webpack this stops the resolution at + // https://github.com/webpack/enhanced-resolve/blob/029d3e2ce802ef5181355bf64f14f6d0d819ed66/lib/ConditionalPlugin.js#L52-L53 + // instead of continuing with the alternatives + return callback(); + } + if (resolveContext.fileDependencies) { apiResolution = this.pnpApi.resolveToUnqualified("pnpapi", issuer, { considerBuiltins: false diff --git a/lib/ResolverFactory.js b/lib/ResolverFactory.js index 037567bd..edca8765 100644 --- a/lib/ResolverFactory.js +++ b/lib/ResolverFactory.js @@ -6,6 +6,7 @@ "use strict"; const versions = require("process").versions; +const findPnpApi = require("module").findPnpApi; const Resolver = require("./Resolver"); const { getType, PathType } = require("./util/path"); @@ -125,8 +126,20 @@ 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}} */ (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; diff --git a/lib/util/module-browser.js b/lib/util/module-browser.js new file mode 100644 index 00000000..1258c22e --- /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 c08417c6..c2c5a400 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/test/pnp.test.js b/test/pnp.test.js index 5a989539..9aed524e 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,22 @@ 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/a.js", + {}, + (err, result) => { + if (err) return done(err); + result.should.equal(path.resolve(fixture, "../pnp-a/m2/a.js")); + done(); + } + ); + }); it("should handle the exports field when using PnP", done => { pnpApi.mocks.set("m1", path.resolve(fixture, "pkg3")); resolver.resolve( diff --git a/types.d.ts b/types.d.ts index e88d59c2..fb6b2614 100644 --- a/types.d.ts +++ b/types.d.ts @@ -289,7 +289,7 @@ 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) => string | null; } declare interface PossibleFileSystemError { code?: string; From e2211b7ea76691973646901956f6150bd6d51d5a Mon Sep 17 00:00:00 2001 From: merceyz Date: Thu, 30 Sep 2021 23:44:40 +0200 Subject: [PATCH 02/10] chore: lint --- lib/ResolverFactory.js | 2 +- types.d.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/ResolverFactory.js b/lib/ResolverFactory.js index edca8765..99f46b4c 100644 --- a/lib/ResolverFactory.js +++ b/lib/ResolverFactory.js @@ -5,8 +5,8 @@ "use strict"; -const versions = require("process").versions; const findPnpApi = require("module").findPnpApi; +const versions = require("process").versions; const Resolver = require("./Resolver"); const { getType, PathType } = require("./util/path"); diff --git a/types.d.ts b/types.d.ts index fb6b2614..431b42ec 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 | null; + resolveToUnqualified: ( + arg0: string, + arg1: string, + arg2: object + ) => null | string; } declare interface PossibleFileSystemError { code?: string; From 9a9d94c4a453c0cd917973bf9763e6a03e116434 Mon Sep 17 00:00:00 2001 From: merceyz Date: Fri, 8 Oct 2021 23:20:54 +0200 Subject: [PATCH 03/10] fix: fallback to `node_modules` if pnp doesn't control the issuer --- lib/PnpPlugin.js | 25 +++++++++++++++++-------- lib/ResolverFactory.js | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lib/PnpPlugin.js b/lib/PnpPlugin.js index 770afe60..46d019e9 100644 --- a/lib/PnpPlugin.js +++ b/lib/PnpPlugin.js @@ -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) => { @@ -59,13 +62,19 @@ module.exports = class PnpPlugin { if (resolution === null) { // This is either not a PnP managed issuer or it's a Node builtin // Try to continue resolving with our alternatives - if (resolveContext.log) { - resolveContext.log(`issuer is not managed by the pnpapi`); - } - // FIXME: In Webpack this stops the resolution at - // https://github.com/webpack/enhanced-resolve/blob/029d3e2ce802ef5181355bf64f14f6d0d819ed66/lib/ConditionalPlugin.js#L52-L53 - // instead of continuing with the alternatives - return callback(); + 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) { diff --git a/lib/ResolverFactory.js b/lib/ResolverFactory.js index 99f46b4c..4dde9760 100644 --- a/lib/ResolverFactory.js +++ b/lib/ResolverFactory.js @@ -318,6 +318,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"); @@ -459,7 +460,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 ModulesInHierachicDirectoriesPlugin( + "alternate-raw-module", + ["node_modules"], + "module" + ) ); } else { plugins.push( From 1d139584359b79e5b7ec3b4dfa0cefd271fbbfd1 Mon Sep 17 00:00:00 2001 From: merceyz Date: Sat, 25 Mar 2023 23:39:26 +0100 Subject: [PATCH 04/10] fix: use renamed plugin --- lib/ResolverFactory.js | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ResolverFactory.js b/lib/ResolverFactory.js index 4dde9760..f660442e 100644 --- a/lib/ResolverFactory.js +++ b/lib/ResolverFactory.js @@ -469,7 +469,7 @@ exports.createResolver = function (options) { ); plugins.push( - new ModulesInHierachicDirectoriesPlugin( + new ModulesInHierarchicalDirectoriesPlugin( "alternate-raw-module", ["node_modules"], "module" diff --git a/package.json b/package.json index c2c5a400..7647d3c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "enhanced-resolve", "version": "5.15.0", + "packageManager": "yarn@1.22.19", "author": "Tobias Koppers @sokra", "description": "Offers a async require.resolve function. It's highly configurable.", "files": [ From b35d48827d1ad5a4a09313ac5c2059276e5a3c0d Mon Sep 17 00:00:00 2001 From: merceyz Date: Sat, 1 Apr 2023 15:02:47 +0200 Subject: [PATCH 05/10] test: fix test case --- test/pnp.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/pnp.test.js b/test/pnp.test.js index 9aed524e..5499f77e 100644 --- a/test/pnp.test.js +++ b/test/pnp.test.js @@ -260,11 +260,13 @@ describe("pnp", () => { resolver.resolve( {}, path.resolve(__dirname, "fixtures"), - "m2/a.js", + "m2/b.js", {}, (err, result) => { if (err) return done(err); - result.should.equal(path.resolve(fixture, "../pnp-a/m2/a.js")); + result.should.equal( + path.resolve(__dirname, "fixtures/node_modules/m2/b.js") + ); done(); } ); From 0dec9ad2097f110a8f0c5a8347f1b8fd3fb1b61c Mon Sep 17 00:00:00 2001 From: merceyz Date: Wed, 24 May 2023 20:22:37 +0200 Subject: [PATCH 06/10] chore: lint --- lib/ResolverFactory.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ResolverFactory.js b/lib/ResolverFactory.js index f660442e..7fa7a5bf 100644 --- a/lib/ResolverFactory.js +++ b/lib/ResolverFactory.js @@ -126,7 +126,9 @@ function processPnpApiOption(option) { option === undefined && /** @type {NodeJS.ProcessVersions & {pnp: string}} */ versions.pnp ) { - const _findPnpApi = /** @type {function(string): PnpApi | null}} */ (findPnpApi); + const _findPnpApi = /** @type {function(string): PnpApi | null}} */ ( + findPnpApi + ); if (_findPnpApi) { return { resolveToUnqualified(request, issuer, opts) { From 61ca304306435690915e711275511bbd60941599 Mon Sep 17 00:00:00 2001 From: merceyz Date: Wed, 24 May 2023 20:26:15 +0200 Subject: [PATCH 07/10] fix: correct types --- lib/PnpPlugin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/PnpPlugin.js b/lib/PnpPlugin.js index 46d019e9..d3d98bad 100644 --- a/lib/PnpPlugin.js +++ b/lib/PnpPlugin.js @@ -50,9 +50,9 @@ 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, { From 97369bc4c55906476d7ae23c8c349606c082a225 Mon Sep 17 00:00:00 2001 From: merceyz Date: Wed, 24 May 2023 21:44:11 +0200 Subject: [PATCH 08/10] test: use expect --- test/pnp.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pnp.test.js b/test/pnp.test.js index 5499f77e..28280ff6 100644 --- a/test/pnp.test.js +++ b/test/pnp.test.js @@ -264,7 +264,7 @@ describe("pnp", () => { {}, (err, result) => { if (err) return done(err); - result.should.equal( + expect(result).toEqual( path.resolve(__dirname, "fixtures/node_modules/m2/b.js") ); done(); From c53553ce6bcf4c66caf9f0469e3f2075a069c543 Mon Sep 17 00:00:00 2001 From: merceyz Date: Wed, 26 Jul 2023 20:37:31 +0200 Subject: [PATCH 09/10] chore: remove `packageManager` --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 7647d3c5..c2c5a400 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "name": "enhanced-resolve", "version": "5.15.0", - "packageManager": "yarn@1.22.19", "author": "Tobias Koppers @sokra", "description": "Offers a async require.resolve function. It's highly configurable.", "files": [ From bf7b68f2310aa3d9f1d40845b186419096c3661c Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Tue, 27 Feb 2024 18:19:36 +0300 Subject: [PATCH 10/10] refactor: code --- lib/ResolverFactory.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/ResolverFactory.js b/lib/ResolverFactory.js index 7fa7a5bf..59558c7f 100644 --- a/lib/ResolverFactory.js +++ b/lib/ResolverFactory.js @@ -5,7 +5,6 @@ "use strict"; -const findPnpApi = require("module").findPnpApi; const versions = require("process").versions; const Resolver = require("./Resolver"); const { getType, PathType } = require("./util/path"); @@ -126,13 +125,18 @@ function processPnpApiOption(option) { option === undefined && /** @type {NodeJS.ProcessVersions & {pnp: string}} */ versions.pnp ) { - const _findPnpApi = /** @type {function(string): PnpApi | null}} */ ( - findPnpApi - ); + 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;