资讯专栏INFORMATION COLUMN

使用 TypeScript 编写一个完善包含测试、文档和持续集成的库

lingdududu / 881人阅读

摘要:单元测试一个合格的库应该包含完整的单元测试。是的支持版,和是一样的,它能够直接运行为后缀的单元测试文件。在目录下加入然后执行即可看到单元测试结果。

这篇文章主要是讲述如何使用 TypeScript 编写一个完善,包含测试、文档、持续集成的库,涵盖了编写整个库所需要的技术和工具,主要涵盖:

项目目录骨架

TypeScript 配置

使用 jest 单元测试

使用 vuepress 编写文档

使用 github pages 部署文档

持续集成部署

原文首发于我的个人网站:听说 - https://tasaid.com/,推荐在我的网站阅读更多技术文章。

</>复制代码

  1. 前端开发 QQ 群:377786580
    欢迎使用和了解滴滴金融出品的移动端组件库 Mand-mobile。

为了迎合这篇文章,我编写了一个可以开箱即用的库模板:https://github.com/linkFly6/ts-lib-basic。

里面集成了这篇文章所阐述的所有内容。

初始化项目目录

先初始化项目目录,一般来说,src 放源码,dist 放编译后的代码,tests 放单元测试,所以先初始化好基础目录。

</>复制代码

  1. .
  2. ├── .vscode # vscode 配置
  3. │ └── launch.json # vscode 调试配置
  4. ├── dist # 编译产出目录,编译后才有
  5. ├── src # 源码
  6. ├── tests # 单元测试
  7. ├── .gitignore # git 忽略文件
  8. ├── .npmrc # npm 配置
  9. ├── .travis.yml # github 持续集成
  10. ├── LICENSE # 开源协议
  11. ├── README.md # README
  12. ├── package-lock.json # npm 锁定依赖
  13. ├── package.json # npm
  14. ├── tsconfig.json # typescript 配置
  15. └── tslint.json # tslint 校验

先按照这个目录文件结构,然后我们会一步步填上内容。

通过 npm init 初始化一个 npm 配置:

初始化 TypeScript 相关工具

既然包是基于 TypeScript 的,那么 TypeScript 工具必不可少。

ts-node

在开发中,可以使用 ts-node(可以理解为可以直接执行 ts 文件的 node)来直接运行我们的 ts 代码。

</>复制代码

  1. npm i --save-dev typescript
  2. npm i --save-dev ts-node

如果是 node 应用,为了让 TypeScript 能够进行 node 类型推导,则需要安装 Node 对应的类型声明:

</>复制代码

  1. npm i --save-dev @types/node
tsconfig.json

tsconfig.json 是 TypeScript 的配置文件,这里提供一份可供参考是配置,置于项目根目录:

</>复制代码

  1. {
  2. "compilerOptions": {
  3. "sourceMap": false,
  4. "module": "commonjs", // 模块配置
  5. "noImplicitAny": true, // 是否默认禁用 any
  6. // "removeComments": true, // 是否移除注释
  7. "types": [ // 默认引入的类型声明
  8. "node", // 默认引入 node 的类型声明
  9. ],
  10. "baseUrl": ".", // 工作根目录
  11. "paths": {
  12. // ~/ 指向 server/types,types 目录下都是 types 文件,所以不会编译产出
  13. "~/*": [
  14. "./types/*"
  15. ]
  16. },
  17. "target": "es6", // 编译目标
  18. "outDir": "dist", // 输出目录
  19. "declaration": true, // 是否自动创建类型声明
  20. },
  21. // 此配置生效范围
  22. "include": [
  23. "src/**/*"
  24. ],
  25. }
tslint.json

tslint 类似 eslint,是 TypeScript 中的代码风格约束工具。

关于 lint,个人方面比较倾向于非强制性的,所以只在 vscode 中安装了扩展 tslint,这样 vscode 会根据项目根目录配置的 tslint.json 标出不符合规范的信息。

这里有一份推荐配置:

</>复制代码

  1. {
  2. "defaultSeverity": "error",
  3. "extends": [
  4. "tslint:recommended"
  5. ],
  6. "jsRules": {},
  7. "rules": {
  8. "max-line-length": [
  9. true,
  10. 140
  11. ],
  12. // 禁止内置原始类型
  13. "ban-types": false,
  14. // 禁止给参数赋值
  15. "no-parameter-reassignment": false,
  16. // 禁止空接口
  17. "no-empty-interface": true,
  18. // 显示类型代码就不需要再加类型声明了
  19. "no-inferrable-types": true,
  20. // 不允许使用内部模块
  21. "no-internal-module": true,
  22. // 不允许在变量赋值之外使用常量数值。如果未指定允许值的列表, 则默认情况下允许-1、0和1 => 乱七八糟的数字会让人混淆
  23. // "no-magic-numbers": [true],
  24. // 不允许使用内部 "modules""namespace"
  25. "no-namespace": true,
  26. // 非空断言,强制使用 == null 之类的断言
  27. // "no-non-null-assertion": true
  28. // 禁止 /// ,直接用 import 即可
  29. "no-reference": true,
  30. // 禁止使用 require,应该使用 import foo = require("foo")
  31. "no-var-requires": false,
  32. // import 的顺序按照字母表
  33. "ordered-imports": false,
  34. // 对象属性声明按照字母表
  35. "object-literal-sort-keys": false,
  36. // // 结束语句后的分号
  37. "semicolon": [
  38. false,
  39. "always"
  40. ],
  41. // 字符串强制单引号
  42. "quotemark": [
  43. true,
  44. "single",
  45. "jsx-double"
  46. ],
  47. // 禁止 arguments.callee
  48. "no-arg": true,
  49. // if 语句的单行不用括号,多行用括号
  50. "curly": false,
  51. // 是否强制使用箭头函数,禁止匿名函数
  52. "only-arrow-functions": false,
  53. // 是否禁止多个空行
  54. "no-consecutive-blank-lines": false,
  55. // 在函数括号前要求或不允许空格
  56. "space-before-function-paren": false,
  57. // 箭头函数的参数使用括号
  58. "arrow-parens": [
  59. true,
  60. "ban-single-arg-parens"
  61. ],
  62. // 不固定变量类型
  63. "no-shadowed-variable": false,
  64. // 行尾多余的空格
  65. "no-trailing-whitespace": false,
  66. // == 和 ===
  67. "triple-equals": false,
  68. // 禁止一些位运算符
  69. "no-bitwise": false,
  70. // 禁止 console
  71. "no-console": false,
  72. // 检查变量名
  73. "variable-name": [
  74. true,
  75. "ban-keywords"
  76. // "check-format",
  77. // "allow-leading-underscore"
  78. ],
  79. // 一行声明变量表达式
  80. "one-variable-per-declaration": false,
  81. // 允许在一个文件里定义多个 class
  82. "max-classes-per-file": [
  83. true,
  84. 5
  85. ],
  86. // 判断表达式 fn && fn()
  87. "no-unused-expression": [
  88. true,
  89. "allow-fast-null-checks"
  90. ],
  91. // 空函数
  92. "no-empty": false,
  93. // forin 是否必须包含 hasOwnProperty 判断
  94. "forin": false,
  95. "no-debugger": false,
  96. // 强制要求必须要声明类型
  97. "typedef": [
  98. true
  99. ]
  100. },
  101. "rulesDirectory": [
  102. "./src"
  103. ]
  104. }
package-lock.json

package-lock.json 是 npm 5 之后引入的,为了解决 npm 过去使用的 package.json 版本依赖太宽松的问题。

比如说 package.json 中依赖了包 mand-mobile,使用了最常用的插入依赖(^):

</>复制代码

  1. "mand-mobile": "^4.16.4",

假设自己项目在上线阶段, mand-mobile 更新到了 mand-mobile@4.17.0,而刚好 mand-mobile@4.17.0 又不小心出现了一个新 bug 会导致页面脚本错误。这时候上线安装依赖的时候,由于 package.json^ 约束太宽松,就会导致 mand-mobile@4.17.0 被安装,从而导致上线出问题。

package-lock.json 就是为了解决这个问题,通过 npm 安装包的时候,会检测本地是否有 package-lock.json

如果没有 package-lock.json,就在安装包的时候将当前包依赖的详细信息(包括子级依赖)都写入生成 package-lock.json

如果有 package-lock.json,则根据 package.json,参考 pacakge-lock.json 来安装包依赖。来保证依赖稳定。

本质上 ppackage-lock.json 的作用类似于 node_modules 包依赖的快照。

单元测试

一个合格的库应该包含完整的单元测试。这里我们使用 jest 对应的 TypeScript 版本:ts-jest。

ts-jest

ts-jest 是 jest 的 TypeScript 支持版,API 和 jest 是一样的,它能够直接运行 .ts 为后缀的单元测试文件。

安装 ts-jest 和对应的类型声明文件:

</>复制代码

  1. npm i --save-dev jest #ts-jest 依赖 jest
  2. npm i --save-dev ts-jest
  3. npm i --save-dev @types/jest

package.json 中加入 jest 配置和 npm run test 的脚本:

</>复制代码

  1. {
  2. "name": "my-app",
  3. "main": "dist/index.js",
  4. "scripts": {
  5. "test": "jest --verbose"
  6. },
  7. "jest": {
  8. "rootDir": "tests",
  9. "transform": {
  10. "^.+.tsx?$": "ts-jest"
  11. },
  12. "testRegex": "(/__tests__/.*|(.|/)(test|spec)).tsx?$",
  13. "moduleFileExtensions": [
  14. "ts",
  15. "tsx",
  16. "js",
  17. "jsx",
  18. "json",
  19. "node"
  20. ]
  21. }
  22. }

这时候就可以基于 jest 编写单元测试了。在 tests/ 目录下加入 example.test.ts

</>复制代码

  1. import { isArrayLike } from "../src"
  2. describe("my-app:isArrayLike", () => {
  3. test("isArrayLike(): true", () => {
  4. expect(
  5. isArrayLike([]),
  6. ).toBe(true)
  7. })
  8. test("isArrayLike(): false", () => {
  9. expect(
  10. isArrayLike({}),
  11. ).toBe(false)
  12. })
  13. })

然后执行 npm run test 即可看到单元测试结果。

express 测试

如果要测试 express/koa 之类的 web 应用框架程序,则可以使用 tj 大神的 supertest。

安装对应的包:

</>复制代码

  1. npm i --save-dev supertest
  2. npm i --save-dev @types/supertest

</>复制代码

  1. import * as express from "express"
  2. /**
  3. * 用于测试 express、koa 等 web 应用框架的工具
  4. */
  5. import * as request from "supertest"
  6. import middleware from "../src"
  7. describe("my-app:basic", () => {
  8. test("locals", done => {
  9. const app = express()
  10. app.use(middleware)
  11. app.get("/example", (req, res) => {
  12. res.send({ code: 0 })
  13. })
  14. // 使用 supertest 进行测试
  15. request(app).get("/example").expect(200, { code: 0 }, done)
  16. })
  17. })
debug

debug 也是 tj 大神编写的一个库,用于在应用程序中输出 debug 信息,用于调试工具库,著名的库大部分都采用该库进行 debug 支持。

</>复制代码

  1. npm i --save debug
  2. npm i --save-dev @types/debug

</>复制代码

  1. import * as d from "debug"
  2. const debug = d(`my-app:basic`)
  3. debug("debug info")

在启动应用程序的时候,只需要在环境变量中注入 DEBUG 即可:

</>复制代码

  1. DEBUG=my-app* node app.js
  2. DEBUG=my-app* ts-node app.ts

vscode 基于 ts-node 调试

.vscode/launch.json 中可以配置基于 ts-node 的调试:

</>复制代码

  1. {
  2. // 使用 IntelliSense 了解相关属性。
  3. // 悬停以查看现有属性的描述。
  4. // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
  5. "version": "0.2.0",
  6. "configurations": [
  7. {
  8. "type": "node",
  9. "request": "launch",
  10. "name": "启动程序",
  11. // 基于 ts-node 调试
  12. "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js",
  13. "args": [
  14. "-P",
  15. "${workspaceRoot}/tests/tsconfig.json",
  16. "${workspaceRoot}/tests/app.ts", // 入口文件
  17. ]
  18. }
  19. ]
  20. }

文档

文档方面,简陋一点的,可以直接使用 README,也可以用 gitbook。不过我个人方便比较推荐 vuepress。

远程托管文档方面,要么自建服务器,要么直接托管到 Github 的 Pages。

使用 vuepress 编写文档

个人比较倾向于使用 vuepress 编写文档,是因为里面扩展 Markdown 扩展了许多丰富实用的语法,以及菜单结构的强大可配置。

这里我们讨论的是在项目中集成文档。

在项目根目录新建目录 /docs

npm i --save-dev vuepress

在项目的 package.json 中加入脚本

</>复制代码

  1. "scripts": {
  2. "docs": "vuepress dev docs",
  3. "docs:build": "vuepress build docs"
  4. }

/docs 新增文件 README.md,写入以下内容:

</>复制代码

  1. ---
  2. home: true
  3. actionText: 开始使用 →
  4. actionLink: /readme
  5. footer: MIT Licensed | Copyright © 2018-present linkFly
  6. features:
  7. - title: 快速
  8. details: 快速创建库
  9. - title: 集成
  10. details: 集成单元测试和自动化 doc 部署
  11. - title: TypeScript
  12. details: TypeScript 支持
  13. ---
  14. 集成了基础工具的,使用 TypeScript 快速编写一个应用库

然后执行结合我们刚才配置的命令,执行 npm run docs,终端 shell 会输出 vuepress 启动的服务地址:

访问地址,即可看到文档页面:

使用 github pages 托管文档

github pages 是 Github 提供的一个免费的页面托管服务,我们可以将 vuexpress 编译出来的文档托管到上面。

Github Pages 服务和 Github 已经打通,可以从项目的 /docs 目录自动部署,这也就是我们为什么要在项目里新建 /docs 目录的原因。

首先,我们将项目中 pageage.json 的脚本进行更新:

</>复制代码

  1. "scripts": {
  2. "docs:build": "vuepress build docs && cp -rf ./docs/.vuepress/dist/* ./docs && rm -r ./docs/.vuepress/dist"
  3. }

这段脚本的大体意思就是先使用 vuepress 构建产出文档的 HTML 文件(在 /docs/.vuepress/dist 目录下),然后将 dist 目录移动到 docs/ 目录下,因为 Github Pages 在识别 docs/ 的时候只能识别 docs/index.html

执行 npm run docs:build

将本地的项目 push 到 Github 以后,打开该项目的 Setting

在 Github Pages 配置项选择 docs/ 文件夹:

然后访问 https://.gitlab.io// 即可看到自动部署的文档。例如:https://linkfly6.github.io/ts-lib-basic/。

使用持续集成服务 travis-ci

travis-ci 是一个持续集成服务,它可以用来自动部署和构建 Github 上的项目。

我们可以集成我们的单元测试。

在项目根目录加入 .travis.yml,在 master 分支进行提交的时候自动运行 npm run test 命令(npm run test 命令配置参见 ts-jest 章节):

</>复制代码

  1. sudo: false
  2. language: node_js
  3. node_js:
  4. - "8"
  5. cache:
  6. directories:
  7. - node_modules
  8. branches:
  9. only:
  10. - master
  11. script:
  12. npm run test

打开 https://travis-ci.org/ 进行注册或登录。新增接入的项目:

选择要打开持续集成的项目:

然后我们更新文档或代码,提交代码到 Github。

稍等大概几十秒,就可以在 travis-ci 里面看到自己的单元测试任务:

最后,在测试完毕的情况下,在 https://www.npmjs.com/ 进行注册。

在 npm 的源是官方的(npm config set registry https://registry.npmjs.org/)情况下,执行 npm login 登录 npm 以后,npm publish 发布包即可。

最后,为了迎合这篇文章,我编写了一个可以开箱即用的库模板:https://github.com/linkFly6/ts-lib-basic。

里面集成了这篇文章所阐述的所有内容。

</>复制代码

  1. 前端开发 QQ 群:377786580
    欢迎使用和了解金融出品的移动端组件库 Mand-mobile。

原文首发于我的个人网站:听说 - https://tasaid.com/,推荐在我的网站阅读更多技术文章。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100649.html

相关文章

  • 【译】使用TypeScript两年后-值得吗?

    摘要:弄了一个持续更新的笔记,可以去看看,链接地址此篇文章的地址使用两年后值得吗基础笔记的地址可以也可以。使用,你可以使用抽象类等功能。有关抽象类的更多信息支持,和方法,只读属性。 弄了一个持续更新的github笔记,可以去看看,链接地址:Front-End-Basics 此篇文章的地址:使用TypeScript两年后-值得吗? 基础笔记的github地址:https://githu...

    RyanQ 评论0 收藏0
  • java开发程序员需要用到的库框架有哪些

    摘要:框架是和应用程序的另一个测试和规范框架。它是为应用程序编写自动测试的最有用的库之一。数据库是许多应用程序包括核心和应用程序不可分割的一部分,可能是进行单元测试时的最大障碍。 作为一名Java开发人员,我们从事不同的领域,从编写核心Java代码到创建JSP页面、编写RESTAPI,有时甚至创建Groovy脚本以实现构建自动化...

    zhaochunqi 评论0 收藏0
  • 自动化测试框架指南

    摘要:基于各种测试的理想测试自动化框架的主要组成部分是测试库单元测试单元测试库可用于塑造任何测试自动化框架的重要组成部分。构建工具旨在帮助您从源代码和支持库开发自动化软件,并运行测试。 ...

    tulayang 评论0 收藏0
  • 为什么我们从Angular 2迁移到Vue.js(为什么我们没有选择React)

    摘要:在,我们刚刚使用发布了我们的客户端的新版本。得到了最多的提及,排在第二位。根据,这个许可证旨在保护他们免受专利巨魔的侵害。正在获得更多开发者的支持,我们在开发过程中看到了这一点,让我们更加相信,我们的选择是对的。 showImg(https://segmentfault.com/img/bVbdxdq?w=1960&h=960);在Rever(www.reverscore.com),我...

    zhjx922 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<