Open travelmassive opened 1 year ago
This is probably something that you are going to have to debug on your end, perhaps by building esbuild from source with additional debugging code added. The file watcher is polling-based and tries to use stat
syscalls for performance when detecting changes. Specifically various properties returned by stat
are merged into something esbuild calls a "mod key" that represents the file's state at rest. On Unix-like operating systems, esbuild's mod key combines the following information (see the code for details):
When any of those properties change in between stat
calls, esbuild's watch mode will trigger another build. There are also conditions when esbuild doesn't use mod keys such as when the modification timestamp returned by the operating system is zero or when the modification timestamp is too new (since modification timestamps for some file systems have a large granularity).
It's possible that the virtual file system you're using is mutating one of those properties on every stat
call which would then cause esbuild to think that the file system is always changing. It's also possible that there's something else going on instead. This is just a guess on my end after reading what you wrote.
Thanks for the tips.
I manually built esbuild from source and printed the return values of ModKey (inode, mtime_sec, mtime_nsec, etc) to take a look. There's nothing interesting here — the values are same for each file between polls (without modifying a file).
I also made a copy of my app on my native filesystem on Linux, and esbuild works as expected here.
Here's some example output, debugging the values in modkey_unix.go:modKey():
Mac:
path: /Users/ian/Documents/Projects/myapp/assets/js/hooks/example.js
stat.Ino: 130632349
stat.Size: 532
int64(stat.Mtim.Sec): 1696025390
int64(stat.Mtim.Nsec): 614540869
uint32(stat.Mode): 33188
stat.Uid: 501
Linux (via mounted folder):
path: /media/psf/Projects/myapp/assets/js/hooks/example.js
stat.Ino: 2615497
stat.Size: 532
int64(stat.Mtim.Sec): 1696025390
int64(stat.Mtim.Nsec): 0
uint32(stat.Mode): 33188
stat.Uid: 1000
Linux (from a copy on root (native, non-mounted) filesystem):
path: /home/ubuntu/myapp/assets/js/hooks/example.js
stat.Ino: 1214891
stat.Size: 532
int64(stat.Mtim.Sec): 1696736918
int64(stat.Mtim.Nsec): 411436975
uint32(stat.Mode): 33188
stat.Uid: 1000
When I run esbuild on the mounted filesystem in Linux with --log-level=verbose, I noticed that esbuild is reporting it was resolving in the root folder "/". Could this be a clue?
Resolving import "./assets/js/app.js" in directory "/" of type "entry-point"
Read 26 entries for directory "/"
Read 26 entries for directory "/"
Read 26 entries for directory "/"
Failed to read directory "/assets": open /assets: no such file or directory
Failed to read directory "/assets"
Failed to read directory "/assets/js"
Attempting to load "/assets/js/app.js" as a file
Failed to read directory "/assets/js": open /assets/js: no such file or directory
Attempting to load "/assets/js/app.js" as a directory
Failed to read directory "/assets/js"
Failed to read directory "/assets/js/app.js"
ReadDirectory /assets/js <-- my own debug Println in fs_real.go:ReadDirectory()
✘ [ERROR] Could not resolve "./assets/js/app.js"
I'm using esbuild to compile JS for my Phoenix Elixir app.
My development environment is:
Problem:
On my Linux environment,
esbuild --watch
goes into a loop of (falsely) detecting files that have changed and rebuilding them, until some kind of file handler limit is exhausted and esbuild stops + my Elixir code reloader crashes.The same command works when run on my Mac in the same folder.
esbuild command:
On my Mac (OSX 13.4, esbuild 0.19.3), esbuild works as expected (I change one file, example.js and it rebuilds):
On Linux (Ubuntu 20.04, esbuild 0.19.3), without changing any code, esbuild loops through many different files (that haven't changed) before eventually being "unable to resolve ./assets/js/app.js", then other apps reading the folder report errors.
At this point, other things start breaking on my VM.
Shell output (from direnv)
direnv: error LoadConfig() Getwd failed: "getwd: no such file or directory"
Output from Phoenix Elixir App (0.19.5) also dies...
If I run the esbuild command on Linux without --watch, the build runs fine without issues.
I would expect it shouldn't matter that I'm running esbuild on a mounted file system?
Thanks for any help — Ian