Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

foreground-child

tapjs113.8mISC3.3.0TypeScript support: included

Run a child as if it's the foreground process. Give it stdio. Exit when it exits.

readme

foreground-child

Run a child as if it's the foreground process. Give it stdio. Exit when it exits.

Mostly this module is here to support some use cases around wrapping child processes for test coverage and such. But it's also generally useful any time you want one program to execute another as if it's the "main" process, for example, if a program takes a --cmd argument to execute in some way.

USAGE

import { foregroundChild } from 'foreground-child'
// hybrid module, this also works:
// const { foregroundChild } = require('foreground-child')

// cats out this file
const child = foregroundChild('cat', [__filename])

// At this point, it's best to just do nothing else.
// return or whatever.
// If the child gets a signal, or just exits, then this
// parent process will exit in the same way.

You can provide custom spawn options by passing an object after the program and arguments:

const child = foregroundChild(`cat ${__filename}`, { shell: true })

A callback can optionally be provided, if you want to perform an action before your foreground-child exits:

const child = foregroundChild('cat', [__filename], spawnOptions, () => {
  doSomeActions()
})

The callback can return a Promise in order to perform asynchronous actions. If the callback does not return a promise, then it must complete its actions within a single JavaScript tick.

const child = foregroundChild('cat', [__filename], async () => {
  await doSomeAsyncActions()
})

If the callback throws or rejects, then it will be unhandled, and node will exit in error.

If the callback returns a string value, then that will be used as the signal to exit the parent process. If it returns a number, then that number will be used as the parent exit status code. If it returns boolean false, then the parent process will not be terminated. If it returns undefined, then it will exit with the same signal/code as the child process.

Caveats

The "normal" standard IO file descriptors (0, 1, and 2 for stdin, stdout, and stderr respectively) are shared with the child process. Additionally, if there is an IPC channel set up in the parent, then messages are proxied to the child on file descriptor 3.

In Node, it's possible to also map arbitrary file descriptors into a child process. In these cases, foreground-child will not map the file descriptors into the child. If file descriptors 0, 1, or 2 are used for the IPC channel, then strange behavior may happen (like printing IPC messages to stderr, for example).

Note that a SIGKILL will always kill the parent process, but will not proxy the signal to the child process, because SIGKILL cannot be caught. In order to address this, a special "watchdog" child process is spawned which will send a SIGKILL to the child process if it does not terminate within half a second after the watchdog receives a SIGHUP due to its parent terminating.

On Windows, issuing a process.kill(process.pid, signal) with a fatal termination signal may cause the process to exit with a 1 status code rather than reporting the signal properly. This module tries to do the right thing, but on Windows systems, you may see that incorrect result. There is as far as I'm aware no workaround for this.

util: foreground-child/proxy-signals

If you just want to proxy the signals to a child process that the main process receives, you can use the proxy-signals export from this package.

import { proxySignals } from 'foreground-child/proxy-signals'

const childProcess = spawn('command', ['some', 'args'])
proxySignals(childProcess)

Now, any fatal signal received by the current process will be proxied to the child process.

It doesn't go in the other direction; ie, signals sent to the child process will not affect the parent. For that, listen to the child exit or close events, and handle them appropriately.

util: foreground-child/watchdog

If you are spawning a child process, and want to ensure that it isn't left dangling if the parent process exits, you can use the watchdog utility exported by this module.

import { watchdog } from 'foreground-child/watchdog'

const childProcess = spawn('command', ['some', 'args'])
const watchdogProcess = watchdog(childProcess)

// watchdogProcess is a reference to the process monitoring the
// parent and child. There's usually no reason to do anything
// with it, as it's silent and will terminate
// automatically when it's no longer needed.

changelog

Changes

v3.3

  • Include watchdogPid as a metadata argument to cleanup function

v3.2

  • Export watchdog and proxySignals functionality

v3.1

  • Add support for optional SpawnOptions param

v3.0

  • Rewritten as hybrid module in TypeScript
  • Support modifying (or suppressing) the exit of parent process.
  • Named export instead of default export
  • Add watchdog side process to terminate the child process if the parent is killed with an uncatchable signal, and the automatic SIGHUP is not sufficient.
  • Cleanup function no longer takes a done callback. Use promises for async actions.

v2.0.0

  • BREAKING CHANGE: Require Node 8
  • Internal: Add lock file
  • Support async before exit callback
  • Update various dependencies

v1.5.6

  • Fix 'childHangup is undefined'

v1.5.5

  • add files list to package.json
  • neveragain.tech pledge request

v1.5.4

  • update tap to v8
  • Let the child decide if signals should be fatal

v1.5.3

  • bump deps

v1.5.2

  • add an automatic changelog script
  • replace cross-spawn-async with cross-spawn
  • test: stay alive long enough to be signaled

v1.5.1

  • avoid race condition in test
  • Use fd numbers instead of 'inherit' for Node v0.10 compatibility

v1.5.0

  • add caveats re IPC and arbitrary FDs
  • Forward IPC messages to foregrounded child process

v1.4.0

  • Set process.exitCode based on the child’s exit code

v1.3.5

  • Better testing for when cross-spawn-async needed
  • appveyor: node v0.10 on windows is too flaky

v1.3.4

  • Only use cross-spawn-async for shebangs
  • update vanity badges and package.json for repo move
  • appveyor

v1.3.3

  • Skip signals in tests on Windows
  • update to tap@4
  • use cross-spawn-async on windows

v1.3.2

  • Revert "switch to win-spawn"
  • Revert "Transparently translate high-order exit code to appropriate signal"
  • update travis versions
  • Transparently translate high-order exit code to appropriate signal
  • ignore coverage folder

v1.3.1

  • switch to win-spawn

v1.3.0

  • note skipped test in test output
  • left an unused var c in
  • slice arguments, added documentation
  • added a unit test, because I strive to be a good open-source-citizen
  • make travis also work on 0.12 and iojs again
  • added badge
  • patch for travis exit weirdness
  • fix typo in .gitignore
  • beforeExit hook

v1.2.0

  • Use signal-exit, fix kill(process.pid) race

v1.1.0

  • Enforce that parent always gets a 'exit' event

v1.0.0

  • first