From 1baf9cd1ee90ab26e039643c7658b69c457f5cf8 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 18 Jul 2023 13:10:29 -0700 Subject: [PATCH] Rehome moved requests to real on-disk files When we're about to default resolving outbound from a moved package, we need to rehome the request back to the original package. Previously, we did this by moving the fromFile into the original package, but keeping its own relative path withn the package. This path doesn't actually exist, but that didn't matter to webpack. Unfortunately it does matter to vite, which for dubious reaons checks that the importing file actually exists before being willing to use it as the base for resolution. So instead we need to rehome to a file that exist, so we'll use `package.json` like we generally do when we want to mean "from this package". However, we also need to *undo* this rehoming if the request falls through to our own fallback. Previously that was easy because we still had the true within-package path in the module specifier. Now we need an additional mechanism for propagating extra metadata along with requests. --- packages/core/src/module-resolver.ts | 35 +++++++++++++------ .../webpack/src/webpack-resolver-plugin.ts | 11 ++++-- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/packages/core/src/module-resolver.ts b/packages/core/src/module-resolver.ts index 826957211..604383d79 100644 --- a/packages/core/src/module-resolver.ts +++ b/packages/core/src/module-resolver.ts @@ -107,28 +107,38 @@ type MergeMap = Map[^\/]+)\/(?.*)/; export interface ModuleRequest { - specifier: string; - fromFile: string; - isVirtual: boolean; + readonly specifier: string; + readonly fromFile: string; + readonly isVirtual: boolean; + readonly meta: Record | undefined; alias(newSpecifier: string): this; rehome(newFromFile: string): this; virtualize(virtualFilename: string): this; + withMeta(meta: Record | undefined): this; } class NodeModuleRequest implements ModuleRequest { - constructor(readonly specifier: string, readonly fromFile: string, readonly isVirtual = false) {} + constructor( + readonly specifier: string, + readonly fromFile: string, + readonly isVirtual: boolean, + readonly meta: Record | undefined + ) {} alias(specifier: string): this { - return new NodeModuleRequest(specifier, this.fromFile) as this; + return new NodeModuleRequest(specifier, this.fromFile, false, this.meta) as this; } rehome(fromFile: string): this { if (this.fromFile === fromFile) { return this; } else { - return new NodeModuleRequest(this.specifier, fromFile) as this; + return new NodeModuleRequest(this.specifier, fromFile, false, this.meta) as this; } } - virtualize(filename: string) { - return new NodeModuleRequest(filename, this.fromFile, true) as this; + virtualize(filename: string): this { + return new NodeModuleRequest(filename, this.fromFile, true, this.meta) as this; + } + withMeta(meta: Record | undefined): this { + return new NodeModuleRequest(this.specifier, this.fromFile, this.isVirtual, meta) as this; } } @@ -247,7 +257,7 @@ export class Resolver { | { type: 'virtual'; filename: string; content: string } | { type: 'real'; filename: string } | { type: 'not_found'; err: Error } { - let resolution = this.resolveSync(new NodeModuleRequest(specifier, fromFile), request => { + let resolution = this.resolveSync(new NodeModuleRequest(specifier, fromFile, false, undefined), request => { if (request.isVirtual) { return { type: 'found', @@ -744,7 +754,7 @@ export class Resolver { return logTransition( 'outbound request from moved package', request, - request.rehome(resolve(originalRequestingPkg.root, request.fromFile.slice(requestingPkg.root.length + 1))) + request.withMeta({ wasMovedTo: request.fromFile }).rehome(resolve(originalRequestingPkg.root, 'package.json')) ); } @@ -953,7 +963,10 @@ export class Resolver { // isV2Ember() let movedPkg = this.packageCache.maybeMoved(pkg); if (movedPkg !== pkg) { - fromFile = resolve(movedPkg.root, request.fromFile.slice(pkg.root.length + 1)); + if (!request.meta?.wasMovedTo) { + throw new Error(`bug: embroider resolver's meta is not propagating`); + } + fromFile = request.meta.wasMovedTo as string; pkg = movedPkg; } diff --git a/packages/webpack/src/webpack-resolver-plugin.ts b/packages/webpack/src/webpack-resolver-plugin.ts index 369ec99e5..d53dc6811 100644 --- a/packages/webpack/src/webpack-resolver-plugin.ts +++ b/packages/webpack/src/webpack-resolver-plugin.ts @@ -108,8 +108,9 @@ function getAdaptedResolve( } class WebpackModuleRequest implements ModuleRequest { - specifier: string; - fromFile: string; + readonly specifier: string; + readonly fromFile: string; + readonly meta: Record | undefined; static from(state: any, babelLoaderPrefix: string, appRoot: string): WebpackModuleRequest | undefined { // when the files emitted from our virtual-loader try to import things, @@ -146,6 +147,7 @@ class WebpackModuleRequest implements ModuleRequest { context: string; contextInfo: { issuer: string; + _embroiderMeta?: Record | undefined; }; }, public isVirtual = false @@ -157,6 +159,7 @@ class WebpackModuleRequest implements ModuleRequest { // that can actually be handed back to webpack) this.specifier = state.request; this.fromFile = state.contextInfo.issuer; + this.meta = state.contextInfo._embroiderMeta ? { ...state.contextInfo._embroiderMeta } : undefined; } alias(newSpecifier: string) { @@ -180,4 +183,8 @@ class WebpackModuleRequest implements ModuleRequest { next.isVirtual = true; return next; } + withMeta(meta: Record | undefined): this { + this.state.contextInfo._embroiderMeta = meta; + return new WebpackModuleRequest(this.babelLoaderPrefix, this.appRoot, this.state) as this; + } }