Reputation: 9935
I'm trying to set up a script in package.json which runs all my various watches for Coffeescript/Sass/etc.
This is the script I'm using on my server, which works fine.
"dev": "coffee --watch --compile js/ & coffee --watch --compile controllers/ & supervisor -e html,js js/index.js",
When I try that same script locally however, it only seems to run the first command. Windows doesn't seem like it knows what to do with the &. Every command there works fine run individually, but they won't all execute together.
Upvotes: 10
Views: 13041
Reputation: 1966
I developed concurrently just for this purpose. For example cat a & cat b
can be achieved with concurrently 'cat a' 'cat b'
. Concurrently also provides a few output formatting options for convenience.
Install it as dev dependency npm install --save-dev concurrently
and then it's ready to be used in package.json "scripts".
Upvotes: 22
Reputation: 17964
npm-run-all
from what I've seen is the most popular package for doing this. It adds scripts run-s
(sequential) and run-p
(parallel) to your projects bin, making them usable from your projects scripts section.
For the following package.json
scripts:
"scripts": {
"start": "npm run build -- --watch",
"prebuild": "rimraf lib dist",
"build:dist": "rollup -c --sourcemap inline --environment NODE_ENV:production",
"build": "babel src -d lib --ignore __tests__,__mocks__",
"preversion": "npm run build && npm run build:dist",
"test": "jest"
}
If you wanted to modify the preversion script with npm-run-all
, you could shorten it to run-s build build:dist
. If you wanted them to run in parallel, instead of sequentially, you would use: run-p build build:dist
. It has options for recovering on error, passing arguments to all of the scripts, and works well cross platform.
Lately, I've been splitting my projects up into micro modules. As soon as I start to face the sort of problem you are running into, that is an indication to me that my project is too large. Large projects are beneficial for being able to find everything and keeping a single version for every release, but lead to build and deployment headaches. With large repos you must orchestrate separate builds for the following types of things:
NODE_ENV
)It will turn your package.json into a disaster.
To fix these issues and still maintain nice versioning and coordination, I use Lerna (npm i -g lerna@prerelease
) on every project. It sets up a monorepo with a packages/
directory that contains each of your projects npm packages. Executing lerna bootstrap
then lerna run start
links all packages that are dependencies of one another, then runs your npm start script in all packages that define one. lerna run
commands execute in parallel by default but can be run sequentially with --concurrency=1
. I have found that there is no project too small to warrant using lerna, it makes small projects less cumbersome.
create-react-app
is a great example of a project that is moving the ecosystem to modular design. It has the bare essentials, 3 scripts (start
, test
, build
) and a 4th eject
script whose only use is to vomit the underlying modularized build system into your project directory. Its extremely fast and hot reloads great, but you have less choice (common misconception). You actually are in much better shape not ejecting, and benefiting from a never failing build system that will get solid upgrades. Grow your system horizontally across modules, not exponentially in all directions.
In an attempt to apply this design to the many build systems not covered by create-react-app
(a good thing), I've created noderaider/modular lerna repo. It works fundamentally the same as create-react-app
, but targets CLI / API module creation packages that work nicely with Lerna
and upstream from create-react-app
. I am publishing nightlies under the convention create-<target>-module
. Each of these packages can be run from CLI, package.json scripts, or orchestrated via their node API. It uses yarn for installs if found in path, and falls back to npm
otherwise. It has current working scaffolds for webpack 2, rollup, postcss and CLI packages, as well as unit tests and code coverage. I'm currently working on modularized scripts, further cohesiveness with lerna
/ create-react-app
, and completing the remaining modules on the roadmap. Pull / feature requests welcome. Expect each package to rapidly spit you out a building, testable, publishable package with travis-ci integration and rapid change prior to 1.0.0
per semver.
TL;DR Use Lerna and modular packages and you will shed these types of problems
Upvotes: 6
Reputation: 2262
There is also a good node package called parallelshell. Install it with :
npm install --save-dev parallelshell
Then execute with:
parallelshell "command 1" "command 2" "command 3"
The advantages of this approach (more detail from the link above) instead of command 1 & command 2 & command 3
include: It's cross-platform; ctrl-c ends all 3 processes; and if one dies they all die, unlike using &
.
Upvotes: 0
Reputation: 616
The problem with mscdex's answer is that there is no easy way to kill those background tasks after they have started. You have to go to task manager and kill them.
Instead, the easiest way to run two tasks is just make it open up two command windows.
ex: "dev": "start coffee --watch --compile js/ & start coffee --watch --compile controllers/ & start supervisor -e html,js js/index.js
If you run 'npm run dev' you will then have a command window open for each of those processes and they can be stopped individually. You dont need the /b switch. I am using "start": "start webpack --watch & start reload -b" to run webpack and reload
Upvotes: 0
Reputation: 106746
For Windows, the built-in equivalent to &
is instead prefixing the command with start /B
. So you may just have "dev" set to a small node script that uses the built-in child_process
to do something like:
var exec = require('child_process').exec;
var prefix = (process.platform === 'win32' ? 'start /B ' : '');
exec(prefix + 'coffee --watch --compile js/');
exec(prefix + 'coffee --watch --compile controllers/');
exec(prefix + 'supervisor -e html,js js/index.js');
Upvotes: 4