# 七.跨平台兼容

前言

不是所有的 shell 命令都是跨平台兼容的,甚至各种常见的文件系统操作也是不兼容的

特别说明,windows 环境的同学建议使用 git bash 来运行 npm script,使用 windows 自带的 cmd 可能会遇到比较多的问题

# 1. 文件系统操作

npm script 中涉及到的文件系统操作包括文件和目录的创建、删除、移动、复制等操作,而社区为这些基本操作也提供了跨平台兼容的包,列举如下:

使用上面这几个小工具改造 npm script 的具体步骤如下:

第 1 步,添加开发依赖:

npm i rimraf cpr make-dir-cli -D
# npm install rimraf cpr make-dir-cli --save-dev
# yarn add rimraf cpr make-dir-cli -D
1
2
3

第 2 步,改造涉及文件系统操作的 npm script:

  "scripts": {
-    "cover:cleanup": "rm -rf coverage && rm -rf .nyc_output",
-    "cover:archive": "cross-var \"mkdir -p coverage_archive/$npm_package_version && cp -r coverage/* coverage_archive/$npm_package_version\"",
+    "cover:cleanup": "rimraf coverage && rimraf .nyc_output",
+    "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",
     "cover:open": "cross-var opn http://localhost:$npm_package_config_port",
-    "postcover": "npm-run-all cover:archive cover:cleanup --parallel cover:serve cover:open"
+    "precover": "npm run cover:cleanup",
+    "postcover": "npm-run-all cover:archive --parallel cover:serve cover:open"
  },
1
2
3
4
5
6
7
8
9
10
11

对改动的几点说明:

  • rm -rf 直接替换成 rimraf
  • mkdir -p 直接替换成 make-dir
  • cp -r 的替换需特别说明下,cpr 默认是不覆盖的,需要显示传入 -o 配置项,并且参数必须严格是 cpr <source> <destination> [options] 的格式,即配置项放在最后面;
  • cover:cleanuppostcover 挪到 precover 里面去执行,规避 cpr 没归档完毕覆盖率报告就被清空的问题;

TIP#13:任何改动之后记得重新运行 npm run cover,确保所有的 npm script 还是按预期工作的

# 2. 引用变量

2.2 在 npm script 中使用变量 (opens new window) 介绍了如何使用内置和预定义变量减少代码重复的技巧,如本节开头的例子,Linux 和 Windows 下引用变量的方式是不同的,Linux 下直接可以用 $npm_package_name,而 Windows 下必须使用 %npm_package_name%,我们可以使用 cross-var (opens new window) 实现跨平台的变量引用,具体步骤如下:

第 1 步,安装 cross-var 为开发依赖:

npm i cross-var -D
# npm install cross-var --save-dev
# yarn add cross-var -D
1
2
3

第 2 步,改写引用变量 npm script,具体 diff 如下:

  "scripts": {
     "cover:cleanup": "rm -rf coverage && rm -rf .nyc_output",
-    "cover:archive": "mkdir -p coverage_archive/$npm_package_version && cp -r coverage/* coverage_archive/$npm_package_version",
-    "cover:serve": "http-server coverage_archive/$npm_package_version -p $npm_package_config_port",
-    "cover:open": "opn http://localhost:$npm_package_config_port",
+    "cover:archive": "cross-var \"mkdir -p coverage_archive/$npm_package_version && cp -r coverage/* coverage_archive/$npm_package_version\"",
+    "cover:serve": "cross-var http-server coverage_archive/$npm_package_version -p $npm_package_config_port",
+    "cover:open": "cross-var opn http://localhost:$npm_package_config_port",
     "postcover": "npm-run-all cover:archive cover:cleanup --parallel cover:serve cover:open"
   },
1
2
3
4
5
6
7
8
9
10

因为 cover:serve 和 cover:open 命令都比较简单,直接在原始命令前增加 cross-var 命令即可,而 cover:archive 内含了两条子命令,我们需要用引号把整个命令包起来(注意这里是用的双引号,且必须转义),然后在前面加上 cross-var。

此外,细心的同学可能发现引入 cross-var 之后,它竟然给我们安装了 babel,如果想保持依赖更轻量的话,可以考虑使用 cross-var-no-babel (opens new window)

# 3. 设置环境变量

在 node.js 脚本和 npm script 使用环境变量也是比较常见的,比如我们在运行测试时,需要加上 NODE_ENV=test,或者在启动静态资源服务器时自定义端口号。因为不同平台的环境变量语法不同,我们可以使用 cross-env (opens new window) 来实现 npm script 的跨平台兼容,具体步骤如下:

第 1 步,添加 cross-env 到开发依赖:

npm i cross-env -D
# npm install cross-env --save-dev
# yarn add cross-env -D
1
2
3

第 2 步,改写使用了环境变量的 npm script:

  "scripts": {
-    "test": "NODE_ENV=test mocha tests/",
+    "test": "cross-env NODE_ENV=test mocha tests/",
  },
1
2
3
4

上面的改动更简单,直接在设置了环境变量的命令前面加上 cross-env 即可。

注意

  • 所有使用引号的地方,建议使用双引号,并且加上转义;
  • 没做特殊处理的命令比如 eslint、stylelint、mocha、opn 等工具本身都是跨平台兼容的;
  • 还是强烈建议有能力的同学能使用 Linux 做开发,只要你入门并且熟练了,效率提升会惊人;
  • 短时间内继续拥抱 Windows 的同学,可以考虑看看 Windows 10 里面引入的 Subsystem (opens new window),让你不用虚拟机即可在 Windows 下使用大多数 Linux 命令。