背景

最近一直在采用TDD(测试驱动开发)的方式来维护公司内部的一套通用业务逻辑。

既然是应用到公司实际项目中的,那就不能随随便便搭个脚手架来完成了。

调研过程中,发现TypeScript library starter和团队的技术堆栈契合的不错。

typescript-library-starter

因为笔者现有团队中的小伙伴项目中均采用typescript,react(ie7运行时切换为qreact),redux,jest等)进行开发。(不坑队友,选starter还是要符合团队的技术堆栈

这个Starter还是比较完善的,目前也一直处于迭代中。

为了保证我们的代码高质量和可维护,它使用了不少的工具。(当然我们可以根据团队需要,增删^_^

至于它工具链中包含的RollupJSJestPrettierTSLintTypeDocTravis CoverallsSemantic releaseCommitizenConventional changelogHusky等更多详细信息,大家可以去它们的github或者google去了解。

NPM Scripts

在这里,我们把重点放在NPM Scripts上面,看看这些个工具组成的开发工作流:

首先,我们按照README的步骤拉取并初始化项目:

  • git clone https://github.com/alexjoverm/typescript-library-starter.git step-by-step-tdd
  • cd step-by-step-tdd
  • npm install通过yarn安装也是可以的,淘宝源啥大家都知道哈

NPM包安装完成后,会出现一个问答(主要是确认下你项目的名字,错了可以直接在项目中改):

世界正在改变,我们来检测并更新下包(一般情况下,升级包不会影响原有项目。):

现在,我们来一行一行看脚本:

lint

npm run lint

"lint": "tslint -t codeFrame 'src/**/*.ts' 'test/**/*.ts'"

不用多说,这是用来保证代码风格的,配套项目中一般会有tslint.json文件。(毕竟代码更多是给人看的

-t codeFrame(就是指定tslint错误输出风格,这里是codeFrame),官网是这么解释的:

相信大家已经秒懂了。

build & prebuild

"prebuild": "rimraf dist"编译前删掉之前生成的dist文件夹。

npm run build编译ts为各种js模块规范

"build": "tsc --module commonjs --outDir dist/lib && rollup -c rollup.config.ts && typedoc --out dist/docs --target es6 --theme minimal --mode file src"

  • 根据tsconfig.json采用tsc生成commonjs规范的模块
  • 根据tsconfig.json采用rollup生成es规范和umd规范的模块
  • 使用typedoc生成文档

Javscript Modules

关于Javascript模块的好文(有很多,大家可以自行google)

npm start

npm start(rollup监控编译src目录下文件,开发阶段使用。不过我觉得开发的时候用npm run test:watch就够了)

"start": "rollup -c rollup.config.ts -w"

npm test

npm test(单元测试)

"test": "jest"

npm run test:watch(单元测试监控模式,基本上开发时用它就够了)

jest配置说明

针对这个starter所配的jest说明:

我们来解释下这些个选项:

  • "transform":node不认识ts,所以需要编译后执行
  • "testRegex":正则匹配要测试的文件
  • "moduleFileExtensions":设置文件扩展名,配置后,(import|require)相关文件不需要加啥(.ts,.tsx,.js)后缀
  • "coveragePathIgnorePatterns":忽略不需要收集代码覆盖率的文件夹中的文件
  • "coverageThreshold":这个选项用来设代码覆盖率(code coverage)收集的最小执行阈值
    • "global":标识符,全局设置(也可以针对路径,单个文件来设置
      • "branches":分支覆盖率(branch coverage):是否每个if代码块都执行了?
      • "functions":函数覆盖率(function coverage):是否每个函数都调用了?
      • "lines":行覆盖率(line coverage):是否每一行都执行了?
      • "statements":是否每个语句都执行了?
  • "collectCoverage":此项配置指示是否收集测试时的覆盖率信息。
  • "mapCoverage": 在这里ts编译器产生source map,Jest在输出覆盖率报告时, 将尝试使用它们来映射出源代码的代码覆盖率,并检查阈值。

npm test:prod(检查代码风格,运行单元测试并生成代码覆盖率报告。)

"test:prod": "npm run lint && npm run test -- --coverage --no-cache"

实战TDD

第一步,我们来确定我们要解决的问题(我这里的是根据babel对Preact中JSX语法的转换,来写一个简单h函数)

我们打开这个链接,会看到如下代码:

大家如果看过Preact h函数的源码,大家就会发现它实质上返回的是一个VNode实例,它包含4个属性:

有了输入和输出,我们就可以撸起袖子上手干啦(gif):

根据测试用例断点调试源码

我们打开vscode官网所提供的项目-->>debugging-jest-tests,把它里面launch.json给拖过来(一行都不用改它的),如下:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Jest All",
      "program": "${workspaceRoot}/node_modules/jest/bin/jest",
      "args": ["--runInBand"],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen"
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Jest Current File",
      "program": "${workspaceRoot}/node_modules/jest/bin/jest",
      "args": ["${file}"],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen"
    }
  ]
}

注意这里的选择:

按F5执行断点调试的gif:

推送到github并自动发布

  1. 进入npm官网,注册一个账号(很简单,就不演示了

  2. 进入Travis CI持续集成,我司用的是gitlab CI),点击右上角的:

    可以先同步下项目,点击:
    找到你的项目(我这里是这个

  3. 进入coveralls一个根据单元测试导出的数据进行分析,展现代码覆盖率的一个工具。这里,同样是使用github登录

    添加仓库:

  4. 现在我们在本地运行下npm run semantic-release-prepare

    如果你是widows系统,你当前可能需要运行npm install --global --production windows-build-tools

    编辑package.json中的repository.url

    "author": "Kirk.Wang <kirk.w.wang@gmail.com>",
    "repository": {
        "type": "git",
        "url": "https://github.com/Kirk-Wang/step-by-step-tdd" //这里替换成你自己的就好了
    }
    
  5. 根据提示,我们运行:

    npm install -g semantic-release-cli

    semantic-release-cli setup

  6. 因为我这里创建的是一个空白项目,并没有git init:

  7. 首先,我执行下git remote add origin git@github.com:Kirk-Wang/step-by-step-tdd.git

  8. 我根据自身需要编辑下.git/config这个件

  9. 然后检查下gh-pages-publish.ts(因为我们要自动发布我们的typedoc到githup pages上)

  10. 我们看下Starter提供的.travis.yml,大家就清楚了,如下:

    language: node_js
    branches:
      only:
        - master
        - /^greenkeeper/.*$/
    cache:
      yarn: true
      directories:
        - node_modules
    notifications:
      email: false
    node_js:
      - node
    script:
      - npm run test:prod && npm run build
    after_success:
      - npm run report-coverage
      - npm run deploy-docs
      - npm run semantic-release
    
  11. 我们接着执行:

    git add .

    npm run commit-->"commit": "git-cz"(因为我们要执行一个工具命令,用来规范我们的commit-message)

    Commitizen,一个撰写合格 Commit message 的工具

    关于它正确姿势,可以参考阮老师这篇文章:(阮老师的文章很好,但不能全信^_^

    Commit message 和 Change log 编写指南

  12. 大家根据需要改一下README.md

  13. 我们终于可以执行: git push

step-by-step-tdd typedoc因为我这里有在github上绑定域名,所以这个项目的gh-pages会自动在这下面。

关于gh-pages,很简单,看下文档就会了。

Prettier & Husky & lint-staged

  1. Prettier统一代码风格神器

  2. HuskyGit Hooks 管理神器

  3. lint-staged通常和Husky配合,提交前使用做Code Linting,Prettier或者其它操作,自由度更大

  4. 这里推荐两篇参考文章:

    我为什么推荐Prettier来统一代码风格

    用 husky 和 lint-staged 构建超溜的代码检查工作流

    相关文章很多,大家自行翻看和过滤。

总结

先上张图:

项目链接

step-by-step-tdd,如果有帮助到大家,那就点个Star^_^。

项目的typedoc

项目npm地址

微信交流群