Skip to content

Commit

Permalink
fix #816: treat ENOTDIR as ENOENT for directories
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Feb 19, 2021
1 parent f50aa9a commit f61ee6b
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 1 deletion.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

* Work around a problem with `pnpm` and `NODE_PATH` ([#816](https://github.com/evanw/esbuild/issues/816))

In version 0.8.43, esbuild added support for node's [`NODE_PATH`](https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders) environment variable which contains a list of global folders to use during path resolution. However, this causes a problem when esbuild is installed with [pnpm](https://pnpm.js.org/), an alternative JavaScript package manager. Specifically pnpm adds a bogus path to `NODE_PATH` that doesn't exist but that has a file as a parent directory. Previously this caused esbuild to fail with the error `not a directory`. Now with this release, esbuild will ignore this bogus path instead of giving an error.

## 0.8.48

* Fix some parsing edge cases ([#835](https://github.com/evanw/esbuild/issues/835))
Expand Down
6 changes: 6 additions & 0 deletions internal/fs/fs_real.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ func (fs *realFS) ReadDirectory(dir string) (DirEntries, error) {
// Cache miss: read the directory entries
names, err := readdir(dir)
entries := DirEntries{dir, make(map[string]*Entry)}

// Unwrap to get the underlying error
if pathErr, ok := err.(*os.PathError); ok {
err = pathErr.Unwrap()
}

if err == nil {
for _, name := range names {
// Call "stat" lazily for performance. The "@material-ui/icons" package
Expand Down
9 changes: 8 additions & 1 deletion internal/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,14 @@ func (r *resolver) dirInfoUncached(path string) *dirInfo {
// List the directories
entries, err := r.fs.ReadDirectory(path)
if err != nil {
if err != syscall.ENOENT {
// Ignore "ENOTDIR" here so that calling "ReadDirectory" on a file behaves
// as if there is nothing there at all instead of causing an error due to
// the directory actually being a file. This is a workaround for situations
// where people try to import from a path containing a file as a parent
// directory. The "pnpm" package manager generates a faulty "NODE_PATH"
// list which contains such paths and treating them as missing means we just
// ignore them during path resolution.
if err != syscall.ENOENT && err != syscall.ENOTDIR {
r.log.AddError(nil, logger.Loc{},
fmt.Sprintf("Cannot read directory %q: %s",
r.PrettyPath(logger.Path{Text: path, Namespace: "file"}), err.Error()))
Expand Down
15 changes: 15 additions & 0 deletions scripts/end-to-end-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@
}),
)

// Test bogus paths with a file as a parent directory (this happens when you use "pnpx esbuild")
tests.push(
test(['entry.js', '--bundle'], {
'entry.js': `import "./file.js/what/is/this"`,
'file.js': `some file`,
}, {
expectedStderr: ` > entry.js: error: Could not resolve "./file.js/what/is/this"
1 │ import "./file.js/what/is/this"
╵ ~~~~~~~~~~~~~~~~~~~~~~~~
1 error
`,
}),
)

// Tests for symlinks
//
// Note: These are disabled on Windows because they fail when run with GitHub
Expand Down

0 comments on commit f61ee6b

Please sign in to comment.