Phantom007
Phantom007

Reputation: 2249

Realtime outputting progress using nodejs

When I run the npm run react-build command on the command line, it shows the progress during the build process, but when I run the same command using nodejs from command-line, it builds first and then shows the entire output after that.

How can I make my script show the progress while processing?

// index.js    
try {
  await execShellCommand("npm run react-build");
}catch(error) {
  console.error(error)
}

function execShellCommand(cmd) {
  const exec = require("child_process").exec;
  return new Promise((resolve, reject) => {
    exec(cmd, (error, stdout, stderr) => {
      if (error) {
        console.warn(error);
        return reject(error);
      }
      console.info(stdout);
      console.info(stderr);
      resolve(stdout ? stdout : stderr);
    });
  });
}

Upvotes: 2

Views: 2068

Answers (2)

Eugene Obrezkov
Eugene Obrezkov

Reputation: 2986

You are buffering the logs from stdout\stderr, not the streaming them. According to the exec docs:

Spawns a shell then executes the command within that shell, buffering any generated output.

Meaning, it waits until the command will be done and only then calls the callback with all the stdout\stderr it collected.

I believe you should take a look into spawn command. According to spawn docs you will get a stream of data from stdout\stderr:

const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

NOTE: though, it does not guarantee that it will show the progress bar properly. Because those progress bars are highly related on VT100 control sequences and I'm not sure how Node.js will handle them in these streams.

Upvotes: 2

nikoss
nikoss

Reputation: 3678

This happens because when you run the command in your shell you are using an interactive shell but when you use exec you are executing the thing and only when it is completed getting the output.

instead of exec you can use spawn and as seen on the arguments instead of returning you the result you can subscribe for the events such as stdout also it has a shell option which you should set to true for getting same interactive behavior

Upvotes: 0

Related Questions