Skip to content

Commit

Permalink
fix #643: child process doesn't exit
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Feb 1, 2021
1 parent a2a221e commit d0a87e4
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

In addition to being a useful feature, this change also simplifies esbuild's internals. Previously esbuild had to maintain separate child processes if the current working directory was changed in between build API calls. Now esbuild will always reuse the same child process across all build API calls. The `stop()` call on the `startService()` API is also now a no-op (it doesn't do anything anymore) and the `startService()` API may be removed in future releases.

* Fix stray `esbuild` process after `node` exits ([#643](https://github.com/evanw/esbuild/issues/643))

I discovered that using esbuild's JavaScript incremental build API could result in the child `esbuild` process not exiting when the parent `node` process exits. This was due to a reference counting issue. The bug has been fixed so this shouldn't happen anymore.

## 0.8.38

* Implement a simple cross-platform watch mode ([#21](https://github.com/evanw/esbuild/issues/21))
Expand Down
4 changes: 2 additions & 2 deletions cmd/esbuild/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func (service *serviceType) handleIncomingPacket(bytes []byte) (result outgoingP
defer service.mutex.Unlock()
if watchStop, ok := service.watchStops[watchID]; ok {
// This watch is now considered finished. This matches the +1 reference
// count at the return of the serve call.
// count at the return of the build call.
refCount = -1
return watchStop
}
Expand Down Expand Up @@ -257,7 +257,7 @@ func (service *serviceType) handleIncomingPacket(bytes []byte) (result outgoingP
// Only mutate the map while inside a mutex
service.mutex.Lock()
defer service.mutex.Unlock()
if _, ok := service.rebuilds[rebuildID]; !ok {
if _, ok := service.rebuilds[rebuildID]; ok {
// This build is now considered finished. This matches the +1 reference
// count at the return of the first build call for this rebuild chain.
refCount = -1
Expand Down
31 changes: 31 additions & 0 deletions scripts/node-unref-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ async function tests() {
})
assert.deepStrictEqual(result.outputFiles.length, 1);
assert.deepStrictEqual(result.outputFiles[0].text, '1 + 2;\n');
assert.deepStrictEqual(result.stop, void 0);

const result2 = await result.rebuild()
assert.deepStrictEqual(result2.outputFiles.length, 1);
Expand All @@ -44,11 +45,41 @@ async function tests() {
result2.rebuild.dispose()
}

async function testWatch() {
const result = await esbuild.build({
stdin: { contents: '1+2' },
write: false,
watch: true,
})

assert.deepStrictEqual(result.rebuild, void 0);
assert.deepStrictEqual(result.outputFiles.length, 1);
assert.deepStrictEqual(result.outputFiles[0].text, '1 + 2;\n');

result.stop()
}

async function testWatchAndIncremental() {
const result = await esbuild.build({
stdin: { contents: '1+2' },
write: false,
incremental: true,
watch: true,
})

assert.deepStrictEqual(result.outputFiles.length, 1);
assert.deepStrictEqual(result.outputFiles[0].text, '1 + 2;\n');

result.stop()
result.rebuild.dispose()
}

const service = await esbuild.startService();
try {
await testTransform()
await testServe()
await testBuild()
await testWatch()
} catch (error) {
service.stop();
throw error;
Expand Down

0 comments on commit d0a87e4

Please sign in to comment.