Use TypeScript to write a library that perfects testing, documentation, and continuous integration

Keywords: Javascript npm JSON github TypeScript

This article mainly describes how to use TypeScript to write a perfect library, including testing, documentation, continuous integration, covering the technology and tools needed to write the entire library, mainly covering:

  1. Project catalog skeleton
  2. TypeScript configuration
  3. Using jest unit testing
  4. Writing documents using vuepress
  5. Deploy documents using github pages
  6. Continuous Integrated Deployment

The original text was first published on my personal website: I heard about it.- https://tasaid.com/ I recommend reading more technical articles on my website.

Front-end development QQ group: 377786580
Welcome to use and understand the mobile component library of financial products Mand-mobile.

To cater for this article, I wrote a library template that can be used out of the box: https://github.com/linkFly6/ts-lib-basic.

It integrates all the contents of this article.

Initialize project directory

Initialize the project directory first. Generally speaking, src puts the source code, dist puts the compiled code, and tests puts the unit test, so initialize the basic directory first.

.
├── .vscode           # vscode configuration
│   └── launch.json   # vscode debugging configuration
├── dist              # Compile the output directory before compiling
├── src               # Source code
├── tests             # unit testing
├── .gitignore        # git ignores files
├── .npmrc            # npm configuration
├── .travis.yml       # github continuous integration
├── LICENSE           # Mozilla Public License
├── README.md         # README
├── package-lock.json # npm lock dependency
├── package.json      # npm
├── tsconfig.json     # typescript configuration
└── tslint.json       # tslint check

First follow the directory file structure, then we will fill in the content step by step.

Initialize an npm configuration through npm init:

Initialize TypeScript-related tools

Since packages are based on TypeScript, the TypeScript tool is essential.

ts-node

In development, you can use ts-node To run our ts code directly.

npm i --save-dev typescript
npm i --save-dev ts-node

If it is a node application, in order to enable TypeScript to deduce the node type, you need to install the corresponding type declaration of Node:

npm i --save-dev @types/node

tsconfig.json

tsconfig.json It is the configuration file of TypeScript, which is provided here as a reference and placed in the project root directory:

{
  "compilerOptions": {
    "sourceMap": false,
    "module": "commonjs", // Module configuration
    "noImplicitAny": true, // Whether to disable any by default
    // "removeComments": true, // whether to remove comments
    "types": [ // Type declarations introduced by default
      "node", // Type declaration of node introduced by default
    ],
    "baseUrl": ".", // Working Root Directory
    "paths": {
      // ~/ Pointing to server/types, the types directory is full of types files, so the output is not compiled.
      "~/*": [
        "./types/*"
      ]
    },
    "target": "es6", // Compilation target
    "outDir": "dist", // Output directory
    "declaration": true, // Whether to automatically create type declarations
  },
  // Effective scope of this configuration
  "include": [
    "src/**/*"
  ],
}

tslint.json

tslint Similar to eslint, it is a code style constraint tool in TypeScript.

With regard to lint, the personal side is more inclined to be non-mandatory, so only the extended tslint is installed in vscode, so that vscode will mark out non-conforming information according to the tslint.json configured in the project root directory.

Here is a recommended configuration:

{
  "defaultSeverity": "error",
  "extends": [
    "tslint:recommended"
  ],
  "jsRules": {},
  "rules": {
    "max-line-length": [
      true,
      140
    ],
    // Prohibit built-in primitive types
    "ban-types": false,
    // No assignment of parameters
    "no-parameter-reassignment": false,
    // No empty interface
    "no-empty-interface": true,
    // Displaying type code eliminates the need for additional type declarations
    "no-inferrable-types": true,
    // Internal modules are not allowed
    "no-internal-module": true,
    // Constant values are not allowed outside of variable assignments. If a list of allowable values is not specified, allowing - 1, 0, and 1 => cluttered numbers by default can be confusing.
    // "no-magic-numbers": [true],
    // Internal'modules'and'namespace' are not allowed
    "no-namespace": true,
    // Non-empty assertions, forcing assertions such as== null
    // "no-non-null-assertion": true
    // Prohibit /// <reference path=> and use import directly.
    "no-reference": true,
    // Do not use require, import foo = require('foo')
    "no-var-requires": false,
    // import in alphabetical order
    "ordered-imports": false,
    // Object property declarations are alphabetized
    "object-literal-sort-keys": false,
    // // semicolon after closing statement
    "semicolon": [
      false,
      "always"
    ],
    // String forcing single quotation marks
    "quotemark": [
      true,
      "single",
      "jsx-double"
    ],
    // Prohibit arguments.callee
    "no-arg": true,
    // if statement single line without parentheses, multiple lines with parentheses
    "curly": false,
    // Whether to force the use of arrow functions to prohibit anonymous functions
    "only-arrow-functions": false,
    // Do you prohibit multiple blank lines?
    "no-consecutive-blank-lines": false,
    // Require or disallow spaces before function parentheses
    "space-before-function-paren": false,
    // Arrow function parameters are parenthesized
    "arrow-parens": [
      true,
      "ban-single-arg-parens"
    ],
    // Unfixed variable type
    "no-shadowed-variable": false,
    // Redundant spaces at the end of the line
    "no-trailing-whitespace": false,
    // = = = = = = = =
    "triple-equals": false,
    // Prohibit some bit operators
    "no-bitwise": false,
    // Prohibit console
    "no-console": false,
    // Check variable names
    "variable-name": [
      true,
      "ban-keywords"
      // "check-format",
      // "allow-leading-underscore"
    ],
    // One-line declarative variable expression
    "one-variable-per-declaration": false,
    // Allow multiple class es to be defined in one file
    "max-classes-per-file": [
      true,
      5
    ],
    // Judgment expression FN & FN ()
    "no-unused-expression": [
      true,
      "allow-fast-null-checks"
    ],
    // Empty function
    "no-empty": false,
    // Whether forin must contain hasOwn Property judgment
    "forin": false,
    "no-debugger": false,
    // Mandatory requirement must declare type
    "typedef": [
      true
    ]
  },
  "rulesDirectory": [
    "./src"
  ]
}

package-lock.json

package-lock.json was introduced after npm 5 to solve the problem that the package.json version used by npm in the past relies too loosely.

For example, package.json relies on package mand-mobile and uses the most commonly used insertion dependencies (^):

"mand-mobile": "^4.16.4",

Assuming that your project is online, mand-mobile updates to mand-mobile@4.17.0, and a new bug happens to cause page scripting errors when mand-mobile@4.17.0 accidentally appears. When installing dependencies online, the loose package.json and ^ constraints will lead to the installation of mand-mobile@4.17.0, which will lead to problems online.

To solve this problem, package-lock.json detects whether package-lock.json exists locally when installing packages through npm.

  • If there is no package-lock.json, the details of current package dependencies (including sub-dependencies) are written to generate package-lock.json at the time of package installation.
  • If you have package-lock.json, install package dependencies by reference to pacakge-lock.json, according to package.json. To ensure the stability of dependence.

In essence, ppackage-lock.json acts like a snapshot of node_modules package dependencies.

unit testing

A qualified library should contain complete unit tests. Here we use jest The corresponding version of TypeScript: ts-jest.

ts-jest

ts-jest yes jest TypeScript support version, API and jest are the same, it can run directly. ts as the suffix of the unit test file.

Install ts-jet and the corresponding type declaration file:

npm i --save-dev jest  #ts-jest depends on jest
npm i --save-dev ts-jest
npm i --save-dev @types/jest

Add the script of the jest configuration and npm run test to package.json:

{
  "name": "my-app",
  "main": "dist/index.js",
  "scripts": {
    "test": "jest --verbose"
  },
  "jest": {
    "rootDir": "tests",
    "transform": {
      "^.+\\.tsx?$": "ts-jest"
    },
    "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx",
      "json",
      "node"
    ]
  }
}

At this point, you can write unit tests based on jest. Add example.test.ts under tests / directory:

import { isArrayLike } from '../src'

describe('my-app:isArrayLike', () => {
  test('isArrayLike(): true', () => {
    expect(
      isArrayLike([]),
    ).toBe(true)
  })

  test('isArrayLike(): false', () => {
    expect(
      isArrayLike({}),
    ).toBe(false)
  })
})

The unit test results can then be seen by executing npm run test.

express test

If you want to test web application frameworks like express/koa, you can use the tj god's supertest.

Install the corresponding package:

npm i --save-dev supertest
npm i --save-dev @types/supertest
import * as express from 'express'
/**
 * Tools for testing express, koa and other web application frameworks
 */
import * as request from 'supertest'
import middleware from '../src'

describe('my-app:basic', () => {
  test('locals', done => {
    const app = express()
    app.use(middleware)
    app.get('/example', (req, res) => {
      res.send({ code: 0 })
    })
    // Testing with supertest
    request(app).get('/example').expect(200, { code: 0 }, done)
  })
})

debug

debug It is also a library written by tj god. It is used to output debug information in application programs and debug tool library. Most famous libraries use this library for debug support.

npm i --save debug
npm i --save-dev @types/debug
import * as d from 'debug'

const debug = d(`my-app:basic`)

debug('debug info')

When starting an application, you just need to inject DEBUG into the environment variable:

DEBUG=my-app* node app.js

DEBUG=my-app* ts-node app.ts

vscode debugging based on ts-node

In. vscode/launch.json, ts-node-based debugging can be configured:

{
  // Use IntelliSense to learn about related properties. 
  // Hover to see the description of existing properties.
  // For more information, visit https://go.microsoft.com/fwlink/?linkid=830387.
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Startup program",
      // Debugging based on ts-node
      "program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js",
      "args": [
        "-P",
        "${workspaceRoot}/tests/tsconfig.json",
        "${workspaceRoot}/tests/app.ts", // Entry file
      ]
    }
  ]
}

File

For documentation, you can use README or README directly. gitbook . But I personally recommend it for your convenience. vuepress.

For remotely hosting documents, you either build your own server or directly host them to Pages in Github.

Writing documents using vuepress

Individuals are more inclined to use vuepress Documentation is written because it extends Markdown to extend many rich and practical grammars, as well as the powerful configurability of the menu structure.

What we are discussing here is the integration of documents in the project.

  1. Create a new directory / docs in the project root directory
  2. npm i --save-dev vuepress
  3. Add scripts to package.json of the project
  "scripts": {
    "docs": "vuepress dev docs",
    "docs:build": "vuepress build docs"
  }

Add the file README.md to / docs and write the following:

---
home: true
 actionText: Start using
actionLink: /readme
footer: MIT Licensed | Copyright © 2018-present linkFly
features:
- title: Fast
  details: Quickly create libraries
 - title: Integration
  details: Integrated unit testing and automated doc deployment
- title: TypeScript
  details: TypeScript support
---

Integrating basic tools, using TypeScript to quickly write an application library

Then execute npm run docs in conjunction with the commands we just configured, and the terminal shell will output the service address started by vuepress:

Visit the address to see the document page:

Managing documents using github pages

github pages Github provides a free page hosting service that allows us to host documents compiled from vuexpress.

The Github Pages service and Github are connected and can be deployed automatically from the project's / docs directory, which is why we need to create a new / docs directory in the project.

First, we update the script of pageage.json in the project:

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

The general meaning of this script is to use vuepress to build the HTML file of the output document (in the / docs/.vuepress/dist directory), and then move the dist directory to the docs / directory, because Github Pages can only recognize docs/index.html when recognizing docs / documents.

Execute npm run docs:build.

After push ing the local project to Github, open Setting for the project:

Select docs/folder in the Github Pages configuration item:

Then visit https://<USERNAME or GROUP>.gitlab.io/<REPO>/to see the document for automatic deployment. For example: https://linkfly6.github.io/ts-lib-basic/.

Using Continuous Integration Service travis-ci

travis-ci It is a continuous integration service that can be used to automatically deploy and build projects on Github.

We can integrate our unit tests.

Add. travis.yml to the project root directory and automatically run the npm run test command when the master branch commits (see npm run test command configuration) ts-jest Chapter:

sudo: false
language: node_js
node_js:
  - "8"

cache:
  directories:
  - node_modules

branches:
  only:
  - master

script:
  npm run test

open https://travis-ci.org/ Register or login. New access projects:

Select the project to open continuous integration:

Then we update the document or code and submit the code to Github.

Wait a few tens of seconds or so to see your unit test tasks in travis-ci:

Finally, when the test is complete, the https://www.npmjs.com/ Register.

When the source of NPM is official (npm config set registry https://registry.npmjs.org/), after npm login is logged in to npm, npm publish can publish the package.

Finally, to cater to this article, I wrote a library template that can be used out of the box: https://github.com/linkFly6/ts-lib-basic.

It integrates all the contents of this article.

Front-end development QQ group: 377786580
Welcome to use and understand the mobile component library of financial products Mand-mobile.

The original text was first published on my personal website: I heard about it.- https://tasaid.com/ I recommend reading more technical articles on my website.

Posted by hessian on Sat, 11 May 2019 06:09:42 -0700