{T}

跨平台兼容

npm script 的一个常见痛点是跨平台兼容性问题。在类Unix系统(Linux、macOS)中通用的Shell命令,在Windows环境下(如CMD或PowerShell)往往无法直接运行。例如,文件操作命令(rm, cp, mkdir)和环境变量的语法在不同平台间存在显著差异。

一个简单粗暴的解决方法是为不同平台编写不同的脚本,但这违背了DRY原则,并增加了维护成本。

json
{
  "scripts": {
    "bash-script": "echo Hello $npm_package_name",
    "win-script": "echo Hello %npm_package_name%"
  }
}

幸运的是,社区提供了许多优秀的工具,可以帮助我们编写一次即可在所有主流平台运行的 npm script

建议:在Windows环境下,推荐使用 Git Bash 作为运行 npm script 的终端,它可以提供更接近类Unix系统的体验,减少兼容性问题。

文件系统操作的跨平台兼容

对于常见的文件和目录操作,我们可以使用以下跨平台工具来替代原生Shell命令:

  • rimraf: 替代 rm -rf,用于强制删除文件和目录。
  • cpr: 替代 cp -r,用于递归地复制文件和目录。
  • make-dir-cli: 替代 mkdir -p,用于创建多层嵌套的目录。

改造步骤如下:

  1. 安装依赖

    bash
    npm install rimraf cpr make-dir-cli --save-dev
  2. 更新 package.json 中的脚本

    假设我们有以下脚本:

    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"
      }
    }

    使用跨平台工具进行改造后:

    json
    {
      "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的 $ 语法。

  1. 安装依赖

    bash
    npm install cross-var --save-dev
  2. 更新脚本

    只需在需要使用变量的命令前加上 cross-var 即可。如果命令中包含多个部分,需要用引号将其包裹起来。

    json
    {
      "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 是解决此问题的标准方案。

  1. 安装依赖

    bash
    npm install cross-env --save-dev
  2. 更新脚本

    在设置环境变量的命令前加上 cross-env 即可。

    json
    {
      "scripts": {
        "test": "cross-env NODE_ENV=test mocha tests/"
      }
    }

总结与建议

  • npm script 中,优先使用双引号,并对特殊字符进行转义。
  • 大多数前端构建工具(如 eslint, mocha, webpack)本身已经处理了跨平台兼容性问题。
  • 如果遇到其他兼容性问题,可以尝试在 npmjs.com 上搜索 cross-platformcross- 前缀的包,通常都能找到成熟的解决方案。
  • 对于Windows用户,可以了解并尝试使用 Windows Subsystem for Linux (WSL),它能在Windows上提供一个完整的Linux环境,从根本上解决兼容性问题。

本节用到的代码见 GitHub,想边看边动手练习的同学可以拉下来自己改,注意切换到正确的分支 06-add-cross-platform-support