tinyspawn is a minimalistic child_process
wrapper with following features:
- Small (~80 LOC, 835 bytes).
- Focus on performance.
- Zero dependencies.
- Meaningful errors.
- Easy to extend.
- Fully typed.
$ npm install tinyspawn --save
The child_process in Node.js is great, but I always found the API confusing and hard to remember.
That's why I created tinyspawn. It's recommended to bind it to $
:
const $ = require('tinyspawn')
The first argument is the command (with arguments) to be executed:
const { stdout } = await $(`node -e 'console.log("hello world")'`)
console.log(stdout) // => 'hello world'
The second argument is any of the spawn#options:
const { stdout } = $(`node -e 'console.log("hello world")'`, {
shell: true
})
When you execute a command, it returns a ChildProcess instance:
const {
signalCode,
exitCode,
killed,
spawnfile,
spawnargs,
pid,
stdin,
stdout,
stderr,
stdin
} = await $('date')
Since tinyspawn returns a ChildProcess instance, you can use it for interacting with other Node.js streams:
const subprocess = $('echo 1234567890')
subprocess.stdout.pipe(process.stdout) // => 1234567890
/* You can also continue interacting with it as a promise */
const { stdout } = await subprocess
console.log(stdout) // => 1234567890
or stdin:
const { Readable } = require('node:stream')
const subprocess = $('cat', { stdin: 'hello world' })
Readable.from('hello world').pipe(subprocess.stdin)
const {stdout} = await subprocess
console.log(stdout) // 'hello world'
A CLI program commonly supports a way to return a JSON that makes it easy to connect with other programs.
tinyspawn has been designed to be easy to work with CLI programs, making it possible to call $.json
or pass { json: true }
as an option:
const { stdout } = await $.json(`curl https://geolocation.microlink.io`)
Although you can pass spawn#options as a second argument, sometimes defining something as default behavior is convenient.
tinyspawn exports the method $.extend
to create a tinyspawn with spawn#options defaults set:
const $ = require('tinyspawn').extend({
timeout: 5000,
killSignal: 'SIGKILL'
})
When working with CLI programs and something wrong happens, it's crucial to present the error as readable as possible.
tinyspawn prints meaningful errors to help you understa dn what happened:
const subprocess = $('node', ['child.js'], {
timeout: 500,
killSignal: 'SIGKILL'
})
console.log(await subprocess.catch(error => error))
// Error [ChildProcessError]: The command spawned as:
// `node child.js`
// exited with:
// `{ signal: 'null', code: 1 }`
// with the following trace:
// at createChildProcessError (/Users/kikobeats/Projects/microlink/tinyspawn/src/index.js:20:17)
// at ChildProcess.<anonymous> (/Users/kikobeats/Projects/microlink/tinyspawn/src/index.js:63:18)
// at ChildProcess.emit (node:events:531:35)
// at ChildProcess._handle.onexit (node:internal/child_process:294:12) {
// command: 'node child.js',
// connected: false,
// signalCode: null,
// exitCode: 1,
// killed: false,
// spawnfile: 'node',
// spawnargs: [ 'node', 'child.js' ],
// pid: 63467,
// stdout: '',
// stderr: 'node:internal/modules/cjs/loader:1148\n' +
// ' throw err;\n' +
// ' ^\n' +
// '\n' +
// "Error: Cannot find module '/Users/kikobeats/Projects/microlink/tinyspawn/child.js'\n" +
// ' at Module._resolveFilename (node:internal/modules/cjs/loader:1145:15)\n' +
// ' at Module._load (node:internal/modules/cjs/loader:986:27)\n' +
// ' at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)\n' +
// ' at node:internal/main/run_main_module:28:49 {\n' +
// " code: 'MODULE_NOT_FOUND',\n" +
// ' requireStack: []\n' +
// '}\n' +
// '\n' +
// 'Node.js v20.15.1'
// }
The ChildProcess instance properties are also available as part of the error:
const { stdout: node } = await $('which node')
const error = await $(`${node} -e 'require("notfound")'`).catch(error => error)
const {
signalCode,
exitCode,
killed,
spawnfile,
spawnargs,
pid,
stdin,
stdout,
stderr,
stdin
} = error
- tinyrun – CLI for executing multiple commands in parallel with minimal footprint (~2KB).
tinyspawn © microlink.io, released under the MIT License.
Authored and maintained by Kiko Beats with help from contributors.
microlink.io · GitHub microlink.io · X @microlinkhq