child_process.spawn
does not work with npm run scripts
on windows.
# package.json
{
"dependencies": {
"touch": "^1.0.0"
},
"scripts": {
"test": "npm run touch1 --verbose && node test.js",
"touch1": "touch foo.txt"
}
}
# test.js
var spawn = require('child_process').spawn;
var touch1 = spawn('npm', ['run', 'touch1', '--verbose'], { stdio: 'inherit' });
touch1.on('error', function(err) {
console.error(err);
process.exit(1);
});
npm run touch1
works fine both linux and windows.
spawn('npm', ['run', 'touch1'])
works fine on linux.
https://travis-ci.org/sanemat/node-windows-spawn-confirm/builds/89416274
But this does not work on windows.
https://ci.appveyor.com/project/sanemat/node-windows-spawn-confirm/build/1.0.2
{ [Error: spawn npm ENOENT]
code: 'ENOENT',
errno: 'ENOENT',
syscall: 'spawn npm',
path: 'npm' }
Is this nodejs issue? or npm issue?
confirming code: child_process.spawn does not work with npm run scripts on windows. by sanemat 路 Pull Request #2 路 sanemat/node-windows-spawn-confirm
I'd say a local issue. The ENOENT error code is the operating system telling you it can't find npm
. You probably either need to configure your PATH environment variable or use an absolute path.
@bnoordhuis
Thank you for your reply.
On windows environment (appveyor), process.env.PATH includes npm path.
where npm
C:\Program Files (x86)\nodejs\npm
C:\Program Files (x86)\nodejs\npm.cmd
process.env.PATH
C:\Program Files (x86)\nodejs\node_modules\npm\bin\node-gyp-bin;C:\projects\node-windows-spawn-confirm\node_modules\.bin;C:\Perl\site\bin;C:\Perl\bin;C:\windows\system32;C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\bin;C:\Program Files\Google\Compute Engine\sysprep\;C:\Program Files\Google\Compute Engine\metadata_scripts\;C:\ProgramData\chocolatey\bin;C:\Program Files\Microsoft\Web Platform Installer\;C:\Tools\GitVersion;C:\Tools\PsTools;C:\Program Files\7-Zip;C:\Program Files\Git\cmd;C:\Program Files\Git\usr\bin;C:\Program Files\Mercurial;C:\Program Files (x86)\Subversion\bin;C:\Program Files\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\110\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files\Microsoft SQL Server\120\DTS\Binn\;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.4\;C:\Program Files (x86)\Microsoft SDKs\Azure\CLI\wbin;C:\Tools\WebDriver;C:\Tools\NUnit\bin;C:\Tools\xUnit;C:\Tools\MSpec;C:\Tools\Coverity\bin;C:\Program Files (x86)\nodejs\;C:\Program Files\nodejs;C:\Program Files (x86)\iojs;C:\Program Files\iojs;C:\Users\appveyor\AppData\Roaming\npm;C:\Program Files (x86)\CMake\bin;C:\go\bin;C:\Program Files\Java\jdk1.8.0\bin;C:\Python27;C:\Ruby193\bin;C:\Program Files\erl7.1\bin;C:\Users\appveyor\.dnx\bin;C:\Program Files\Microsoft DNX\Dnvm\;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\Program Files (x86)\MSBuild\14.0\Bin;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Tools\NuGet3;C:\Program Files\Amazon\AWSCLI\;C:\Program Files\Microsoft Windows Performance Toolkit\;C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120;C:\Users\appveyor\AppData\Roaming\npm;C:\Program Files\AppVeyor\BuildAgent\
https://ci.appveyor.com/project/sanemat/node-windows-spawn-confirm/build/1.0.17/job/3u42bafouw95to63
Windows being Windows, I'm going to guess that you need to execute npm.cmd
You guess this?
if (windowsEnvironment) {
var cmd = 'npm.cmd'
} else {
var cmd = 'npm'
}
spawn(cmd, ['run', 'touch1'])
Ummm...
Yes, like that. I'll close the bug report as it's not an issue with node.js itself.
thanks.
I can verify: npm.cmd
works. Blegh.
Well, npm.cmd works to launch the process, but later when you want to kill it (e.g. touch1.kill(), assuming that you had started a process that runs forever such as a server), the kill() command silently fails to actually terminate the process.
In my case, "npm start" would run "node server.js"; if I specify spawn('node', ['server.js']) it works beautifully. If I specify proc = spawn('npm.cmd', ['start']), the process is left running after I call proc.kill().
Above problem occurs on linux as well, its because node server.js
is not your direct child, npm is, and it has a shell child, and the shell has a node server.js
child.... POSIX process groups would be the unix way of dealing with this, but process groups don't exist on Windows.
Note that various npmjs.com packages exist to portably spawn npm, check them out.
Thanks!
In case anyone else with a similar issue finds this thread, here was my solution:
const os = require('os');
const process = spawn(...); // long running process
// ... later...
if (os.platform() === 'win32') { // process.platform was undefined for me, but this works
execSync(`taskkill /F /T /PID ${process.pid}`); // windows specific
} else {
process.kill();
}
While I can understand why the existence of a workaround could be considered a solution to this issue, I find the inclination to allow differences to proliferate between OSes disturbing. **Stands on soapbox.** JS is a cross-platform language. Node should be as well. To say that I should worry about Windows while developing in Linux on a MacBook is WRONG. And to say the bugs that come from that are my fault is WRONG. **Gets off soapbox.**
Then use .exec()
or pass { shell: true }
to .spawn()
. It's all in the documentation.
hi i have a problem with spawn
var spawn = require('child_process').spawn;
var bower = spawn('bower', ['install',comp], { stdio: 'inherit' , shell: true});
console.log('********',comp)
bower.on('error', function(err) {
console.error(err);
process.exit(1);
});
bower.on('close', function(code) {
if (code !== 0) {
console.log('Bower failed.');
}
console.log('-------------');
});
bower.on('exit', function(code) {
if (code !== 0) {
console.log('Bower failed.');
}
console.log('-------e------');
});
}
command is executed but i cant intercept when execution is finished
./scripts/watch-demo demos/nn-art/nn-art.ts
events.js:160
throw er; // Unhandled 'error' event
^
Error: spawn node_modules/.bin/watchify ENOENT
at exports._errnoException (util.js:1018:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:193:32)
at onErrorNT (internal/child_process.js:367:16)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickCallback (internal/process/next_tick.js:104:9)
at Module.runMain (module.js:606:11)
at run (bootstrap_node.js:390:7)
at startup (bootstrap_node.js:150:9)
at bootstrap_node.js:505:3
How can I fix this?
@sanemat Can you please elaborate what exactly you did to resolved the issue.
I am running percy exec -- protractor conf.js
i am getting below error.
=====
[percy] created build #8: https://percy.io/J-B-Hunt/StyleGuide/builds/1483709
[percy] percy has started.
events.js:174
throw er; // Unhandled 'error' event
^
Error: spawn protractor ENOENT
at Process.ChildProcess._handle.onexit (internal/child_process.js:240:19)
at onErrorNT (internal/child_process.js:415:16)
at process._tickCallback (internal/process/next_tick.js:63:19)
Emitted 'error' event at:
at Process.ChildProcess._handle.onexit (internal/child_process.js:246:12)
PLease let me know where/which file i have to update ?
Can anyone help me out here ?
@Bhav1907 you should be able to work around that by using protractor.cmd
. Example:
percy exec -- protractor.cmd conf.js
See the test-win
package script here https://github.com/percy/example-percy-protractor/blob/master/package.json#L7
Hi, maybe this can help you.
import { spawn } from "child_process";
// or
const { spawn } = require("child_process");
// alias spawn
const exec = (commands) => {
spawn(commands, { stdio: "inherit", shell: true });
};
// use like this
exec("npm run build");
You can change the function name exec
, maybe run
?
Hey everyone, not sure how relevant my comment is going to be, but i managed to run my npm run
commands using child_process.exec() instead of spawn().
My current example uses a Nrwl workspace, but it can work for any npm commands really.
const exec = require('child_process').exec
const execContext = exec('npm run affected:libs');
const stdOutMessages = [];
execContext.stdout.on('data', (cmd) => {
console.log('Getting stdout data...');
stdOutMessages.push(cmd)
});
execContext.stdout.on('close', () => {
console.log('stdout closed...');
console.log(stdOutMessages.join(''));
});
Produces the following output in the terminal:
Getting stdout data...
Getting stdout data...
Getting stdout data...
stdout closed...
> [email protected] affected:libs C:\Users\qbissoondial\work\my-lib
> nx affected:libs
> NX Affected libs:
- my-lib
I'm on Node version 12 and I ran this on a Windows 10 machine without any problems. I didn't need to use npm.cmd
either.
Then use
.exec()
or pass{ shell: true }
to.spawn()
. It's all in the documentation.
THANK YOU SO MUCH FOR YOUR ANSWER!
I think this {shell:true} should be handled by the spawn command. Node has capacity to determine the right config to use depending on the OS. I really don't understand why they put this as an option.
@AllanOricil
I really don't understand why they put this as an option.
{shell: true}
doesn't just "make .spawn
work" in this case. When you .exec
or .spawn
with shell: true
node will first spawn a shell (cmd.exe by default on windows) and then run the command in that shell.
This is usually not desirable when using spawn
for certain workloads. If you explicitly want this behavior (of having a shell) you can just .exec
like Ben said.
@AllanOricil
I really don't understand why they put this as an option.
{shell: true}
doesn't just "make.spawn
work" in this case. When you.exec
or.spawn
withshell: true
node will first spawn a shell (cmd.exe by default on windows) and then run the command in that shell.This is usually not desirable when using
spawn
for certain workloads. If you explicitly want this behavior (of having a shell) you can just.exec
like Ben said.
@benjamingr thanks for the response. I don't really know if I had exactly same problem, I just know that when I added the following option to my code, it started to work on windows. I'm using sfdx cli, which is built using Ocliff. The sfdx cli allow us to extend the native functionality by creating plugins. I created on plugin that was calling a standard sfdx command using spawn, and it was working fine on linux, but when I ran it on Windows it was not working at all. Then I added the option below and the problem was solved to both environments.
```javascript
shell: os.platform() === 'win32'
````
In my case (windows, trying to run npm/yarn with spawn), passing {shell:true}
as the third argument to spawn
did the trick:
https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
Most helpful comment
Windows being Windows, I'm going to guess that you need to execute npm.cmd