Sending data between Nodejs processes
Tags: node, javascript, tutorial
Published: 2022-09-16 16:03:08

Last month when I was building an open-sourced project, I met with a situation that needs to run `npm test` in the child process and send back the data to the main process,

So I did some investigation and figured out my solution in the end. Here is my summary of how many ways we can use for establishing nodejs process communication.

## child_process.fork
fork gives you a communication channel by native, specify a file for the child process and they will establish a communication channel after generating the child process, as simple as what is shown in the Nodejs official document.

```js
// index.js
import { fork } from 'node:child_process'
import path from 'path'

const subProcess = fork(path.resolve(process.cwd(),'sub.js'))
subProcess.on('message', (msg) => {
  console.log('PARENT got message: ', msg)
  subProcess.send('parent -> child')
})

// sub.js
process.send("child -> parent")
process.on('message', (msg) => {
  console.log('CHILD got message: ', msg)
})

// output
PARENT got message:  child -> parent
CHILD got message:  parent -> child
```

## child_process.spawn
fork works only if we have the file running in the child process. In some other cases, we might wanna use the child process to execute a command and we use spawn for such cases. I thought the spawned child process can't establish a communication channel until I found the parameters **stdio**, here is the example:

```js
// index.js
import { spawn } from 'node:child_process'

const subProcess = spawn('node', ['sub.js'], {
  // inherit stdin, stdout and stderr, establish IPC communication channel
  stdio: ['inherit', 'inherit', 'inherit', 'ipc']  
})

subProcess.on('message', (msg) => {
  console.log('PARENT got message: ', msg)
  subProcess.send('parent -> child')
});

// sub.js
process.send("child -> parent")
process.on('message', (msg) => {
  console.log('CHILD got message: ', msg)
})

// output
PARENT got message:  child -> parent
CHILD got message:  parent -> child
```

## Listen stdout or stderr
but for my case, I need my child process to run an npm script, somehow it can't establish the communication channel.

And finally, I have to switch to my tricky solution which passes the data through stdout or stderr, because I found the parent process can listen the data from child process's stdout and stderr if we set **stdio** as pipe, then what we need to do is just let the child process to output the data with a pre-defined format so the parent process can recognize the data by the format.

```js
// index.js
const subProcess = spawn('node', 'run test', {
  // pipe stderr so we can subsribe the data event on stderr
  stdio: ['inherit', 'inherit', 'pipe']
});

subProcess.stderr.on('data', (buffer) => {
  const data = buffer.toString()
  if (data.startsWith('PREFIX')) {
    // Here we know this is the data sent from the child process manually
  }
})

// testing files
process.stderr.write('PREFIX' + 'message to parent' + "\n")
```

## Conclusion
For establish a communication channel between node process:
* Using fork if you have the file for the child process
* Using spawn and modify stdio if you only need to run a command in the child process
* If you are running an NPM script, we can do communication through stdout and stderr.