I have a package.json file like below with scripts tag.
{
"name": "name",
"version": "1.0.1",
"license": "MIT",
"scripts": {
"cmd1": "cd packages/apis/ && yarn start",
"cmd2": "cd packages/utils/ && yarn start",
"cmd3": "cd packages/components/ && yarn start",
"cmd4": "cd services/ad/ && yarn dev",
"start": "yarn cmd1 && yarn cmd2 && yarn cmd3 && yarn cmd4"
},
"dependencies": {
// dependencies listed here
}
}
Above command run each command sequentially but what happens is that it is waiting for the previous command to complete execution before it executes the next command in line. But the problem is that each of above commands are watching different services for changes in file and then compiles them accordingly. So that means that above start command only runs the first command i.e. cmd1 and watching it and does not run the rest of the commands.
I tried using concurrently package but it runs all commands in parallel. I also looked at npm-run-all package but it seems to have an issue when trying to stop the process with ctrl + c key combination because it does not stop the process so I have to close the terminal.
Is there any other way to make them run sequentially while watching all the cmds?
You may write your own Node.js script to do that. Maybe check if the first command emits a string you are looking for (e.g. "Server started on http://localhost:8000/") then execute the next command.
EDIT:
Maybe this is helpful:
#!/usr/bin/env node
/**
* Usage:
* ./runMany.js --command COMMAND1 [AWAITED_OUTPUT_REGEX1] [--command COMMAND2 ...] ...
*/
const { exec } = require('child_process');
const args = process.argv.slice(2);
async function main() {
/** @type {{ command: string; awaitedOutput?: RegExp }[]} */
const commands = [];
for (let i = 0; i < args.length; i++) {
const el = args[i];
if (el === '--command') {
++i;
const command = args[i + 1] || '';
const awaitedOutput =
args[i + 2] === undefined || args[i + 2] === '--command'
? undefined
: (++i, new RegExp(args[i + 2]));
commands.push({ command, awaitedOutput });
}
}
console.table(commands);
let i = 0;
for (const command of commands) {
console.info(`Executing: command ${i}`);
await execute(command);
console.info(`Done: command ${i++}`);
}
}
main();
/** @type {(options: {command: string, awaitedOutput?: RegExp}) => Promise<void>} */
function execute({ command, awaitedOutput }) {
const child = exec(command);
return new Promise((resolve) => {
awaitedOutput ? console.info(`Waiting for output that matches: ${awaitedOutput}`) : resolve();
child.stdout.on('data', (data) => {
const output = data.toString();
if (awaitedOutput?.test(output)) {
resolve();
}
process.stdout.write(output);
});
child.stderr.on('data', (data) => {
const output = data.toString();
process.stderr.write(output);
});
child.on('exit', (code) => {
// if there was an error, exit
if (code) {
process.exit(code);
}
resolve();
});
});
}
Paste it in runMany.js then use it as:
node runMany.js --command 'yarn cmd1' 'THE OUTPUT YOU ARE WAITING FOR FROM cmd1' --command 'yarn cmd2' 'THE OUTPUT YOU ARE WAITING FOR FROM cmd2' --command 'yarn cmd3' 'THE OUTPUT YOU ARE WAITING FOR FROM cmd3' --command 'yarn cmd4' 'THE OUTPUT YOU ARE WAITING FOR FROM cmd4'
You just need to change the start command from:
"start": "yarn cmd1 && yarn cmd2 && yarn cmd3 && yarn cmd4"
to
"start": "yarn cmd1 & yarn cmd2 & yarn cmd3 & yarn cmd4 &"
This should run commands without waiting for previous command to finish.
The running jobs can be found with command "jobs". Those can be brought forward with the command "fg" if you need to kill them one by one before it is finished.
Hope it worksout.
The package npm-run-all seems to have a what you are looking for. npm-run-all with --parallel flag
npm-run-all --parallel cmd1 cmd2 cmd3
Documentation says all running parallel commands are killed if one command is single CTRL+C.
Refer following links to set up each "yarn cmd" with a name.
https://github.com/mysticatea/npm-run-all/blob/HEAD/docs/npm-run-all.md#npm-scripts
Also see "nohup" command if you need to return to terminal without waiting for commands to finish.