npm-run-all
npm-run-all copied to clipboard
Broken with npm@7 when using npx ("Need to install the following packages: run")
After upgrading to npm@7, using npx npm-run-all ... stops execution and asks the user to install some run package (not a thing! don't do it!).
Example Command:
C:\Users\useruser\code\projectname>npx npm-run-all my:script
Need to install the following packages: run Ok to proceed?
Log reveals that execution is broken:
0 verbose cli 'C:\Users\useruser\AppData\Local\Volta\tools\image\node\16.0.0\node_modules\npm\bin\npm-cli.js', 0 verbose cli 'exec', 0 verbose cli '--', 0 verbose cli 'run', 0 verbose cli 'my:script'
Node@{15,16}, NPM@7 (via Volta) OS: Windows 10
Analysis
This happens because run-task.js determines npmPath from the execution of itself. However, in the latest version, if using npx, it will actually resolve to npx-cli.js which then tries to execute npx run ... (instead of npm run ...).
Workaround
Don't use npx. If (like in my case), the binaries did not get linked properly, use this instead:
node node_modules/npm-run-all/bin/npm-run-all -p script1 script2
For a shortcut, you can add the following to your package.json -> scripts:
"nra": "node node_modules/npm-run-all/bin/npm-run-all"
and then:
npm run nra -- -p script1 script2
I have the same issue on Mac OS Big Sur as well. If you accidently say yes to install run then it continues to try to consider each script name as a file module and as expected it can't find it.
$ npx npm-run-all --parallel "test:*"
# should run test:unit and test:lint scripts
instead,
Starting: test:v2
internal/modules/cjs/loader.js:883
throw err;
^
Error: Cannot find module 'Error: Cannot find module '/Users/username/project/test:unit'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
at Function.Module._load (internal/modules/cjs/loader.js:725:27)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
at internal/main/run_main_module.js:17:47 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}
The workaround that worked for me was to include an explicit reference to npm with --npm-path npm:
So my package.json looks like:
"scripts": {
"do:all-the-things": "npx npm-run-all --npm-path npm do:a-thing do:another-thing",
"do:a-thing": "echo 'thing'",
"do:another-thing": "echo 'thing'"
}
The same issue, when running npx -y ts-node --project ./helpers/tsconfig.json "./helpers/spell-check.ts" and using NodeAPI in spell-check.ts.
Using const options: { npmPath: "npm" } helped, thanks @elwinschmitz !
Spent 1.5 hours debugging on Teams call... For some reason, it didn't ask for run to be installed. Maybe, because I was running npx with -y flag? Or because my colleague accepted installation? Not sure, but the symptoms were pretty hard to debug. It said:
Watching C:\ws4\UMP\LicencingService\ClientApp and all sub-directories not excluded by your .gitignore. Will not monitor dotfiles.
Found & ignored ./DAT\npm\node_modules ; is listed in .gitignore
Found & ignored ./node_modules ; is listed in .gitignore
Starting: cspell
and the process never ended.
This should be handled by the library here: https://github.com/mysticatea/npm-run-all/blob/bf91f94ce597aa61da37d2e4208ce8c48bc86673/lib/run-task.js#L157
something like:
// Required due to changes in npm@7+
let defaultNpmPath = process.env.npm_execpath;
if (defaultNpmPath && defaultNpmPath.endsWith('npx-cli.js')) {
defaultNpmPath.replace(/npx-cli\.js$/, 'npm-cli.js');
}
const npmPath = options.npmPath || defaultNpmPath;
I use npx run-s blah1 blah2 ... all the time from the cli (actually with an even shorter alias) and this hasn't worked since we upgraded node to 16.13.1 a couple of weeks ago. The @Domiii workaround is helpful but does not work once you stray deeper under the package.json directory of the current project (something npx handles).
Edit: @elwinschmitz solution is working for me. Thanks.
Forking @elwinschmitz's solution, you can instead avoid npx entirely:
"do:all-the-things": "npm-run-all do:a-thing do:another-thing",
My use case relies on npx... I'm using npm like traditional "make" where I might want to run multiple targets from the cli, sequentially. example:
npx run-s --npm-path clean build install run
^-- where I might not want to have a dedicated package script for every permutation of targets
The alias is now working like this:
alias npr='npx run-s --npm-path npm'
(..although run-s occasionally loses a symlink after cleaning the node_modules and running npm install)
My team uses npm directly instead of relying on tools like grunt, etc. So the package.json already has a pretty comprehensive set of scripts that are responsible for building and running the code.
@koba04 this might become a severe security vulnerability if someone figures out the way to put malicious code to the run npm package. Despite run is not updated for 7 years it has 50k+ downloads a week, probably the majority is because people don't pay attention and agree to install it or use npm in non-interactive environments (like Docker) where npx installs required packages automatically.
This cropped up for me in the trufflesuite/truffle monorepo because we were running lerna bootstrap as npx lerna bootstrap to avoid the chicken/egg problem of needing to install lerna as a local dependency before you can bootstrap.
We're a yarn-only project, and switching that command to yarn exec lerna bootstrap worked around this issue.
Swapping out the npx ... command for npm exec -- ... also seems to work around this problem.
I'm open to landing a patch to the maintenance fork I have if anyone has a clue how to best fix: https://github.com/bcomnes/npm-run-all2/issues/93#issuecomment-1304280790
I might take a stab myself soon but figured I would put the offer out there in the meantime.
Landed a fix for this: https://github.com/bcomnes/npm-run-all2/releases/tag/v6.0.4