From 57bb54ea26bef7eab062925364158a4c478062f3 Mon Sep 17 00:00:00 2001 From: Jake Gordon Date: Sun, 12 Apr 2020 14:02:30 -0700 Subject: [PATCH] Ensure --watch mode exits correctly when stdin is closed. (#3493) * Ensure --watch mode exits correctly when stdin is closed. This is necessary when rollup is used as the front end for an Elixir Phoenix application. In dev mode, the phoenix watchers run the rollup command as a child process and the underlying erlang port mechanism assumes that the child process closes when the parent stdin is closed. Without this fix the old zombie processes never close and accumulate as you stop and start in development mode. This was discussed and fixed in 2017 in the original rollup-watcher repository: * https://github.com/rollup/rollup-watch/issues/30#issuecomment-316468552 * https://github.com/rollup/rollup-watch/pull/57/files It appears to then have been removed as a side effect of another change * https://github.com/rollup/rollup/pull/2410 Finally, was requested back in a PR that never got merged because of some doubt around the need to hide it behind a CLI flag * https://github.com/rollup/rollup/pull/2653/files For reference, webpack implements this hidden behind the --watch-stdin CLI flag. * Add a test that times out without this change Co-authored-by: Lukas Taegert-Atkinson --- cli/run/watch.ts | 2 +- test/cli/samples/watch/close-stdin/_config.js | 4 +++ .../watch/close-stdin/_expected/out.js | 3 +++ test/cli/samples/watch/close-stdin/main.js | 1 + test/cli/samples/watch/close-stdin/wrapper.js | 26 +++++++++++++++++++ 5 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 test/cli/samples/watch/close-stdin/_config.js create mode 100644 test/cli/samples/watch/close-stdin/_expected/out.js create mode 100644 test/cli/samples/watch/close-stdin/main.js create mode 100755 test/cli/samples/watch/close-stdin/wrapper.js diff --git a/cli/run/watch.ts b/cli/run/watch.ts index 47ae5b873..176220c5f 100644 --- a/cli/run/watch.ts +++ b/cli/run/watch.ts @@ -26,9 +26,9 @@ export default async function watch(command: any) { onExit(close); process.on('uncaughtException' as any, close); - // only listen to stdin if it is a pipe if (!process.stdin.isTTY) { process.stdin.on('end', close); + process.stdin.resume(); } if (configFile) { diff --git a/test/cli/samples/watch/close-stdin/_config.js b/test/cli/samples/watch/close-stdin/_config.js new file mode 100644 index 000000000..523753514 --- /dev/null +++ b/test/cli/samples/watch/close-stdin/_config.js @@ -0,0 +1,4 @@ +module.exports = { + command: 'node wrapper.js main.js --watch --format es --file _actual/out.js', + description: 'closes the watcher when stdin closes' +}; diff --git a/test/cli/samples/watch/close-stdin/_expected/out.js b/test/cli/samples/watch/close-stdin/_expected/out.js new file mode 100644 index 000000000..d862de816 --- /dev/null +++ b/test/cli/samples/watch/close-stdin/_expected/out.js @@ -0,0 +1,3 @@ +var main = 42; + +export default main; diff --git a/test/cli/samples/watch/close-stdin/main.js b/test/cli/samples/watch/close-stdin/main.js new file mode 100644 index 000000000..7a4e8a723 --- /dev/null +++ b/test/cli/samples/watch/close-stdin/main.js @@ -0,0 +1 @@ +export default 42; diff --git a/test/cli/samples/watch/close-stdin/wrapper.js b/test/cli/samples/watch/close-stdin/wrapper.js new file mode 100755 index 000000000..0338bd7c9 --- /dev/null +++ b/test/cli/samples/watch/close-stdin/wrapper.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node + +const stream = require('stream'); +const fs = require('fs'); +const path = require('path'); + +delete process.stdin; +process.stdin = new stream.Readable({ + encoding: 'utf8', + read() { + return null; + } +}); + +const outputDir = path.resolve(__dirname, '_actual'); +fs.mkdirSync(outputDir); +const outputFile = path.resolve(outputDir, 'out.js'); +fs.writeFileSync(outputFile, 'NOT WRITTEN'); + +const watcher = fs.watch(outputFile, () => { + watcher.close(); + // This closes stdin + process.stdin.push(null); +}); + +require('../../../../../dist/bin/rollup');