English
npm scripts cross-platform compatibility: Why does && sometimes fail?

A seemingly harmless npm script
First, look at a common scenario. In package.json In it, we often write it like this:
json
{
"scripts": {
"preflight": "node scripts/check.js",
"build": "npm run preflight && vite build"
}
}On macOS or Linux,npm run build Runs perfectly:
Execute first
preflightExecute after success
vite build
But on Windows (native cmd or PowerShell), this command may fail or behave abnormally.
The Culprit: Shell Differences
&& It is not npm syntax, but a command separator interpreted and executed by the current shell.
| environment | Shell | && Behavior |
|---|---|---|
| macOS / Linux | bash / zsh | Supports (execute the next only if the previous succeeds) |
| Windows(Git Bash) | bash | Support |
| Windows(cmd) | cmd | Partially supported, but behavior differs |
| Windows (PowerShell) | PowerShell | Not supported,&& will be treated as an undefined operator |
When your team members use different operating systems,&& It could become a hidden pitfall.
Solution: npm-run-all
npm-run-all It is a tool specifically designed to solve this type of problem, providing a cross-platform way to execute commands.
Install
bash
npm install --save-dev npm-run-allBasic usage
json
{
"scripts": {
"preflight": "node scripts/check.js",
"build:vite": "vite build",
"build": "npm-run-all -s preflight build:vite"
}
}-s Indicates serial execution (sequence), equivalent to &&, but cross-platform compatible.
Before and after renovation comparison
Before modification (with hidden hazards):
json
"build": "npm run preflight && vite build"After modification (cross-platform safe):
json
"build": "npm-run-all -s preflight build:vite"Practical Case: VitePress Project
Taking a real VitePress project as an example, archive data needs to be generated before building:
json
{
"scripts": {
"docs:preflight": "node docs/scripts/generate-archive-data.js",
"docs:build:vitepress": "vitepress build docs",
"docs:build": "npm-run-all -s docs:preflight docs:build:vitepress"
}
}In this way, regardless of whether developers run it on macOS, Linux, or Windows npm run docs:build, can all achieve consistent behavior.
Other useful features of npm-run-all
1. Parallel execution -p
When there are no dependencies between tasks, they can be executed in parallel to save time:
json
"dev": "npm-run-all -p start:server start:client"2. Wildcard batch execution
json
"build": "npm-run-all -s build:*"This will execute all in sequence build:xxx script in the format.
3. Mixed use
json
"deploy": "npm-run-all -s clean build -p deploy:*"Execute serially first clean and build, then execute all in parallel deploy:xxx.
4. Error Handling
In serial mode, the failure of any task will immediately stop subsequent tasks.
In parallel mode, by default it waits for all tasks to complete (can be via
--raceChange)
Comparison of common alternatives
| Plan | cross-platform | serial | parallel | wildcard | Learning cost |
|---|---|---|---|---|---|
&& / & | No | Part | No | No | low |
npm-run-all | Yes | Yes | Yes | Yes | low |
concurrently | Yes | No | Yes | No | middle |
cross-env | Environment variables only | - | - | - | low |
concurrently Focus on parallel execution, while npm-run-all Excels in both serial and parallel.
Best practice recommendations
Use by default
npm-run-all -ssubstitute&&Use when parallelism is needed
npm-run-all -p替代&Cooperate
cross-envSet cross-platform environment variablesMaintain script naming conventions:
xxx:yyyThe format facilitates wildcard matching.
Summary
&& 看起来简单,但它的行为依赖于底层 Shell,在团队协作中可能成为隐患。
npm-run-all Provides a concise, unified, cross-platform solution:
Intuitive grammar:
-sSerial,-pparallelPowerful: supports wildcards and mixed execution
Zero-config migration: replacement
&&Just change one line
If your project has multiple contributors, or needs to support CI/CD environments (possibly running in Linux or Windows containers), it is strongly recommended that you switch now to npm-run-all.