利用 NPM Scripts 提高开发效率

利用 NPM Scripts 提高开发效率

NPM 是 Node.js 的包管理工具. 利用 NPM Scripts 以及一些 NPM 包可以帮我们实现单元测试, Lint, Git Hook 以及包发布和自定义脚本等等.

以现在我手头上的一个 TypeScript 项目为例, 使用了以下脚本:

{
    "start": "node ./build/src/index.js",
    "dev": "nodemon --exec ./node_modules/.bin/ts-node -- ./src/index.ts",
    "build": "tsc",
    "test:run": "mocha --require espower-typescript/guess 'test/**/*.ts' --timeout=10000 --exit",
    "test:coverage": "cross-env NODE_ENV=test nyc npm run test:run",
    "test:watch": "cross-env NODE_ENV=test npm run test:run -- --watch",
    "test:ci": "cross-env NODE_ENV=ci nyc npm run test:run",
    "test": "cross-env NODE_ENV=test npm run test:run",
    "report-coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
    "lint": "tslint --project tsconfig.json '{src,test}/**/*.ts'",
    "prettier": "prettier --write '**/**/*.{ts,json,css,js}'",
    "precommit": "lint-staged",
    "commit": "git-cz",
    "commitmsg": "validate-commit-msg",
    "version": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md",
    "migration": "ts-node ./node_modules/.bin/typeorm migrations:generate -n Update"
}
  • start

    node ./build/src/index.js

    运行编译后的 JavaScript 代码, 在线上环境执行该脚本.

  • dev

    nodemon --exec ./node_modules/.bin/ts-node -- ./src/index.ts

    通过 nodemon 和 ts-node 运行项目并自动 reload. 在开发环境下执行该命令, 当 ts 代码改动时会自动重新编译并重启.

  • build

    tsc

    编译 typescript. 之所以加入到 npm scripts 来, 是因为 npm scripts 的命令会尝试从 node_modules/.bin 中寻找可执行文件, 而我们直接执行 tsc 的话他会默认从全局找, 找不到就抛出错误.

  • 测试

    这里有多个测试命令, 主要是针对不同的测试需求和场景

    • test:run

      mocha --require espower-typescript/guess 'test/**/*.ts' --timeout=10000 --exit

      该命令直接运行测试, 也是比较普遍常见的测试命令, 他是所有其他测试命令的基础命令. 我不会直接运行该命令, 而是其他基于这个基础上的其他测试命令.

    • test:coverage

      cross-env NODE_ENV=test nyc npm run test:run

      该命令把当前 NODE_ENV 设置为了 test, 在原本 test:run 命令基础上加上了测试覆盖率报告, nyc 可以用来统计测试覆盖率.

      coverage

    • test:watch

      cross-env NODE_ENV=test npm run test:run -- --watch

      该命令把当前 NODE_ENV 设置为了 test, 在原本 test:run 命令基础上传入了 --watch, 从而让 mocha 检测代码变化自动重启测试. 在测试驱动开发中特别有用.

    • test:ci

      cross-env NODE_ENV=ci nyc npm run test:run

      该命令把当前 NODE_ENV 设置为了 ci, 在原本 test:run 命令基础上加上了测试覆盖率报告, nyc 可以用来统计测试覆盖率. 它和 test:coverage 区别在于环境变量的差异, test:coverage 在本地需要查看测试覆盖率的时候执行, 而 test:ci 在 CI 环境执行.

    • test

      cross-env NODE_ENV=test npm run test:run

      该命令把当前 NODE_ENV 设置为了 test, 然后执行了 test:run. 在本地开发环境我们想跑一遍测试可以执行该命令, 测试完成后会自动退出.

    test:run 是基础测试脚本, 不会直接运行该命令. 一半我运行的是后面四条. 基本可以满足大多数的测试情况, 如果还需要本地运行测试自动 reload 并自动输出测试覆盖率报告的话, 可以自己再写个 test:watch:coverage 脚本或者再 npm run test:coverage -- --watch 就可以了.

    另外这里使用了 cross-env, 是考虑到这种环境变量设置方式不适用于 Windows. 在一些团队项目中, 无法保证没有人使用 Windows.

  • report-coverage

    nyc report --reporter=text-lcov > coverage.lcov && codecov

    该命令一般在 test:ci 之后执行, 用于将 nyc 生成的覆盖率报告转换为 codecov 格式同时发布到 codecov 上面.

  • lint

    tslint --project tsconfig.json '{src,test}/**/*.ts'

    从代码可以看出, 它执行的是 lint 检查. CI 中可以在 test:ci 前执行该命令.

  • prettier

    prettier --write '//*.{ts,json,css,js}'

    使用 prettier 格式化代码, 这条命令比较少用, 因为一般会设置 prettier 在文件修改之后 autofix. 放这里的使用场景是当变更 prettier 规则的时候方便的重新规范项目代码.

  • precommit

    lint-staged

    这个命令其实是一个钩子, 不直接去执行. 这里写的是 lint-staged . 在我们 commit 代码的时候, 我们的 precommit 脚本会先被执行. 利用这一点我们可以在 commit 前进行一些检查, 常用的是 lint 检查和 commit-msg 检查.

    package.json 中, 我有下面一段配置:

    "lint-staged": {
      "*.{ts,js,json,css}": ["prettier --write", "git add"]
    },
    

    lint-staged 这个包的作用是, 他可以检查我们 commit 时 add 的文件, 根据一些规则来对其执行相应的操作. 这里我们对所有 add 上来的 TS, JS, JSON, CSS 文件用 prettier 进行了规范, 同时 add 进来, 以加入到当次 commit 中来. 类似的我们可以使用其他的工具做一些其他方面的检查, 例如检查图片大小之类的.

    另外, 建议安装 husky 这个包, 它支持通过 npm scripts 的形式执行所有的 git hooks. 虽然 npm 已经自带了一些 hooks, 但 husky 提供了诸如 postmerge, prerebase 之类的钩子等等是 npm 自身所没有的.

  • commit / commit-msg

    commit: git-cz

    commit-msg: validate-commit-msg

    precommit 通过之后, 会执行 commit 中的命令也就是 git-cz. commitcommit-msg 两条命令其实是为了达到一个目的, 就是 commit-msg 的检查. 这一步需要安装 husky 来实现. 同时我们还需要在 package.json 配置

    "config": {
      "commitizen": {
        "path": "cz-conventional-changelog"
      }
    }
    

    具体可以参考 https://github.com/commitizen/cz-cli

    完成上述配置之后, 每次提交都会检查 commit message 是否符合 Angular Commit Message 的要求, 不符合则拒绝提交, 符合则通过.

  • version

    conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md

    让项目 Commit Message 遵循 Angular Commit Message 规范之后带来的另一个好处就是我们可以很方便的生成 changelog.

    该命令其实我们也不会去执行, 除非你需要手动发布版本. 该命令会生成 changelog 文件然后自动把生成的文件暂存.

    这里强烈推荐一个包叫 np. 它可以极大的方便发布流程. 做到依赖检查, 测试检查, 然后运行我们的 version 命令, 也就是生成 changelog, 然后自动打标签自动发布自动推送. 实在是发布版本利器.

    我这里的 version 就是给 np 包去用的.

    np

  • migration

    ts-node ./node_modules/.bin/typeorm migrations:generate -n Update

    这其实是一条普通的自定义脚本, 但之所以列出来说, 是因为我觉得 migration 在 Node.js 的出现很不容易. 在 JavaScript 的 ORM 如 Sequelize, Bookshelf 之类的, 似乎都没有对 migration 的支持. 大多数主流的后端语言的 ORM 都有 migration 的支持, 以前用 PHP 的 Laravel 框架的时候就用过其 migration, 个人觉得这是一个在大型项目中非常有存在必要的东西, 可以避免对表的误操作.

    上面这条命令还需要配置 ormconfig.json 文件, 这里不叙述. 执行该命令时, 他会检查当前代码中 models 和数据库表的差异, 自动生成 migration 文件. 不再需要自己手写 migration, 简直不要太方便.