Appearance
npm scripts 跨平台兼容性:为什么 && 有时会失败?
一个看似没问题的 npm script
先看一个常见场景。在 package.json 中,我们经常这样写:
json
{
"scripts": {
"preflight": "node scripts/check.js",
"build": "npm run preflight && vite build"
}
}在 macOS 或 Linux 上,npm run build 完美运行:
- 先执行
preflight - 成功后执行
vite build
但到了 Windows 上(原生 cmd 或 PowerShell),这条命令可能失败或行为异常。
罪魁祸首:Shell 差异
&& 并不是 npm 的语法,而是由当前 Shell 解释执行的命令分隔符。
| 环境 | Shell | && 行为 |
|---|---|---|
| macOS / Linux | bash / zsh | 支持(前一条成功才执行后一条) |
| Windows(Git Bash) | bash | 支持 |
| Windows(cmd) | cmd | 部分支持,但行为有差异 |
| Windows(PowerShell) | PowerShell | 不支持,&& 会被当作未定义的运算符 |
当你的团队成员使用不同操作系统时,&& 就可能成为隐藏的坑。
解决方案:npm-run-all
npm-run-all 是一个专门为解决这类问题而设计的工具,它提供了跨平台的命令执行方式。
安装
bash
npm install --save-dev npm-run-all基本用法
json
{
"scripts": {
"preflight": "node scripts/check.js",
"build:vite": "vite build",
"build": "npm-run-all -s preflight build:vite"
}
}-s 表示串行执行(sequence),效果等同于 &&,但跨平台兼容。
改造前后对比
改造前(有隐患):
json
"build": "npm run preflight && vite build"改造后(跨平台安全):
json
"build": "npm-run-all -s preflight build:vite"实战案例:VitePress 项目
以一个真实的 VitePress 项目为例,构建前需要先生成归档数据:
json
{
"scripts": {
"docs:preflight": "node docs/scripts/generateArchiveData.js",
"docs:build:vitepress": "vitepress build docs",
"docs:build": "npm-run-all -s docs:preflight docs:build:vitepress"
}
}这样,无论开发者在 macOS、Linux 还是 Windows 上执行 npm run docs:build,都能获得一致的行为。
npm-run-all 的其他实用功能
1. 并行执行 -p
当任务之间没有依赖关系时,可以并行执行以节省时间:
json
"dev": "npm-run-all -p start:server start:client"2. 通配符批量执行
json
"build": "npm-run-all -s build:*"这会依次执行所有 build:xxx 格式的脚本。
3. 混合使用
json
"deploy": "npm-run-all -s clean build -p deploy:*"先串行执行 clean 和 build,再并行执行所有 deploy:xxx。
4. 错误处理
- 串行模式下,任何任务失败都会立即停止后续任务
- 并行模式下,默认等待所有任务完成(可通过
--race改变)
常见替代方案对比
| 方案 | 跨平台 | 串行 | 并行 | 通配符 | 学习成本 |
|---|---|---|---|---|---|
&& / & | 否 | 部分 | 否 | 否 | 低 |
npm-run-all | 是 | 是 | 是 | 是 | 低 |
concurrently | 是 | 否 | 是 | 否 | 中 |
cross-env | 仅环境变量 | - | - | - | 低 |
concurrently专注于并行执行,而npm-run-all同时擅长串行和并行。
最佳实践建议
- 默认使用
npm-run-all -s替代&& - 需要并行时使用
npm-run-all -p替代& - 配合
cross-env设置跨平台环境变量 - 保持脚本命名规范:
xxx:yyy格式便于通配符匹配
总结
&& 看起来简单,但它的行为依赖于底层 Shell,在团队协作中可能成为隐患。
npm-run-all 提供了一个简洁、统一、跨平台的解决方案:
- 语法直观:
-s串行,-p并行 - 功能强大:支持通配符、混合执行
- 零配置迁移:替代
&&只需改一行
如果你的项目有多个 contributors,或者需要支持 CI/CD 环境(可能运行在 Linux 或 Windows 容器中),强烈建议现在就切换到 npm-run-all。
