Skip to content
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

Unable to resolve files with CLI but works from file config #3652

Closed
ChrisMBarr opened this issue Feb 16, 2024 · 5 comments
Closed

Unable to resolve files with CLI but works from file config #3652

ChrisMBarr opened this issue Feb 16, 2024 · 5 comments

Comments

@ChrisMBarr
Copy link

ChrisMBarr commented Feb 16, 2024

I ran into a strange issue which at first appeared to be the same as #1101 .
I have a Node project (Express server) in a monorepo structured like this:

├── package.json (root level)
├── angular-app-1/
├── angular-app-2/
└── server
    ├── package.json
    ├── tsconfig.json
    ├── src/

Locally I could build just fine with this in my /server/package.json

"build": "esbuild src/** --bundle --platform=node --outdir=dist --minify --log-level=debug"

No issues, but when I made a PR on github we have an action that runs the above build script, but it would fail with a bunch of errors like this

● [DEBUG] Resolving import "src/controllers" in directory "/home/runner/work/my-proj/my-proj/server" of type "entry-point"

  Checking for package alias matches
    Failed to find any package alias matches
  Read 14 entries for directory "/home/runner/work/my-proj/my-proj/server"
  Searching for "src/controllers" in "node_modules" directories starting from "/home/runner/work/my-proj/my-proj/server"
    Matching "src/controllers" against "paths" in "/home/runner/work/my-proj/my-proj/server/tsconfig.json"
      Using "/home/runner/work/my-proj/my-proj/server" as "baseURL"
    Attempting to load "/home/runner/work/my-proj/my-proj/server/src/controllers" as a file
      Checking for file "controllers"
      Checking for file "controllers.tsx"
      Checking for file "controllers.ts"
      Checking for file "controllers.jsx"
      Checking for file "controllers.js"
      Checking for file "controllers.css"
      Checking for file "controllers.json"
      Failed to find file "controllers"
    Attempting to load "/home/runner/work/my-proj/my-proj/server/src/controllers" as a directory
      Read 9 entries for directory "/home/runner/work/my-proj/my-proj/server/src"
      Read 4 entries for directory "/home/runner/work/my-proj/my-proj/server/src/controllers"
      Failed to find file "/home/runner/work/my-proj/my-proj/server/src/controllers/index.tsx"
      Failed to find file "/home/runner/work/my-proj/my-proj/server/src/controllers/index.ts"
      Failed to find file "/home/runner/work/my-proj/my-proj/server/src/controllers/index.jsx"
      Failed to find file "/home/runner/work/my-proj/my-proj/server/src/controllers/index.js"
      Failed to find file "/home/runner/work/my-proj/my-proj/server/src/controllers/index.css"
      Failed to find file "/home/runner/work/my-proj/my-proj/server/src/controllers/index.json"
    Parsed package name "src" and package subpath "./controllers"
    Checking for a package in the directory "/home/runner/work/my-proj/my-proj/server/node_modules/src/controllers"
    Read 14 entries for directory "/home/runner/work/my-proj/my-proj/server"
    Read 391 entries for directory "/home/runner/work/my-proj/my-proj/server/node_modules"
    Failed to read directory "/home/runner/work/my-proj/my-proj/server/node_modules/src": open /home/runner/work/my-proj/my-proj/server/node_modules/src: no such file or directory
    Failed to read directory "/home/runner/work/my-proj/my-proj/server/node_modules/src"
    Attempting to load "/home/runner/work/my-proj/my-proj/server/node_modules/src/controllers" as a file
      Failed to read directory "/home/runner/work/my-proj/my-proj/server/node_modules/src": open /home/runner/work/my-proj/my-proj/server/node_modules/src: no such file or directory
    Attempting to load "/home/runner/work/my-proj/my-proj/server/node_modules/src/controllers" as a directory
      Failed to read directory "/home/runner/work/my-proj/my-proj/server/node_modules/src"
      Failed to read directory "/home/runner/work/my-proj/my-proj/server/node_modules/src/controllers"
    Checking for a package in the directory "/home/runner/work/my-proj/my-proj/node_modules/src/controllers"
    Read 14 entries for directory "/home/runner/work/my-proj/my-proj"
    Read 33 entries for directory "/home/runner/work/my-proj/my-proj/node_modules"
    Failed to read directory "/home/runner/work/my-proj/my-proj/node_modules/src": open /home/runner/work/my-proj/my-proj/node_modules/src: no such file or directory
    Failed to read directory "/home/runner/work/my-proj/my-proj/node_modules/src"
    Attempting to load "/home/runner/work/my-proj/my-proj/node_modules/src/controllers" as a file
      Failed to read directory "/home/runner/work/my-proj/my-proj/node_modules/src": open /home/runner/work/my-proj/my-proj/node_modules/src: no such file or directory
    Attempting to load "/home/runner/work/my-proj/my-proj/node_modules/src/controllers" as a directory
      Failed to read directory "/home/runner/work/my-proj/my-proj/node_modules/src"
      Failed to read directory "/home/runner/work/my-proj/my-proj/node_modules/src/controllers"

Error: R] Could not resolve "src/controllers"

The files absolutely exist on disk and I'm not sure why this was trying to resolve them in a strange way thinking they were directories. I flailed around for a while trying to make this work, eventually I just changed it to use a file to build like this:

This file is esbuild.prod.mjs

import * as esbuild from "esbuild";

await esbuild.build({
  entryPoints: ["./src/**"],
  outdir: "./dist",
  bundle: true,
  minify: true,
  logLevel: "debug",
  platform: "node",
});

and then I have

"build": "node esbuild.prod.mjs"

And to my surprise that works! Both locally and when run from the github actions. I can't explain this, but I wanted to report it here. Please let me know if you need any other details about this.

@hyrious
Copy link

hyrious commented Feb 16, 2024

It sounds like you have some issue with shell expanding rules, since shell command in npm scripts will be interpreted differently on different platforms. That is to say src/** may be expanded differently on GitHub actions and on your local machine.

Maybe wrap your command like this would work:

"build": "esbuild \"src/**\" --bundle ..."

@evanw
Copy link
Owner

evanw commented Feb 17, 2024

Yes, that’s correct. The way shell syntax works is that glob patterns without quotes are automatically interpreted and expanded by the shell before esbuild even sees them. So esbuild never sees "src/**" in that case (it sees "src/controllers" instead). If you quote it then the shell passes it to esbuild without interpreting it, which is equivalent to your example that uses the JS API. If passing "src/**" to the JS API works then it's likely that passing it to the CLI API would also work.

I'm not sure why this was trying to resolve them in a strange way thinking they were directories

There is a difference between the import path src/controllers and the import path ./src/controllers. Using node's normal path resolution rules, importing from src/controllers would look in node_modules for a package called src while importing from ./src/controllers would look for a file called ./src/controllers.js (or ./src/controllers/index.js or any of the other many things that node's path resolution algorithm requires esbuild to check for).

Forgetting to include the leading ./ is a common mistake when people use esbuild's CLI, so esbuild tries to automatically add it for you in some cases. One of those cases is if adding a leading ./ would create a valid relative path to a file, and another of those cases is if a glob pattern is present. When esbuild sees the entry point "src/components" (after shell expansion), it does not add a leading ./ because neither heuristic applies (./src/components is a directory, not a file), but when esbuild sees the entry point "src/**" (when shell expansion doesn't happen), the second heuristic applies and esbuild automatically rewrites it to "./src/**" instead.

So when the shell expands it, esbuild is treating it as a package path (because it didn't auto-correct the mistake of omitting the leading ./) while when the shell doesn't expand it, esbuild is treating it as a relative path (because it did auto-correct the mistake of omitting the leading ./). Other possible fixes might be to use a leading ./ to indicate a relative path instead of a package path, or to use a more specific glob pattern that doesn't match directories at all (such as src/**/*.ts or something).

@ChrisMBarr
Copy link
Author

Thank you for explaining this, I learned something new. I did try this a few times with ./ prefixed on my path, which didn't seem to make a difference. According to what you are saying though, if I had added quotes around my path that would have fixed the issue?

"build": "esbuild \"src/**\" --bundle --platform=node --outdir=dist --minify --log-level=debug"

Now knowing this, looking at the documentation for glob pattnerns and elsewhere in the documentation I am not finding any mention of this behavior. I believe that would be extremely helpful to mention somewhere or perhaps change the sample code to use quoted paths since that will work everywhere. I wasted many many hours yesterday on this, and I knew the whole time it would be a very simple but non-obvious solution like this.

@evanw
Copy link
Owner

evanw commented Apr 27, 2024

This is behavior now documented here: https://esbuild.github.io/api/#glob-style-entry-points. In addition, the CLI-specific section at the top of https://esbuild.github.io/api/ now reminds readers to be aware of the behavior of their shell.

@evanw
Copy link
Owner

evanw commented Apr 27, 2024

I'm closing this issue as it has now been documented.

@evanw evanw closed this as completed Apr 27, 2024
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

3 participants