npm script 工作流

npm script

本文章系列来自于对掘金小册的npm-script一书的内容整理,欢迎大家支持正版

快速创建npm项目

执行npm init 初始化命令,生成package.json工程描述文件

1
2
3
4
5
6
7
8
9
10
npm init

package name: 包名称
version: 版本号
description: 描述信息
entry point: 入口文件
test command: 测试命令
git repository: 仓库地址
keywords: 关键字
license: 许可协议

也可以通过 -f -y 命令跳过问答快速生成package.json

1
2
3
4
// -force
npm init -f
// -yes
npm init -y

可以通过以下命令自定义初始化配置

1
2
3
4
5
npm config set init.author.email "wangshijun2010@gmail.com"
npm config set init.author.name "wangshijun"
npm config set init.author.url "http://github.com/wangshijun"
npm config set init.license "MIT"
npm config set init.version "0.1.0"

npm run 执行命令

使用npm run xxx 可以执行写在package.json文件中 “scirps” 里面的命令
eg:

1
2
3
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},

在执行 npm run xxx 之前,npm会将node_modules/.bin添加到环境变量 $PATH的前面,也就是所有可执行文件的npm依赖都可以直接在 npm script 中直接调用,无需在npm script 中加入完整路径 eg:”./node_modules/.bin/xxxx **.js”

多个npm script串行执行

可以在配置命令的时候,采用 && 符号链接不同的命令,执行时会严格按照先后顺序执行

eg:

1
2
3
"scripts": {
"test": "npm run lint:js && npm run lint:css && npm run lint:json && npm run lint:markdown && mocha tests/"
},

同时如果执行过程中遇到了错误后面命令也会停止执行

多个npm script并行执行

需要同时给出结果的一些场景,可能需要并行执行,即把 && 符号换成 & 即可

1
2
3
"scripts": {
"test": "npm run lint:js & npm run lint:css & npm run lint:json & npm run lint:markdown & mocha tests/"
},

对于子命令中长进程处理

由于不同情况下不同自命令的执行时间不同,同时发送多条异步请求,需要等待请求执行完成之后再处理。通过命令中增加 & wait 解决
eg:

1
npm run lint:js & npm run lint:css & npm run lint:json & npm run lint:markdown & mocha tests/ & wait

加上wait之后,过长的进程就可以通过 command + C 命令结束进程

可以通过下载npm install npm-run-all 更加简洁的配置多命令运行,参考官方文档

为 npm script传递参数

一些命令在执行的时候需要一些执行参数
eg: eslint 内置的自动修复模式,需要传入 –fix参数,在scripts中声明执行的时候也可能需要这些命令,有两种添加方式

  • 第一种: 建立新的带参数命令

    1
    2
    "lint:js": "eslint *.js",
    "lint:js:fix": "eslint *.js --fix",
  • 第二种: 引用之前的无参数命令,并为之传递参数

    1
    2
    "lint:js": "eslint *.js",
    "lint:js:fix": "npm run lint:js -- --fix",

–fix 参数前面的 – 意思是要给前面的npm run lint:js 实际指向的命令传递额外的参数。

给 npm script 添加注释

添加注释可以再命令执行时优化log记录,也可以帮助标识命令的含义,一共有两种做法,推荐后者

  • 方法1:
    1
    2
    "//": "运行所有代码检查和单元测试",
    "test": "npm-run-all --parallel lint:* mocha"

声明一个// 为key的命令,npm会自动忽略该键,但是声明多个的时候最后只会展示最后一个
Alt text

  • 方法2:
    1
    "test": "# 运行所有代码检查和单元测试 \n    npm-run-all --parallel lint:* mocha"

注意注释后面的换行符 \n 和多余的空格,换行符是用于将注释和命令分隔开,这样命令就相当于微型的 shell 脚本,多余的空格是为了控制缩进,也可以用制表符 \t 替代。这种做法能让 npm run 列出来的命令更美观
test

调整 npm script 日志输出

显示尽可能少的信息

调用 npm script 的时候添加 –loglevel silent 、–silent 或者 -s 参数

显示尽可能多的运行时状态

当我们在排查问题得时候需要较详细的log日志
使用 –loglevel verbose 、 –verbose 或者更简单的 -d 参数

npm script 钩子

npm run xxx的命令执行的时候分三个阶段

  • 检查 scripts对象中是不是存在 prexxx命令,如果有先执行该命令
  • 检查是否有 xxx 命令,有的话运行 test 命令,没有的话报错
  • 检查是否存在 postxxx 命令,如果有,执行 posttest 命令

利用这点我们可以再自动化测试之后增加测试覆盖率的判定,即写在postxxx命令当中,然后利用open工具打开
eg:

  • precover,收集覆盖率之前把之前的覆盖率报告目录清理掉;
  • cover,直接调用 nyc,让其生成 html 格式的覆盖率报告;
  • postcover,清理掉临时文件,并且在浏览器中预览覆盖率报告;

npm 中的环境变量

获得变量

我们可以拿到完整的环境变量

1
npm run env

也可以通过 npm run env | grep npm_package | sort 命令筛选拿到预定义的环境变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 作者信息...
npm_package_author_email=wangshijun2010@gmail.com
npm_package_author_name=wangshijun
npm_package_author_url=http://github.com/wangshijun
// 依赖信息...
npm_package_devDependencies_markdownlint_cli=^0.5.0
npm_package_devDependencies_mocha=^4.0.1
npm_package_devDependencies_npm_run_all=^4.1.2
// 各种 npm script
npm_package_scripts_lint=npm-run-all --parallel lint:*
npm_package_scripts_lint_css=stylelint *.less
npm_package_scripts_lint_js=eslint *.js
npm_package_scripts_lint_js_fix=npm run lint:js -- --fix
npm_package_scripts_lint_json=jsonlint --quiet *.json
// 基本信息
npm_package_version=0.1.0
npm_package_gitHead=3796e548cfe406ec33ab837ac00bcbd6ee8a38a0
npm_package_license=MIT
npm_package_main=index.js
npm_package_name=hello-npm-script
npm_package_readmeFilename=README.md
// 依赖的配置
npm_package_nyc_exclude_0=**/*.spec.js
npm_package_nyc_exclude_1=.*.js...

使用变量

变量的使用方法遵循 shell 里面的语法,直接在 npm script 给想要引用的变量前面加上 $ 符号即可
eg:

1
2
3
{
"dummy": "echo $npm_package_name"
}

使用场景

比如需要把收集分析的报告信息,按照版本号进行分档管理

1
2
3
4
5
6
7
8
"scripts": {
- "precover": "rm -rf coverage",
"cover": "nyc --reporter=html npm test",
- "postcover": "rm -rf .nyc_output && opn coverage/index.html"
+ "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",
+ "postcover": "npm run cover:archive && npm run cover:cleanup && opn coverage_archive/$npm_package_version/index.html"
}

此时:
cover:archive 做了 2 件事情:

  • mkdir -p coverage_archive/$npm_package_version 准备当前版本号的归档目录;
  • cp -r coverage/* coverage_archive/$npm_package_version,直接复制文件来归档;…

自定义变量

例如生成的报告需要与其他同事约定一个服务器端口号,并利用http-server启动一个轻量级服务来在线展示报告

1
2
3
4
5
6
7
8
9
10
11
12
"version": "0.1.0",
+ "config": {
+ "port": 3000
+ },
"scripts": {
@@ -15,7 +18,9 @@
"cover": "nyc --reporter=html npm test",
- "postcover": "npm run cover:archive && npm run cover:cleanup && opn coverage_archive/$npm_package_version/index.html"
+ "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"
},...

引用自定义变量的格式为:
$npm_package_config_port
即可拿到自定义的端口号 3000

npm 自动命令补全

暂时跳过

##