npm script 的一个常见痛点是跨平台兼容性问题。在类Unix系统(Linux、macOS)中通用的Shell命令,在Windows环境下(如CMD或PowerShell)往往无法直接运行。例如,文件操作命令(rm, cp, mkdir)和环境变量的语法在不同平台间存在显著差异。
一个简单粗暴的解决方法是为不同平台编写不同的脚本,但这违背了DRY原则,并增加了维护成本。
{
"scripts": {
"bash-script": "echo Hello $npm_package_name",
"win-script": "echo Hello %npm_package_name%"
}
}幸运的是,社区提供了许多优秀的工具,可以帮助我们编写一次即可在所有主流平台运行的 npm script。
建议:在Windows环境下,推荐使用 Git Bash 作为运行
npm script的终端,它可以提供更接近类Unix系统的体验,减少兼容性问题。
对于常见的文件和目录操作,我们可以使用以下跨平台工具来替代原生Shell命令:
rm -rf,用于强制删除文件和目录。cp -r,用于递归地复制文件和目录。mkdir -p,用于创建多层嵌套的目录。改造步骤如下:
安装依赖:
npm install rimraf cpr make-dir-cli --save-dev更新 package.json 中的脚本:
假设我们有以下脚本:
{
"scripts": {
"cover:cleanup": "rm -rf coverage .nyc_output",
"cover:archive": "mkdir -p coverage_archive/1.0.0 && cp -r coverage/* coverage_archive/1.0.0"
}
}使用跨平台工具进行改造后:
{
"scripts": {
"cover:cleanup": "rimraf coverage .nyc_output",
"cover:archive": "make-dir coverage_archive/1.0.0 && cpr coverage/* coverage_archive/1.0.0 -o"
}
}注意:cpr 命令需要使用 -o (--overwrite) 参数来覆盖已存在的文件,并且其参数顺序是固定的:cpr <source> <destination> [options]。
不同平台引用环境变量的语法也不同($VAR vs %VAR%)。cross-var 工具可以解决这个问题,它允许你在所有平台统一使用类Unix的 $ 语法。
安装依赖:
npm install cross-var --save-dev更新脚本:
只需在需要使用变量的命令前加上 cross-var 即可。如果命令中包含多个部分,需要用引号将其包裹起来。
{
"scripts": {
"cover:archive": "cross-var \"make-dir coverage_archive/$npm_package_version && cpr coverage/* coverage_archive/$npm_package_version -o\"",
"cover:serve": "cross-var http-server coverage_archive/$npm_package_version -p $npm_package_config_port"
}
}如果你关心依赖的体积,可以考虑使用
cross-var-no-babel,它是一个不依赖Babel的轻量级版本。
在脚本中设置环境变量也存在平台差异(NODE_ENV=production command vs set NODE_ENV=production && command)。cross-env 是解决此问题的标准方案。
安装依赖:
npm install cross-env --save-dev更新脚本:
在设置环境变量的命令前加上 cross-env 即可。
{
"scripts": {
"test": "cross-env NODE_ENV=test mocha tests/"
}
}npm script 中,优先使用双引号,并对特殊字符进行转义。eslint, mocha, webpack)本身已经处理了跨平台兼容性问题。cross-platform 或 cross- 前缀的包,通常都能找到成熟的解决方案。本节用到的代码见 GitHub,想边看边动手练习的同学可以拉下来自己改,注意切换到正确的分支
06-add-cross-platform-support。