npm-run-all
npm-run-all copied to clipboard
Consolidation of multiple similar libraries
Hi @mysticatea and @k88hudson! Thanks for your hard work with npm-run-all
!
I maintain a similar library - the functionality is slightly different but it shares a lot of common functionality with npm-run-all
. My library is called parallelshell - which I maintain with @paulpflug. I am also aware of a few other libraries that attempt to solve the problem of properly parallelising npm (or shell) tasks:
-
concurrently
which is written by @kimmobrunfeldt and has had contributions from @luv2code. -
shell-executor
which is written by @royriojas. -
npm-parallel
which is written by @spion -
pkgrun
which is written by @reggi
We're all trying to reach the same goal - run npm tasks quickly and easily in parallel (and sometimes serially), and have them log & exit in ways you'd expect. For the most part, each of us (I presume) has convergently developed these solutions. While it's great that we're all solving this problem, its bad that we're all solving it...
The point
I think we should combine forces, to make one canonical parallelisation tool. Personally, I see no point in continuing development of both parallelshell
and npm-run-all
- we may as well just have one. Having said that, I'm still using parallelshell
because it solves particular bugs that I (and @paulpflug) have solved (with great pain) which npm-run-all
is yet to solve.
The way I see it - I'm happy (as long as @paulpflug is) to port the fixes we have developed in parallelshell
, over to npm-run-all
rather than expend effort developing the features I want from npm-run-all
inside of parallelshell
. I dont want to speak for all other developers (@paulpflug, @kimmobrunfeldt, @luv2code, @royriojas, @spion, and @reggi) - but I for one would certainly like for all of these projects to consolidate under one label. If and when these projects converge, I'd like everyone of the original authors/contributors to be a contributor of the new project - to ensure that it remains well maintained. How does this sound to you?
FYI, I chose to file this issue here - rather than any of the other projects - because I think this project has the best name. By and large they are pretty much all interchangeable (or certainly could be with a bit of development).
Summary
-
npm-run-all
andparallelshell
are very similar (as are other projects) - We should develop one
- (IMO) All of the maintainers of the other projects should all be core contributors of this project, and deprecate their respective projects.
- Everyone is happy and users have one well developed tool to chose from.
I'm okay with unifying into this project.
:+1:
Yeah, I just figured out https://github.com/mysticatea/npm-run-all/issues/6 :(
I was thinking of writing an alternate implementation that uses the data from package.json
but doesn't rely on npm run
at all - especially given that npm run
seems to be so slow (or is it just slow for me?)
In any case, I agree it would be best if the effort was concentrated, but personally I'm not sure what the direction should be...
Wow, really interesting. I am grateful for your proposal. I'd like to cooperate to make helpful tool for developers!
@spion I feel npm run
is slow too. So I have been thinking that directly-spawn content of npm tasks. But it's very hard....
:+1: happy to merge, help or document :), I guess #6 is an issue that most of us have faced at some point, probably the most important thing a library that runs several things in parallel should have.
I would definitely say spawning from the package.json, rather than npm run
is a good idea. parallelshell has been working on solving the problem of properly killing subshells and the processes running in them, and we have https://github.com/keithamus/parallelshell/pull/30 which is going pretty well thanks to @paulpflug. I think we could take this and turn it into a PR for npm-run-all
.
Not depending on npm run
as an executable also opens us up to the ability to have npm-run-all
run arbitrary scripts, not just npm ones - perhaps with a -e
flag (e.g. npm-run-all build:* --sequential -e 'echo "done!"'
).
Also I think it'd be a good idea to see how npm run
itself works. Here's the run-script command which mostly builds up which scripts to run (e.g. pre
and post
prefixes) - L159-167 build up the commands to run, and L166 is what each command runs (i.e. it calls the lifecycle
command with the package json, command, working directory and true
). lifecycle.js is basically all of the execution magic, including making all of the env vars, building the shell string and actually running the command. When it all comes down to it, all npm run
is essentially doing export ${lots_of_env_vars}; sh -c ${npm_script_string}
.
I would be interested in @othiym23 and @isaacs opinions about possibly modularising some of this - so we can all re-use the same piece of code for execution logic. They may well also have some insight for us as they wrote most of npm's lifecycle.js :smile: (although most of that code is 5 years old and so I'd understand if they've forgotten).
I too think that merging these projects makes sense. One comment about the naming though. I chose a general name because concurrently is not tied to npm run scripts, you can also use the tool for any shell command.
How about we make 2 packages. the first focusing on sequential and parallel shell execution (name maybe 'parallelshell') and the second focusing on launching npm tasks (grep from project.json or similar)) while depending on the first for execution (name maybe 'npm-run')
I think that would be super transparent for the users and limits the necessary flag count.
I agree, that sounds like a good idea.
Thanks @keithamus for putting this together. I love this idea. I too think that this should have a more general name and not be npm
specific. Just to play devils advicate, I'd love this all to be within one project with special flags for npm
specific functionality (e.x. --npm-run
or --pkg-glob
) , just a thought. I embrace a clean / clear UNIX based design, but keeping in mind that we're all node.js developers and that whatever this thing ends up being is going to be very tied to that ecosystem is important. However two commands as @paulpflug describes also makes sense. :+1:. With all that said I'm looking forward to seeing this through and would love to help in any capacity.
Just found these projects that touch on this stuff.
- https://github.com/benoror/better-npm-run
- https://github.com/bahmutov/with-package
Hey everyone, awesome to see this coming together :+1: npm scripts for the win!
Personally I see two separate but related goals here;
- To run tasks in parallel in a way that works on all platforms
- To provide a better syntax for organizing and running npm scripts or groups of npm scripts
Obviously Windows compatibility is a goal for both 1 and 2, so some code/ideas could be shared, but I would prefer to see them remain separately focused on their respective goals.
If anyone is interested, I know some people on npm/who work on the cli and I would be happy to reach out if they have suggestions, or if any of you want to provide some feedback.
Thanks so much @keithamus for opening this issue and for linking to everyone's projects, you are all awesome :dancer: I'm giving another talk on npm scripts at View Source conf in November, and I can tell you more and more people are getting excited about doing front end automation this way thanks to your work and blog posts :smile:
In fact, I will definitely bring this up with the folks at npm. Thanks also @mysticatea for writing this :)
Hey @k88hudson! Thanks for the kind words. I definitely think feedback from the peeps at npm would help here.
Aside; @k88hudson I watched your (absolutely excellent) npm talk at Nordic.js which led me to npm-run-all
and prompted this issue. Small world :earth_asia:!
I thought about it a while, here is what I want:
- one project - three cli's
- the commands should be short and make no flags necessary in default mode
-
run-seq
/run-para
for running whatever in parallel or sequential (mainly for use in package.json, e.g.:{"scripts":"{"first":"run-seq 'echo 1' 'echo 2'"}
) -
run-npm
as a drop-in replacement fornpm run
with wildcards as a main feature. On console:run-npm watch:*
would call all scripts starting withwatch:
in parallel. Callingrun-npm watch
should act as a shorthand fornpm-run watch:*
(yes I really want to save that line"watch":"Call all other watches"
in package.json) Sadlynpm-run
is already taken. - advanced scripts featuring placeholders (example for package.json:
{"adv-scripts":"first":"ENV=%1 echo %2"}
, would be called this waynpm-run first VAR1 'hello world'
) This will make it possible to create meta package.json, which holds scripts for several other projects:{"adv-scripts":"git:push":"cd %1 && git push"}
- coffee-script - or anything else without curly brackets .. I hate them, mainly because of the german keyboard layout ;)
In my eyes a unsolved problem of all project-processing methods is to handle several projects. The worst case: Say I researched recently and found a new postprocessing tool far better than the other tool I used in 5 of my projects and now I want to migrate... But even simple tasks like "bump the version of 4 projects and push them to github" is difficult.
Maybe we could collect what all others want and start putting a feature list together - so the development can start :smile:
- one project - three cli's
- the commands should be short and make no flags necessary in default mode
- run-seq / run-para for running whatever in parallel or sequential (mainly for use in package.json, e.g.: {"scripts":"{"first":"run-seq 'echo 1' 'echo 2'"})
On the surface this idea seems good; because having a mix of flags is a bit of a pain, and a bit hard to disambiguate. However when you consider the power of npm-run-all
chaining multiple commands, you can see that npm-run-all
currently does a better job:
$ npm-run-all --sequential a b c --parallel d e f --sequential g h i
# To do this with three commands:
$ run-series a b c && run-parallel d e f && run-series g h i
# Or
$ run-series 'run-sequential a b c' 'run-parallel d e f' 'run-sequential g h i'
I have some tasks in a project right now which are mix of sequential and parallel (build all the things, then watch the output with several tools and serve html all at once). npm-run-all
facilitates this in - what I think - the easiest way possible.
Having said that I think it could end up being pretty hairy having command line, npm, sequential and parallel all wrapped in one lib. How about the following instead:
-
One project, two clis
-
The two commands are
run-all
andnpm-run-all
-
run-all
takes a set of strings, which are shell commands, and--series
and--parallel
commands which behave much likenpm-run-all
does now.$ run-all 'echo hello' 'echo world' hello world $ run-all 'sleep 1 && echo hello' 'echo world' hello world $ run-all --parallel 'sleep 1; echo hello' 'echo world' world hello $ run-all 'echo 1' --parallel 'sleep 2; echo 2' 'sleep 1; echo 3' 'echo 4' 1 4 3 2
-
npm-run-all
works pretty much as it always did; it matches the behaviour ofrun-all
except it calls aliases for npm-scripts:$ npm-run-all test:* build:* --parallel watch:*
- run-npm as a drop-in replacement for npm run with wildcards as a main feature. On console: run-npm watch:* would call all scripts starting with watch: in parallel. Calling run-npm watch should act as a shorthand for npm-run watch:* (yes I really want to save that line "watch":"Call all other watches" in package.json) Sadly npm-run is already taken.
I like the idea of npm-run watch
defaulting to an alias for npm-run watch:*
but we should make sure it is overridable. I imagine the logic to be a bit like this:
if packageJson.watch
run packageJson.watch
elseif !packageJson.watch && packageJson.watch:*
run --series packageJson.watch:*
- advanced scripts featuring placeholders (example for package.json: {"adv-scripts":"first":"ENV=%1 echo %2"}, would be called this way npm-run first VAR1 'hello world') This will make it possible to create meta package.json, which holds scripts for several other projects: {"adv-scripts":"git:push":"cd %1 && git push"}
I'm going to disagree with this on a few points:
- I think
package.json#config
is sufficient for metadata (although the environment variable is a little on the verbose side for my liking:$npm_package_config_<thing>
). - If a package is so complex that it requires many config vars, it should probably be a script.
- I think we need to be careful about exactly what we're implementing here. To me - the core feature set is "run commands in parallel in a cross compatible way" and "use that as a basis to quickly orchestrate a set of npm scripts". IMO anything else is scope-creep.
- coffee-script - or anything else without curly brackets .. I hate them, mainly because of the german keyboard layout ;)
Ew no! Babel or bust!
In my eyes a unsolved problem of all project-processing methods is to handle several projects. The worst case: Say I researched recently and found a new postprocessing tool far better than the other tool I used in 5 of my projects and now I want to migrate... But even simple tasks like "bump the version of 4 projects and push them to github" is difficult.
I agree, this is a problem (well, for my work its managing hundreds of components and keeping everything up to date and standardised across the board). I think this is an orthogonal problem though - mostly one of provisioning and less about orchestrating tasks.
I like the idea of run-all
and npm-run-all
.
The collection of small programs is definitely good, but package.json#scripts
field has small area, so I'd like to keep compact notation of this tool.
coffee-script - or anything else without curly brackets .. I hate them, mainly because of the german keyboard layout
I was surprised by the location of brace's keys!
But this tool has many asynchronous loops, so I'd like to use async/await
(an ES stage 3 proposal).
BTY, I think we should be looking at https://github.com/npm/npm/pull/9970 .
I'm thinking maybe we should change the separator of Glob-like patterns of npm-run-all
.
Though I will add collaborators of this repository, may I add all people who is joining this conversation?
And there are requests about making changes.
- Doesn't commit changes to the master branch directly.
- Creates a PR then other members review it.
I like @paulpflug's idea of having separate CLI commands for parallel and sequential run.
In @keithamus' example:
$ npm-run-all --sequential a b c --parallel d e f --sequential g h i
# To do this with three commands:
$ run-series a b c && run-parallel d e f && run-series g h i
# Or
$ run-series 'run-sequential a b c' 'run-parallel d e f' 'run-sequential g h i'
I like 2nd(this is not an option because lack of windows support) and 3rd more because they explicitly state which steps are run sequentially and which are run parallel. The 1st command has implicit hidden information: all those substeps are run sequentially.
I think we have enough to get a prototype going. I'm going to make some time this weekend to get a first draft done and we can all see where to go from there.
This sounds really good. Has there been any development on this? I'm currently using npm-run-all
because it seems like it is going to be the destination project for all these similar efforts. The "one cross-platform, parallel script runner to rule them all". Any way I can help?
@keithamus Good on you for opening this Issue and burying your lib in exchange for working together for an even better one. GitHub needs more developers like you. :+1:
Also, thank you for your article on switching to npm. I just made the switch because of it and it's beautiful over here.
Now if you'll excuse me, I have to go build yet another grid system to pollute the sea of grids with... :(
@mysticatea Oh and good job on this. Works like a charm!
Thanks for the kind words @corysimmons.
I know I said I'd get a draft done a couple of months ago - things got a bit in the way, but rest assured it is on my todo list (item number 3 :wink:) so I'll be pushing some code soon.
hey,
Because I needed more functionality, I created a tool yesterday. Now it is finished with unit tests but without much documentation yet. Haven't run the tests on windows, though.
So here is the spawn wrapper better-spawn with all the things I learned from parallelshell.
And here the script-runner
Usage
usage: run [<options> [cmd..]..]
options:
-h, --help output usage information
-v, --verbose verbose logging (not implemented yet)
--silent suppress output of children
-t, --test no runing only show process structure
-s, --sequential following cmds will be run in sequenz
-p, --parallel following cmds will be run in parallel
-i, --ignore the following cmd will be ignored for --first, --wait and errors
-f, --first only in parallel block: close all sibling processes after first exits (succes/error)
-w, --wait only in parallel block: will not close sibling processes on error
-m, --master only in parallel block: close all sibling processes when the following cmd exits. exitCode will only depend on master
-f, --first close all sibling processes after first exits (succes/error)
run also looks in node_modules/.bin for cmds
run-para is a shorthand for run --parallel
run-seq is a longhand for run
run-npm will match cmd with npm script and replace them, usage of globs is allowed
run-npm currently uses minimatch, but I'm not fully statisfied
I thought about templating of scripts:
Say we have a script "test":"mocha :'1'"
npm run test # would run mocha
npm-run test # would run mocha
npm-run test(--watch) # would run mocha --watch
It would be not to hard to implement, but I can't think of a use case currently
Sorry to butt in. I came across parallelshell from an adventure in building with VS Code. It didn't work, so I went to its site, which led me here. Anyway...
Quoth the @kimmobrunfeldt:
In @keithamus' example:
$ npm-run-all --sequential a b c --parallel d e f --sequential g h i # To do this with three commands: $ run-series a b c && run-parallel d e f && run-series g h i # Or $ run-series 'run-sequential a b c' 'run-parallel d e f' 'run-sequential g h i'
I like 2nd(this is not an option because lack of windows support) and 3rd more because they explicitly state which steps are run sequentially and which are run parallel. The 1st command has implicit hidden information: all those substeps are run sequentially.
I'm confused as to your Windows comment. Using &&
works the same for me in Windows as it does in Unix/Linux--it runs the commands in series if the previous command succeeded. Maybe it changed with recent versions of Windows... What doesn't work the same is &
. Also, what is the difference between run-series
and run-sequential
in the above example? Couldn't you just do run-sequential 'run-sequential a b c' 'run-parallel d e f' 'run-sequential g h i'
? Honestly, with &&
, I'm not sure run-series
is even necessary, that's what &&
does (technically, that's what ;
on Unix/Linux and &
on Windows does; &&
also checks exit codes). I believe that the third command is irrelevant because of this.
I agree that the first command is bad in that it includes an implicit behavior, another reason I prefer the second example. I would suggest that, if you boil this down to one command with aliases, that the one command considers --sequential
and --parallel
mutually exclusive. Having used commands with ordered parameters in the past, it can easily become a PITA, requires additional knowledge, is more error-prone and isn't very intuitive, IMHO.
The second command, however, does brings up a question: what to do with exit codes (if anything)? None of these examples use ||
in case one (or more? or all?) of the parallel commands fails. This is where I think the decomposition and flexibility in the second example really shows its value. For example, imagine something like this (which isn't great, I just tried to make it more realistic than a b c):
run-series clean initEmail
&& run-parallel --must-succeed build 'sendEmail --subj="building \"${projName}\"" [email protected]'
&& run-series --any-must-succeed 'minify -d app/js -r "^.*\\.js"' imgify
&& run-parallel emailDev emailMgrs
|| run-series pkgErr emailDev
Although, since run-series
is (so far, as I understand it) redundant, this could really be:
npm run clean && npm run initEmail
&& npm run-all --all-must-succeed build 'sendEmail --subj="building \"${projName}\"" [email protected]'
&& npm run minify -- -d app/js -r "^.*\\.js" && npm run imgify
&& npm run-all --any-must-succeed emailDev emailMgrs
|| npm run pkgErr && npm run emailDev
I could see needing run-series
in order to bridge the gap between ;
and &
to allow users to run commands cross-platform in series regardless of exit code.
Lastly, I am very glad you all agreed to combine your efforts. There is way too much fragmentation and duplication of purpose and effort these days.
I think we can agree this is a difficult topic.. we only have 1 line, no syntax highlighting and '
as an indicator for nesting.
With npm run
we can get hold on the 1 line and nesting problem. But with the syntax we have a clear tradeoff between verbosity and clarity. I think the best way is to offer both possibilities..
I'm strongly for ordered parameters as &&
, ||
and all other also have a significant order and everything else would be confusing.
So for you example, I think a desireable syntax would be:
run-npm clean initEmail buildAndEmail minify --any emailDev emailMgrs --on-error pkgErr emailDev
with all nested commands hidden behind own npm scripts.
Hi all, may I know what's the status of the consolidation of all projects? Is there any possibility to create a Github organization and put all related repos in there?
Which project is the one where you are all merging into ?
it's npm-run-all.
I'm confused as to your Windows comment. Using && works the same for me in Windows as it does in Unix/Linux--it runs the commands in series if the previous command succeeded. Maybe it changed with recent versions of Windows...
Ok thanks for clarifying, I wasn't sure as I haven't used a windows shell for a while.
Any update on this?