spawn-rx: A better version of spawn
spawn-rx
is a package that adds an Observable as well as a Promise version of
the child_process.spawn
API, and fixes some deficiencies in spawn
that come
up especially on Windows. For example:
-
spawn
searches PATH on POSIX platforms but will not on Windows, you need to
provide an exact path. spawn-rx makes Windows act like other platforms.
-
On Windows, {detached: true}
doesn't actually create a process group properly.
spawn-rx
provides a spawnDetached
method that allows you to spawn a detached
process and kill the entire process group if needed.
-
POSIX platforms allow you to directly execute scripts that have a shebang at
the top of the file, whereas Windows can only natively spawn
EXE files, which
makes executing npm binaries annoying. spawn-rx
automatically rewrites your
cmd
and args
parameters for CMD scripts, PowerShell scripts, and node.js
files.
Examples
spawn-as-promise:
spawnPromise('wmic', [])
.then((result) => console.log(result));
Handle failed processes as errors:
try {
await spawnPromise('exit', ['-1']);
} catch (e) {
console.log("Processes that return non-zero exit codes throw")
}
Kill running process trees:
let disp = spawnDetached('takesALongTime', []).subscribe();
await Promise.delay(1000);
disp.dispose();
Stream process output:
spawn('ls', ['-r'])
.subscribe(
(x) => console.log(x),
(e) => console.log("Process exited with an error"));
Execute scripts:
let result = await spawnPromise('uuid');
What's Jobber?
Jobber is a Windows executable that will execute a command in a process group,
and if signaled via a named pipe, will terminate that process group. It's used
in the implementation of spawnDetached
. Jobber was written by me, and its license
is the same as spawn-rx
, it is not a third-party dependency.
Spawn output
By default spawn will merge stdout and stderr into the returned observable.
You can exclude one or the other by passing ignore
in the stdio
option of spawn.
Alternatively if you call it with { split: true }
option, the observable output
will be an object { source: 'stdout', text: '...' }
so you can distinguish
the outputs.
Stdin support
If you provide an Observable<string>
in opts.stdin
, it'll be subscribed upon
and fed into the child process stdin. Its completion will terminate stdin stream.
Methods
function spawn(
exe: string,
params: string[],
opts: SpawnOptions & SpawnRxExtras & { split: true }
): Observable<OutputLine>;
function spawn(
exe: string,
params: string[],
opts?: SpawnOptions & SpawnRxExtras & { split: false | undefined }
): Observable<string>;
function spawnDetached(
exe: string,
params: string[],
opts: SpawnOptions & SpawnRxExtras & { split: true }
): Observable<OutputLine>;
function spawnDetached(
exe: string,
params: string[],
opts?: SpawnOptions & SpawnRxExtras & { split: false | undefined }
): Observable<string>;
function spawnPromise(
exe: string,
params: string[],
opts: SpawnOptions & SpawnRxExtras & { split: true }
): Promise<[string, string]>;
function spawnPromise(
exe: string,
params: string[],
opts?: SpawnOptions & SpawnRxExtras
): Promise<string>;
function spawnDetachedPromise(
exe: string,
params: string[],
opts: SpawnOptions & SpawnRxExtras & { split: true }
): Promise<[string, string]>;
function spawnDetachedPromise(
exe: string,
params: string[],
opts?: SpawnOptions & SpawnRxExtras
): Promise<string>;
function findActualExecutable(
exe: string,
args: string[]
): {
cmd: string;
args: string[];
};