Resolve failed when the same name file and directory
sxzz opened this issue · 3 comments
Reproduction: https://github.com/sxzz/esbuild-esm-loader-issue
src/
├── index.ts
├── utils # this is a directory
└── utils.ts
node --loader @esbuild-kit/esm-loader src/index.ts
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '/path/esbuild-esm-loader-issue/src/utils' is not supported resolving ES modules imported from /path/esbuild-esm-loader-issue/src/index.ts
at __node_internal_captureLargerStackTrace (node:internal/errors:465:5)
at new NodeError (node:internal/errors:372:5)
at finalizeResolution (node:internal/modules/esm/resolve:433:17)
at moduleResolve (node:internal/modules/esm/resolve:1009:10)
at defaultResolve (node:internal/modules/esm/resolve:1218:11)
at i (file:///path/esbuild-esm-loader-issue/node_modules/.pnpm/@esbuild-kit+esm-loader@2.1.0/node_modules/@esbuild-kit/esm-loader/dist/index.js:87:17)
at ESMLoader.resolve (node:internal/modules/esm/loader:580:30)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:294:18)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:80:40)
at link (node:internal/modules/esm/module_job:78:36) {
code: 'ERR_UNSUPPORTED_DIR_IMPORT',
url: 'file:///path/esbuild-esm-loader-issue/src/utils'
}
If rename or remove src/utils
, it works.
IMHO, the problem caused by here.
Lines 79 to 81 in 0d64195
Hmm, I'm not sure if this is a bug.
When you import a path ./utils
, and it explicitly matches a directory name, I think that should take precedence over an implicit file name match.
Besides, since this is how Node.js resolves it (rename your files to .js
and run node src/index.js
), changing this behavior will introduce a breaking change to how native ESM resolves files.
I think a better way is to be consistent with ts-node
, esbuild
and esmo
(<0.14.x).
-
If you try to click the import path with ctrl key, the VSCode will jump to
src/utils.ts
. We should respect resolution algorithm of TypeScript. -
esbuild Demo
> esbuild src/index.ts --bundle
(() => { // src/utils.ts var foo = "bar"; // src/index.ts console.log(foo); })();
Also, native ESM has no default extension and resolve index
, so changing .ts to .js directly will not work. (even if the utils
folder does not exist)
To use Node.js's classic resolution algorithm, you can use the --experimental-specifier-resolution=node
flag:
$ node --loader @esbuild-kit/esm-loader --experimental-specifier-resolution=node src/index.js
(node:34643) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
(node:34643) ExperimentalWarning: The Node.js specifier resolution flag is experimental. It could change or be removed at any time.
bar
Or with tsx:
$ npx tsx --experimental-specifier-resolution=node src/index.js
bar
With this flag, users have a way to toggle between both resolution algorithms. If we override the default behavior to force Node's classic resolution algorithm, users will be limited to one behavior. For this reason, I don't think we should change it.
I agree we should try to resolve /index.js
instead of /index
though. Hasn't happened yet but it's bound to. Happy to accept a PR to fix that.