Skip to content
This repository has been archived by the owner on Oct 18, 2023. It is now read-only.

Resolve failed when the same name file and directory #13

Closed
sxzz opened this issue May 20, 2022 · 3 comments · Fixed by #16 or #17
Closed

Resolve failed when the same name file and directory #13

sxzz opened this issue May 20, 2022 · 3 comments · Fixed by #16 or #17

Comments

@sxzz
Copy link

sxzz commented May 20, 2022

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.

if ((error as any).code === 'ERR_UNSUPPORTED_DIR_IMPORT') {
return resolve(`${specifier}/index`, context, defaultResolve);
}

@privatenumber
Copy link
Member

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.

@sxzz
Copy link
Author

sxzz commented May 21, 2022

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)

@privatenumber
Copy link
Member

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
2 participants