esbuild does not use typescript source for self-references or sub path imports
Describe the bug
Subpath and self-reference imports are resolved to their literal values rather than the TypeScript source file.
// package.json
{
"name": "subpath-exports",
"exports": {
"./sub": "./dist/sub.js"
},
"imports": {
"#sub": "./dist/sub.js"
}
}
// src/index.ts
import "./sub.js"
import "subpath-exports/sub"
import "#sub"
esbuild will resolve #sub and subpath-exports/sub to ./dist/sub.js, not ./src/sub.ts. This can cause module not found errors if dist has not been produced, or unexpected behavior if the dist/ is out of date and doesn't match the other source.
Reproduction
echo 'import("#sub"); import("subpath-exports/sub")' | npx esbuild --bundle
✘ [ERROR] Could not resolve "#sub"
<stdin>:1:7:
1 │ import("#sub"); import("subpath-exports/sub")
╵ ~~~~~~
The module "./dist/sub.js" was not found on the file system:
package.json:9:12:
9 │ "#sub": "./dist/sub.js"
╵ ~~~~~~~~~~~~~~~
You can mark the path "#sub" as external to exclude it from the bundle, which will remove this
error. You can also add ".catch()" here to handle this failure at run-time instead of bundle-time.
✘ [ERROR] Could not resolve "subpath-exports/sub"
<stdin>:1:23:
1 │ import("#sub"); import("subpath-exports/sub")
╵ ~~~~~~~~~~~~~~~~~~~~~
The module "./dist/sub.js" was not found on the file system:
package.json:6:13:
6 │ "./sub": "./dist/sub.js"
╵ ~~~~~~~~~~~~~~~
You can mark the path "subpath-exports/sub" as external to exclude it from the bundle, which will
remove this error. You can also add ".catch()" here to handle this failure at run-time instead of
bundle-time.
2 errors
https://github.com/everett1992/subpath-exports
Here's the reproduction: link
Note to self: This request is that esbuild should interpret the rootDir, outDir, module, and moduleResolution settings exactly as TypeScript does in this case. TypeScript does the reverse mapping here to discover the location of the original TypeScript code for these imports.
This feature request is likely pretty complicated to implement because TypeScript's behavior here is likely pretty complex as it involves the combinatorial behavior of a lot of different tsconfig.json settings, or at least it would require a lot of research to implement correctly.
Separately of tsconfig, you may want to point subpath exports directly at anticipated output files in a monorepo setting. A workaround for this issue is to add an extra condition (e.g. "source") and pass it to --conditions. Another approach that can work is specifying --external.