From c040ad8f30b88cb5723a821deb9ee19ade53644a Mon Sep 17 00:00:00 2001 From: merceyz Date: Thu, 2 Sep 2021 22:22:59 +0200 Subject: [PATCH] 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;