Skip to content

Esbuild and nodejs module resolution #4144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Karelito00 opened this issue Apr 13, 2025 · 2 comments
Closed

Esbuild and nodejs module resolution #4144

Karelito00 opened this issue Apr 13, 2025 · 2 comments

Comments

@Karelito00
Copy link

I'm using esbuild to build a typescript project. I'm using a dependency in my typescript project that was coded with typescript however was transpiled to js and published like that, the structure of that dependency look like this from node_modules:

node_modules/
└── mydependency/
    ├── package.json
    └── package/
        ├── index.js
        └── utils/
            └── utils.js
            └── index.js
        └── errors/
            └── index.js

In package/index.js the dependency is exporting everything from utils and errors folders. Acting like a module file.

Also there is a something = require("..") in the utils file of the utils folder(package/utils/utils.js). I'm expecting that esbuild resolve the index.js in the parent folder. However is resolving the package.json. When I look at the esbuild verbose logs, I found this:

⬥ [VERBOSE] Resolving import ".." in directory "node_modules/mydependency/package/utils" of type "require-call"
  Attempting to load "node_modules/mydependency/package" as a file
    Checking for file "package"
    Checking for file "package.jsx"
    Checking for file "package.js"
    Checking for file "package.tsx"
    Checking for file "package.ts"
    Checking for file "package.css"
    Checking for file "package.json"
    Found file "package.json"
  Read 3 entries for directory "node_modules/mydependency"
  Primary path is "node_modules/mydependency/package.json" in namespace "file"

After a deep research I understood that node module resolution resolves the relative path ".." like that. But why while developing this dependency(mydependency) doing the import in the typescript file(utils.ts) I don't get this error. Why in typescript do not resolve to package.json? Also why if I run a testing.js file with nodejs(20.9.0) from mydependency folder that call a method in utils.js the require doesn't resolve to package.json an resolves correctly to the index.js in the parent directory (mydependency/package/index.js). But if I bundle this testing file with esbuild it resolves to package.json.

@evanw
Copy link
Owner

evanw commented Apr 13, 2025

why if I run a testing.js file with nodejs(20.9.0) from mydependency folder that call a method in utils.js the require doesn't resolve to package.json an resolves correctly to the index.js in the parent directory (mydependency/package/index.js). But if I bundle this testing file with esbuild it resolves to package.json.

I don't think there's a good reason. That just sounds like a bug with esbuild. Looking at node's algorithm reference, the relevant part might be here:

3. If X is equal to '.', or X begins with './', '/' or '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
   c. THROW "not found"

I'm guessing the specification meant to say something like if X is equal to '.' or '..'. That's what node's isRelative function actually implements. And I'm guessing that the specification is missing something around only running LOAD_AS_FILE(Y + X) if X doesn't end in ... Perhaps that's what the trailingSlash check does.

Thanks for the impressive name collision test case. This looks like a bug with esbuild. In the meantime, the library author should be able to work around it by avoiding the name collision.

@Karelito00
Copy link
Author

Thank you for your response @evanw. While debugging I was also reading the definition of node module resolution and I thought that esbuild was following the algorithm successfully but I couldn't figure out why nodejs was not failing in that case. Now that I read your explanation I'm supposing that's the issue. As well I checked the trailingSlash condition and our case(the relative path '..') meets that condition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants