1
1
import type { Plugin as EsBuildPlugin } from 'esbuild' ;
2
2
import { type PluginItem , transform } from '@babel/core' ;
3
- import { ResolverLoader , virtualContent , locateEmbroiderWorkingDir } from '@embroider/core' ;
3
+ import { ResolverLoader , virtualContent , locateEmbroiderWorkingDir , explicitRelative } from '@embroider/core' ;
4
4
import { readFileSync , readJSONSync } from 'fs-extra' ;
5
5
import { EsBuildModuleRequest } from './esbuild-request' ;
6
6
import assertNever from 'assert-never' ;
7
- import { resolve } from 'path' ;
7
+ import { dirname , isAbsolute , resolve } from 'path' ;
8
8
import { hbsToJS } from '@embroider/core' ;
9
9
import { Preprocessor } from 'content-tag' ;
10
10
@@ -32,10 +32,11 @@ export function esBuildResolver(root = process.cwd()): EsBuildPlugin {
32
32
let firstFailure ;
33
33
34
34
for ( let candidate of candidates ( path ) ) {
35
- let result = await build . resolve ( candidate , {
35
+ let { specifier, fromFile } = adjustVirtualImport ( candidate , importer ) ;
36
+ let result = await build . resolve ( specifier , {
36
37
namespace,
37
38
resolveDir,
38
- importer,
39
+ importer : fromFile ,
39
40
kind,
40
41
pluginData : { ...pluginData , embroiderExtensionSearch : true } ,
41
42
} ) ;
@@ -52,7 +53,8 @@ export function esBuildResolver(root = process.cwd()): EsBuildPlugin {
52
53
return firstFailure ;
53
54
} ) ;
54
55
build . onResolve ( { filter : / ./ } , async ( { path, importer, pluginData, kind } ) => {
55
- let request = EsBuildModuleRequest . from ( build , kind , path , importer , pluginData ) ;
56
+ let { specifier, fromFile } = adjustVirtualImport ( path , importer ) ;
57
+ let request = EsBuildModuleRequest . from ( build , kind , specifier , fromFile , pluginData ) ;
56
58
if ( ! request ) {
57
59
return null ;
58
60
}
@@ -132,3 +134,28 @@ function runMacros(src: string, filename: string, macrosConfig: PluginItem): str
132
134
plugins : [ macrosConfig ] ,
133
135
} ) ! . code ! ;
134
136
}
137
+
138
+ // esbuild's resolve does not like when we resolve from virtual paths. That is,
139
+ // a request like "../thing.js" from "/a/real/path/VIRTUAL_SUBDIR/virtual.js"
140
+ // has an unambiguous target of "/a/real/path/thing.js", but esbuild won't do
141
+ // that path adjustment until after checking whether VIRTUAL_SUBDIR actually
142
+ // exists.
143
+ //
144
+ // We can do the path adjustments before doing resolve.
145
+ function adjustVirtualImport ( specifier : string , fromFile : string ) : { specifier : string ; fromFile : string } {
146
+ let fromDir = dirname ( fromFile ) ;
147
+ if ( ! isAbsolute ( specifier ) && specifier . startsWith ( '.' ) ) {
148
+ let targetPath = resolve ( fromDir , specifier ) ;
149
+ let newFromDir = dirname ( targetPath ) ;
150
+ if ( fromDir !== newFromDir ) {
151
+ return {
152
+ specifier : explicitRelative ( newFromDir , targetPath ) ,
153
+ // we're resolving *from* the destination, because we need to resolve
154
+ // from a file that exists, and we know that (if this was supposed to
155
+ // succeed at all) that file definitely does
156
+ fromFile : targetPath ,
157
+ } ;
158
+ }
159
+ }
160
+ return { specifier, fromFile } ;
161
+ }
0 commit comments