Skip to content

Commit

Permalink
fix #1589: server "stop()" waits for active builds
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Sep 12, 2021
1 parent 40b06d7 commit fcfd63e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

I would also like to add data for Safari. They have recently added support for arbitrary module namespace identifier names (https://bugs.webkit.org/show_bug.cgi?id=217576) and `export * as` (https://bugs.webkit.org/show_bug.cgi?id=214379). However, I have no idea how to determine which Safari release these bugs correspond to so this compatibility data for Safari has been omitted.

* Avoid unnecessary additional log messages after the server is stopped ([#1589](https://github.com/evanw/esbuild/issues/1589))

There is a development server built in to esbuild which is accessible via the `serve()` API call. This returns a promise that resolves to an object with a `stop()` method that immediately terminates the development server. Previously calling this could cause esbuild to print stray log messages since `stop()` could cause plugins to be unregistered while a build is still in progress. With this release, calling `stop()` no longer terminates the development server immediately. It now waits for any active builds to finish first so the builds are not interrupted and left in a confusing state.

## 0.12.26

* Add `--analyze` to print information about the bundle ([#1568](https://github.com/evanw/esbuild/issues/1568))
Expand Down
48 changes: 41 additions & 7 deletions pkg/api/serve_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type apiHandler struct {
rebuild func() BuildResult
currentBuild *runningBuild
fs fs.FS
serveWaitGroup sync.WaitGroup
serveError error
}

type runningBuild struct {
Expand Down Expand Up @@ -547,13 +549,24 @@ func serveImpl(serveOptions ServeOptions, buildOptions BuildOptions) (ServeResul
}
}

var stoppingMutex sync.Mutex
isStopping := false

// The first build will just build normally
var handler *apiHandler
handler = &apiHandler{
onRequest: serveOptions.OnRequest,
outdirPathPrefix: outdirPathPrefix,
servedir: serveOptions.Servedir,
rebuild: func() BuildResult {
stoppingMutex.Lock()
defer stoppingMutex.Unlock()

// Don't start more rebuilds if we were told to stop
if isStopping {
return BuildResult{}
}

build := buildImpl(buildOptions)
if handler.options == nil {
handler.options = &build.options
Expand All @@ -563,17 +576,38 @@ func serveImpl(serveOptions ServeOptions, buildOptions BuildOptions) (ServeResul
fs: realFS,
}

// Start the server
// When wait is called, block until the server's call to "Serve()" returns
result.Wait = func() error {
handler.serveWaitGroup.Wait()
return handler.serveError
}

// Create the server
server := &http.Server{Addr: addr, Handler: handler}
wait := make(chan error, 1)
result.Wait = func() error { return <-wait }
result.Stop = func() { server.Close() }

// When stop is called, block further rebuilds and then close the server
result.Stop = func() {
stoppingMutex.Lock()
defer stoppingMutex.Unlock()

// Only try to close the server once
if isStopping {
return
}
isStopping = true

// Close the server and wait for it to close
server.Close()
handler.serveWaitGroup.Wait()
}

// Start the server and signal on "serveWaitGroup" when it stops
handler.serveWaitGroup.Add(1)
go func() {
if err := server.Serve(listener); err != http.ErrServerClosed {
wait <- err
} else {
wait <- nil
handler.serveError = err
}
handler.serveWaitGroup.Done()
}()

// Start the first build shortly after this function returns (but not
Expand Down

0 comments on commit fcfd63e

Please sign in to comment.