{T}

使用环境变量

npm script 中,我们可以利用环境变量来提高脚本的灵活性和可维护性。npm 在执行脚本时,会将 package.json 中的配置和依赖信息注入到环境变量中,供脚本直接使用。这些变量以 npm_package_npm_config_ 开头。

遵循 DRY (Don't Repeat Yourself) 原则,通过使用预定义和自定义变量,我们可以编写出更具适应性和可移植性的 npm script,轻松地将脚本复用至不同项目,而无需修改。

使用预定义变量

npm 提供了丰富的预定义变量。你可以通过 npm run env 命令查看当前项目所有可用的环境变量。其中,npm_package_* 系列变量包含了 package.json 中的所有字段信息。

例如,以下是一些常见的预定义变量:

shell
npm_package_name=your-project-name
npm_package_version=1.0.0
npm_package_author_name=author
npm_package_scripts_test=mocha
npm_package_devDependencies_mocha=^8.0.0

在脚本中,你可以通过 $ 符号(在 Windows 的 CMD 中是 %)来引用这些变量。例如,$npm_package_name 会被替换为项目的名称。

实战:按版本归档测试覆盖率报告

一个常见的需求是追踪测试覆盖率的变化趋势。我们可以将每次生成的覆盖率报告按照项目的版本号进行归档。

假设我们使用 nyc 来生成覆盖率报告,可以修改 package.json 中的 scripts 如下:

json
{
  "name": "hello-npm-script",
  "version": "0.1.0",
  "scripts": {
    "test": "mocha",
    "cover": "nyc --reporter=html npm test",
    "cover:cleanup": "rm -rf coverage .nyc_output",
    "cover:archive": "mkdir -p coverage_archive/$npm_package_version && cp -r coverage/* coverage_archive/$npm_package_version",
    "postcover": "npm run cover:archive && npm run cover:cleanup && opn coverage_archive/$npm_package_version/index.html"
  }
}

这里的脚本协同工作如下:

  • cover:archive:
    1. mkdir -p coverage_archive/$npm_package_version: 使用项目版本号创建一个用于归档的目录。
    2. cp -r coverage/* ...: 将 coverage 目录下的报告文件复制到新建的版本归档目录中。
  • postcover: 这是一个钩子脚本,在 npm run cover 执行成功后自动运行。
    1. npm run cover:archive: 执行归档操作。
    2. npm run cover:cleanup: 清理本次生成的临时文件。
    3. opn ...: 自动在浏览器中打开归档后的覆盖率报告。

执行 npm run cover 后,项目根目录下会生成 coverage_archive/0.1.0/ 这样的目录结构,其中包含了本次运行的覆盖率报告。

使用自定义变量

除了 npm 提供的预定义变量,我们还可以在 package.jsonconfig 字段中定义自己的变量。这些变量可以通过 npm_package_config_* 的形式在脚本中引用。

实战:为覆盖率报告启动一个 Web 服务

为了方便团队成员查看覆盖率报告,我们可以启动一个简单的 HTTP 服务来托管报告页面。我们可以将端口号定义为自定义变量,以方便修改。

首先,安装一个轻量的 HTTP 服务工具 http-server

shell
npm install http-server --save-dev

然后,在 package.json 中添加 config 字段并更新 scripts

json
{
  "name": "hello-npm-script",
  "version": "0.1.0",
  "config": {
    "port": "3000"
  },
  "scripts": {
    "test": "mocha",
    "cover": "nyc --reporter=html npm test",
    "cover:cleanup": "rm -rf coverage .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",
    "postcover": "npm-run-all cover:archive cover:cleanup --parallel cover:serve cover:open"
  }
}

相关改动说明:

  • config 对象中,我们定义了 port 变量。
  • cover:serve 脚本使用 http-server 启动服务。它通过 $npm_package_version 找到正确的报告路径,并使用 $npm_package_config_port 来设置服务端口。
  • postcover 脚本使用 npm-run-all 来编排多个任务,其中 cover:servecover:open 是并行执行的,因为 cover:serve 是一个常驻进程。

现在,再次运行 npm run cover,终端会启动 http-server 并保持运行状态,同时浏览器会自动打开 http://localhost:3000,显示覆盖率报告页面。

注意:自定义变量的声明不支持引用其他变量。例如,在 config 字段中 {"path": "$npm_package_version/foo"} 是无效的。

通过结合使用预定义和自定义变量,我们可以创建出高度灵活且易于维护的 npm script,从而显著提升开发工作流的自动化水平。


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