I often have projects where I have multiple development tasks that need to be running while I work. My worst offender actually has four.

  • the main web server
  • an api web server
  • webpack
  • a grunt task that copies some files

I’ll spare you the details of why it’s such a mess.

I got tired of making several terminals to spin up all those tasks. My first attempt at a solution was to use a bash script that looked something like this.

#!/usr/bin/env bash
node server.js &
node api.js &
npx webpack &
npx grunt watch &

The problem with this is that you end up with orhaned processes when you ctrl+c kill it.

Killing Orphaned Processes

Killing the orphans isn’t so hard.

ps aux | grep node

Find the pids.

kill [pid]

But that’s using up more time than just having 4 separate terminals.

Use Node.js and child_process.spawn

Then I found a solution that worked. Write some Node.js that uses child_process.spawn to spawn my tasks as separate processes.

I worked out good defaults that make life easy:

  • include my path
  • spawn a bash shell
  • use the current working directory
  • inherit stdin, stdout and stderr

It looked a bit like this.

#!/usr/bin/env node
'use strict';

var path = require('path');

function spawn({ cmd, cwd }) {
  return require('child_process').spawn(cmd, {
    env: {
      PATH: process.env.PATH
    },
    shell: true,
    stdio: ['inherit', 'inherit', 'inherit'],
    cwd: cwd || process.cwd()
  });
}

spawn({ cmd: `node server.js` });
spawn({ cmd: `node api.js` });
spawn({
  cmd: 'npx webpack --config webpack.development.js --watch --colors',
  cwd: path.join(__dirname, 'assets')
});
spawn({ cmd: `npx grunt watch` });

Spawn in Parallel

It worked. I’m going to use this on many projects, so I made it a library.

tl;dr

Check out spawn-in-parallel.

Install.

npm install --save-dev @ryanburnette/spawn-in-parallel

Set up a development script.

mkdir -p scripts
touch scripts/development
chmod +x scripts/development

It’ll look something like this.

#!/usr/bin/env node
'use strict';
require('@ryanburnette/spawn-in-parallel')([
  'node server.js',
  'node api.js',
  'npx webpack',
  'npx grunt watch'
]);

Get to work.

scripts/development

When you’re done, ctrl+c kill it with no orphaned processes.