Skip to content

Latest commit

 

History

History
205 lines (147 loc) · 8.74 KB

output.md

File metadata and controls

205 lines (147 loc) · 8.74 KB
execa logo

📢 Output

Stdout and stderr

The stdout and stderr options redirect the subprocess output. They default to 'pipe', which returns the output using result.stdout and result.stderr.

import {execa} from 'execa';

const {stdout, stderr} = await execa`npm run build`;
console.log(stdout);
console.log(stderr);

Ignore output

const {stdout, stderr} = await execa({stdout: 'ignore'})`npm run build`;
console.log(stdout); // undefined
console.log(stderr); // string with errors

File output

await execa({stdout: {file: 'output.txt'}})`npm run build`;
// Or:
await execa({stdout: new URL('file:///path/to/output.txt')})`npm run build`;
// Redirect interleaved stdout and stderr to same file
const output = {file: 'output.txt'};
await execa({stdout: output, stderr: output})`npm run build`;
// Append instead of overwriting
await execa({stdout: {file: 'output.txt', append: true}})`npm run build`;

Terminal output

The parent process' output can be re-used in the subprocess by passing 'inherit'. This is especially useful to print to the terminal in command line applications.

await execa({stdout: 'inherit', stderr: 'inherit'})`npm run build`;

To redirect from/to a different file descriptor, pass its number or process.stdout/process.stderr.

// Print both stdout/stderr to the parent stdout
await execa({stdout: process.stdout, stderr: process.stdout})`npm run build`;
// Or:
await execa({stdout: 1, stderr: 1})`npm run build`;

Any output type

If the subprocess uses Node.js, IPC can be used to return almost any type from the subprocess. The result.ipcOutput array contains all the messages sent by the subprocess.

// main.js
import {execaNode} from 'execa';

const {ipcOutput} = await execaNode`build.js`;
console.log(ipcOutput[0]); // {kind: 'start', timestamp: date}
console.log(ipcOutput[1]); // {kind: 'stop', timestamp: date}
// build.js
import {sendMessage} from 'execa';

await sendMessage({kind: 'start', timestamp: new Date()});
await runBuild();
await sendMessage({kind: 'stop', timestamp: new Date()});

Multiple targets

The output can be redirected to multiple targets by setting the stdout or stderr option to an array of values. This also allows specifying multiple inputs with the stdin option.

The following example redirects stdout to both the terminal and an output.txt file, while also retrieving its value programmatically.

const {stdout} = await execa({stdout: ['inherit', {file: 'output.txt'}, 'pipe']})`npm run build`;
console.log(stdout);

When combining 'inherit' with other values, please note that the subprocess will not be an interactive TTY, even if the current process is one.

Interleaved output

If the all option is true, stdout and stderr are combined:

stdout and stderr are guaranteed to interleave. However, for performance reasons, the subprocess might buffer and merge multiple simultaneous writes to stdout or stderr. This can prevent proper interleaving.

For example, this prints 1 3 2 instead of 1 2 3 because both console.log() are merged into a single write.

const {all} = await execa({all: true})`node example.js`;
// example.js
console.log('1'); // writes to stdout
console.error('2'); // writes to stderr
console.log('3'); // writes to stdout

This can be worked around by using setTimeout().

import {setTimeout} from 'timers/promises';

console.log('1');
console.error('2');
await setTimeout(0);
console.log('3');

Stdout/stderr-specific options

Some options are related to the subprocess output: verbose, lines, stripFinalNewline, buffer, maxBuffer. By default, those options apply to all file descriptors (stdout, stderr, and others) and IPC messages. A plain object can be passed instead to apply them to only stdout, stderr, all (both stdout and stderr), ipc, fd3, etc.

// Same value for stdout and stderr
await execa({verbose: 'full'})`npm run build`;

// Different values for stdout and stderr
await execa({verbose: {stdout: 'none', stderr: 'full'}})`npm run build`;

Additional file descriptors

The stdio option is an array combining stdin, stdout, stderr and any other file descriptor. It is useful when using additional file descriptors beyond the standard ones, either for input or output.

result.stdio can be used to retrieve some output from any file descriptor, as opposed to only stdout and stderr.

// Retrieve output from file descriptor number 3
const {stdio} = await execa({
	stdio: ['pipe', 'pipe', 'pipe', 'pipe'],
})`npm run build`;
console.log(stdio[3]);

Shortcut

The stdio option can also be a single value 'pipe', 'overlapped', 'ignore' or 'inherit'. This is a shortcut for setting that same value with the stdin, stdout and stderr options.

await execa({stdio: 'ignore'})`npm run build`;
// Same as:
await execa({stdin: 'ignore', stdout: 'ignore', stderr: 'ignore'})`npm run build`;

Big output

To prevent high memory consumption, a maximum output size can be set using the maxBuffer option. It defaults to 100MB.

When this threshold is hit, the subprocess fails and error.isMaxBuffer becomes true. The truncated output is still available using error.stdout, error.stderr and error.ipcOutput.

This is measured:

try {
	await execa({maxBuffer: 1_000_000})`npm run build`;
} catch (error) {
	if (error.isMaxBuffer) {
		console.error('Error: output larger than 1MB.');
		console.error(error.stdout);
		console.error(error.stderr);
	}

	throw error;
}

Low memory

When the buffer option is false, result.stdout, result.stderr, result.all, result.stdio[*] and result.ipcOutput properties are empty.

This prevents high memory consumption when the output is big. However, the output must be either ignored, redirected, streamed or listened to. If streamed, this should be done right away to avoid missing any data.


Next: 📃 Text lines
Previous: 🎹 Input
Top: Table of contents