From f74a81c21ea524870881bb1970cc584f35c3bda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 16 Jul 2021 10:50:13 +0200 Subject: [PATCH 1/2] Abort esbuild if stdin is closed when serving --- cmd/esbuild/main.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cmd/esbuild/main.go b/cmd/esbuild/main.go index 71ce20e745e..ad6d8c08147 100644 --- a/cmd/esbuild/main.go +++ b/cmd/esbuild/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "io" "os" "runtime/debug" "strings" @@ -261,11 +262,17 @@ func main() { } } - // Disable the GC since we're just going to allocate a bunch of memory - // and then exit anyway. This speedup is not insignificant. Make sure to - // only do this here once we know that we're not going to be a long-lived - // process though. - if !isServe { + if isServe { + // Watch stdin and abort in case it is closed + go func() { + io.ReadAll(os.Stdin) + os.Exit(exitCode) + }() + } else { + // Disable the GC since we're just going to allocate a bunch of memory + // and then exit anyway. This speedup is not insignificant. Make sure to + // only do this here once we know that we're not going to be a long-lived + // process though. debug.SetGCPercent(-1) } From 2c4077fecee076253443528a30546b6134c6ca05 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Sun, 25 Jul 2021 22:24:57 -0400 Subject: [PATCH 2/2] only monitor stdin when it's not a tty --- cmd/esbuild/main.go | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/cmd/esbuild/main.go b/cmd/esbuild/main.go index ad6d8c08147..900b30b3959 100644 --- a/cmd/esbuild/main.go +++ b/cmd/esbuild/main.go @@ -202,7 +202,8 @@ func main() { } // Print help text when there are no arguments - if len(osArgs) == 0 && logger.GetTerminalInfo(os.Stdin).IsTTY { + isStdinTTY := logger.GetTerminalInfo(os.Stdin).IsTTY + if len(osArgs) == 0 && isStdinTTY { logger.PrintText(os.Stdout, logger.LevelSilent, osArgs, helpText) os.Exit(0) } @@ -254,26 +255,46 @@ func main() { } } else { // Don't disable the GC if this is a long-running process - isServe := false + isServeOrWatch := false for _, arg := range osArgs { if arg == "--serve" || arg == "--watch" || strings.HasPrefix(arg, "--serve=") { - isServe = true + isServeOrWatch = true break } } - if isServe { - // Watch stdin and abort in case it is closed - go func() { - io.ReadAll(os.Stdin) - os.Exit(exitCode) - }() - } else { + if !isServeOrWatch { // Disable the GC since we're just going to allocate a bunch of memory // and then exit anyway. This speedup is not insignificant. Make sure to // 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 { + // 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. + // See: https://github.com/brunch/brunch/issues/920. + // + // We don't do this when stdin is a TTY because that interferes with + // the Unix background job system. If we read from stdin then Ctrl+Z + // to move the process to the background will incorrectly cause the + // job to stop. See: https://github.com/brunch/brunch/issues/998. + go func() { + // This just discards information from stdin because we don't use + // it and we can avoid unnecessarily allocating space for it + buffer := make([]byte, 512) + for { + _, err := os.Stdin.Read(buffer) + if err != nil { + // Only exit cleanly if stdin was closed cleanly + if err == io.EOF { + os.Exit(0) + } else { + os.Exit(1) + } + } + } + }() } exitCode = cli.Run(osArgs)