Skip to content

Commit

Permalink
fix #1511, fix #1885: add --watch=forever
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Sep 1, 2022
1 parent 41c45af commit 77194c8
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 1 deletion.
8 changes: 8 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog

## Unreleased

* Add `--watch=forever` to allow esbuild to never terminate ([#1511](https://github.com/evanw/esbuild/issues/1511), [#1885](https://github.com/evanw/esbuild/issues/1885))

Currently using esbuild's watch mode via `--watch` from the CLI will stop watching if stdin is closed. The rationale is that stdin is automatically closed by the OS when the parent process exits, so stopping watch mode when stdin is closed ensures that esbuild's watch mode doesn't keep running forever after the parent process has been closed. For example, it would be bad if you wrote a shell script that did `esbuild --watch &` to run esbuild's watch mode in the background, and every time you run the script it creates a new `esbuild` process that runs forever.

However, there are cases when it makes sense for esbuild's watch mode to never exit. One such case is within a short-lived VM where the lifetime of all processes inside the VM is expected to be the lifetime of the VM. Previously you could easily do this by piping the output of a long-lived command into esbuild's stdin such as `sleep 999999999 | esbuild --watch &`. However, this possibility often doesn't occur to people, and it also doesn't work on Windows. People also sometimes attempt to keep esbuild open by piping an infinite stream of data to esbuild such as with `esbuild --watch </dev/zero &` which causes esbuild to spin at 100% CPU. So with this release, esbuild now has a `--watch=forever` flag that will not stop watch mode when stdin is closed.

## 0.15.6

* Lower `for await` loops ([#1930](https://github.com/evanw/esbuild/issues/1930))
Expand Down
24 changes: 23 additions & 1 deletion cmd/esbuild/main.go
Expand Up @@ -153,6 +153,7 @@ func main() {
cpuprofileFile := ""
isRunningService := false
sendPings := false
isWatchForever := false

// Do an initial scan over the argument list
argsEnd := 0
Expand Down Expand Up @@ -202,6 +203,21 @@ func main() {
sendPings = true

default:
// Some people want to be able to run esbuild's watch mode such that it
// never exits. However, esbuild ends watch mode when stdin is closed
// because stdin is always closed when the parent process terminates, so
// ending watch mode when stdin is closed is a good way to avoid
// accidentally creating esbuild processes that live forever.
//
// Explicitly allow processes that live forever with "--watch=forever".
// This may be a reasonable thing to do in a short-lived VM where all
// processes in the VM are only started once and then the VM is killed
// when the processes are no longer needed.
if arg == "--watch=forever" {
arg = "--watch"
isWatchForever = true
}

// Strip any arguments that were handled above
osArgs[argsEnd] = arg
argsEnd++
Expand Down Expand Up @@ -283,7 +299,7 @@ func main() {
// only do this here once we know that we're not going to be a long-lived
// process though.
debug.SetGCPercent(-1)
} else if !isStdinTTY {
} else if !isStdinTTY && !isWatchForever {
// If stdin isn't a TTY, watch stdin and abort in case it is closed.
// This is necessary when the esbuild binary executable is invoked via
// the Erlang VM, which doesn't provide a way to exit a child process.
Expand All @@ -307,6 +323,12 @@ func main() {
os.Exit(1)
}
}

// Some people attempt to keep esbuild's watch mode open by piping
// an infinite stream of data to stdin such as with "< /dev/zero".
// This will make esbuild spin at 100% CPU. To avoid this, put a
// small delay after we read some data from stdin.
time.Sleep(4 * time.Millisecond)
}
}()
}
Expand Down

0 comments on commit 77194c8

Please sign in to comment.