NPM
NPM
- npm init默认配置
npm config set init.author.email "oorzc@qq.com"
npm config set init.author.name "oorzc"
npm config set init.author.url "http://github.com/oorzc"
npm config set init.license "MIT"
npm config set init.version "0.0.1"
#配置完成 执行下面 直接生成package.json文件
npm init -y
- script命令
"scripts": {
"lint:js": "eslint *.js",
"lint:css": "stylelint *.less",
"lint:json": "jsonlint --quiet *.json",
"lint:markdown": "markdownlint --config .markdownlint.json *.md",
"mocha": "mocha tests/",
"test串行&&": "npm run lint:js && npm run lint:css && npm run lint:json && npm run lint:markdown && mocha tests/",
"test并行&": "npm run lint:js & npm run lint:css & npm run lint:json & npm run lint:markdown & mocha tests/ $ wait",
"test": "npm-run-all --parallel lint:* mocha",
"test": "# 运行所有代码检查和单元测试 \n npm-run-all --parallel lint:* mocha",
}
- 多个 npm script 串行
&&
符号把多条 npm script 按先后顺序串起来即可,按照先后顺序执行(如果前序命令失败(通常进程退出码非0),后续全部命令都会终止)
"test串行&&": "npm run lint:js && npm run lint:css"
- 让多个 npm script 并行
有时候需要同时给出测试结果和测试运行结果。把连接多条命令的 &&
符号替换成 &
即可
注意:它只负责触发多条命令,而不管结果的收集,需要在末尾增加增加 & wait
加上 wait 的额外好处是,如果我们在任何子命令中启动了长时间运行的进程,比如启用了 mocha 的
--watch
配置,可以使用ctrl + c
来结束进程,如果没加的话,你就没办法直接结束启动到后台的进程。
"test并行&": "npm run lint:js & npm run lint:css $ wait",
- 管理多个命令
npm-run-all
实现更轻量和简洁的多命令运行
用如下命令将 npm-run-all
添加到项目依赖中:
npm i npm-run-all -D
#多个命令
"test": "npm-run-all lint:js lint:css lint:json lint:markdown mocha"
#npm-run-all 还支持通配符匹配分组的 npm script
#简化 (此处为串行任务)
"test": "npm-run-all --parallel lint:* mocha"
- npm script传递参数
"lint:js": "eslint *.js",
"lint:js:fix": "eslint *.js --fix",
"lint:js:fix": "npm run lint:js -- --fix",
## 注意指向的命令需要加 -- 分隔符
- 给 npm script 添加注释
"test": "# 运行所有代码检查和单元测试 \n npm-run-all --parallel lint:* mocha"
注意注释后面的换行符 \n
和多余的空格,换行符是用于将注释和命令分隔开,这样命令就相当于微型的 shell 脚本,多余的空格是为了控制缩进,也可以用制表符 \t
替代。这种做法能让 npm run 列出来的命令更美观,但是 scripts 声明阅读起来不那么整齐美观。
- 使用预定义变量
npm run env
就能拿到完整的变量列表
这里我使用 npm run env | grep npm_package | sort
拿到部分排序后的预定义环境变量:
// 作者信息...
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 给想要引用的变量前面加上 $
符号即可。比如:
{
"dummy": "echo $npm_package_name"
}
- 用 node.js 脚本替代复杂的 npm script
把庞大的 npm script 拆到单独文件中
当 npm script 不断累积、膨胀的时候,全部放在 package.json 里面可能并不是个好主意,因为这样会导致 package.json 糟乱,可读性降低。
借助 scripty 我们可以将 npm script 剥离到单独的文件中,从而把复杂性隔到单独的模块里面,让代码整体看起来更加清晰。
示例项目中的覆盖率相关的 npm script 占据了很大的篇幅,如下:
"scripts": {
"cover": "nyc --reporter=html npm test",
"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",
"precover": "npm run cover:cleanup",
"postcover": "npm-run-all cover:archive --parallel cover:serve cover:open"
},
如果要隔离复杂性,我们可以考虑从 cover 相关的 script 入手,具体操作步骤如下:
1. 安装依赖
npm i scripty -D
# npm install scripty --save-dev
# yarn add scripty -D
2. 准备目录和文件
mkdir -p scripts/cover
先创建两层的目录,因为我们计划把 cover 脚本写成多个,方便单独去执行,这里命名为 scripts 是 scripty 默认的,实际上是可以自定义的。
touch scripts/cover.sh
touch scripts/cover/serve.sh
touch scripts/cover/open.sh
然后创建空白的脚本文件,因为有了单独的脚本,我们可以把原来的 precover、cover、postcover、cover:archive、cover:cleanup 合并到一个文件中。
按照 scripty 的默认约定,npm script 命令和上面各文件的对应关系如下:
命令 | 文件 | 备注 |
---|---|---|
cover | scripts/cover.sh | 内含 precover、postcover 的逻辑 |
cover:serve | scripts/cover/serve.sh | 启动服务 |
cover:open | scripts/cover/open.sh | 打开预览 |
特别注意的是,给所有脚本增加可执行权限是必须的,否则 scripty 执行时会报错,我们可以给所有的脚本增加可执行权限:
chmod -R a+x scripts/**/*.sh
3. 修改 scripty 脚本
准备好目录和文件之后,接下来需要给脚本填充内容,脚本内容如下(因为脚本使用的是 bash,所以直接忽略了跨平台兼容的处理,跨平台兼容脚本最好使用 Node.js 编写,下节会介绍):
scripts/cover.sh
内容如下(cleanup --> cover --> archive --> preview):
#!/usr/bin/env bash
# remove old coverage reports
rimraf coverage && rimraf .nyc_output
# run test and collect new coverage
nyc --reporter=html npm run test
# achive coverage report by version
mkdir -p coverage_archive/$npm_package_version
cp -r coverage/* coverage_archive/$npm_package_version
# open coverage report for preview
npm-run-all --parallel cover:serve cover:open
scripts/cover/serve.sh
内容如下:
#!/usr/bin/env bash
http-server coverage_archive/$npm_package_version -p $npm_package_config_port
scripts/cover/open.sh
内容如下(这里有个 sleep,是为了确保文件系统写入完成):
#!/usr/bin/env bash
sleep 1
opn http://localhost:$npm_package_config_port
细心的同学可能注意到了,在 shell 脚本里面是可以随意使用 npm 的内置变量和自定义变量的。
4. 修改 package.json
主要改动是清理 cover:* 命令,接入 scripty,具体的 diff 如下:
"scripts": {
"test": "cross-env NODE_ENV=test mocha tests/",
- "cover": "nyc --reporter=html npm test",
- "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",
- "precover": "npm run cover:cleanup",
- "postcover": "npm-run-all cover:archive --parallel cover:serve cover:open"
+ "cover": "scripty",
+ "cover:serve": "scripty",
+ "cover:open": "scripty"
},
这里我们只保留了 cover、cover:serve、cover:open 等 3 个命令,让它们都指向 scripty,调用哪个脚本都由 scripty 来处理。
5. 实际测试
修改完毕之后,重新运行 npm run cover,不出意外的话,我们能得到和原来完全相同的结果,仔细观察运行的日志,会发现在代码执行前有段额外的输出,scripty 在实际执行的时候会把执行的命令内容打印出来,方便调试:
用 node.js 脚本替代复杂的 npm script
Node.js 丰富的生态能赋予我们更强的能力,对于前端工程师来说,使用 Node.js 来编写复杂的 npm script 具有明显的 2 个优势:首先,编写简单的工具脚本对前端工程师来说额外的学习成本很低甚至可以忽略不计,其次,因为 Node.js 本身是跨平台的,用它编写的脚本出现跨平台兼容问题的概率很小。
下面我们就一起探索下,如何把上节中使用 shell 编写的 cover 脚本改写成 Node.js 脚本,在 Node.js 脚本中我们也能体味到 shelljs 这个工具包的强大。
1. 安装 shelljs 依赖
使用如下命令安装 shelljs 到项目依赖中:
npm i shelljs -D
# npm install shelljs --save-dev
# yarn add shelljs -D
此外,我们计划使用 chalk 来给输出加点颜色,让脚本变的更有趣,同样安装到 devDependencies 里面:
npm i chalk -D
# npm install chalk --save-dev
# yarn add chalk -D
2. 创建 Node.js 脚本
touch scripts/cover.js
3. 用 Node.js 实现同等功能
shelljs 为我们提供了各种常见命令的跨平台支持,比如 cp、mkdir、rm、cd 等命令,此外,理论上你可以在 Node.js 脚本中使用任何 npmjs.com 上能找到的包。清理归档目录、运行测试、归档并预览覆盖率报告的完整 Node.js 代码如下:
const { rm, cp, mkdir, exec, echo } = require('shelljs');
const chalk = require('chalk');
console.log(chalk.green('1. remove old coverage reports...'));
rm('-rf', 'coverage');
rm('-rf', '.nyc_output');
console.log(chalk.green('2. run test and collect new coverage...'));
exec('nyc --reporter=html npm run test');
console.log(chalk.green('3. archive coverage report by version...'));
mkdir('-p', 'coverage_archive/$npm_package_version');
cp('-r', 'coverage/*', 'coverage_archive/$npm_package_version');
console.log(chalk.green('4. open coverage report for preview...'));
exec('npm-run-all --parallel cover:serve cover:open');
关于改动的几点说明:
- 简单的文件系统操作,建议直接使用 shelljs 提供的 cp、rm 等替换;
- 部分稍复杂的命令,比如 nyc 可以使用 exec 来执行,也可以使用 istanbul 包来完成;
- 在 exec 中也可以大胆的使用 npm script 运行时的环境变量,比如
$npm_package_version
;
4. 让 package.json 指向新脚本
准备好 Node.js 脚本之后,我们需要修改 package.json 里面的命令,使其运行该脚本:
"scripts": {
"test": "cross-env NODE_ENV=test mocha tests/",
- "cover": "scripty",
+ "cover": "node scripts/cover.js",
"cover:open": "scripty"
},
Npm 包发布
控制台注册
npm adduser登录
npm login
登录报错 请切换镜像
查看镜像
npm config get registry
设置原镜像
npm config set registry https://registry.npmjs.org
淘宝镜像
npm config set registry https://registry.npmmirror.com
yarn config set registry https://registry.npmmirror.com
发布
npm publish查看已发布版本列表
npm view test versions --json删除已发布版本
# 删除包的指定版本
npm unpublish test@1.0.0
# 强制删除包的指定版本
npm unpublish test@1.0.0 --force
# 删除包
npm unpublish test
# 强制删除包
npm unpublish test --force
npm版本升级
npm version major #例如:1.0.2 -> 2.0.0
npm version minor #例如:1.0.2 -> 1.1.2
npm version patch #例如:1.0.2 -> 1.0.3
npm version 0.0.4