Prospects for the feed

There are many common tools, methods and business functions within the company, and we can build a library of tools for each project to use.

Requirements to implement: 🤔

  • Support editor quick completion and prompt
  • Automated build
  • Supports automatic changlog generation
  • Code is submitted and published after it passes Lint and tests

Involved in the library

  • eslint + @typescript-eslint/parser
  • rollup
  • jest
  • @microsoft/api-extractor
  • gulp

Initialize the project

Create a new project directory such as fly-Helper and initialize the project with NPM init.

The installationTypeScript

yarn add -D typescript
Copy the code

Create the SRC directory, import files, and ts configuration files

fly-helper
 |
 |- src
 	 |- index.ts
 |- tsconfig.json
Copy the code

Configuration tsconfig. Json

/* tsconfig.json */ {"compilerOptions": {/* Base configuration */ "target": "esNext ", "lib": ["dom", "esnext"], "removeComments": False, "declaration": true, "sourceMap": true, /* Strong type check configuration */ "strict": true, "noImplicitAny": False, /* Module analysis configuration */ "baseUrl": ".", "outDir": "./lib", "esModuleInterop": true, "moduleResolution": "node", "resolveJsonModule": true }, "include": [ "src" ] }Copy the code

Refer to commit

1892d4

Ps: Commit also added.editorConfig to constrain the student’s code format

Configuration eslint

TypeScirpt has fully adopted ESLint as code to check The future of TypeScript on ESLint

It also provides a TypeScript file parser @typescript-eslint/parser and configuration options @typescript-eslint/eslint-plugin

The installation

yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin 
Copy the code

The directory structure

fly-helper
 |- .eslintignore
 |- .eslintrc.js
 |- tsconfig.eslint.json
Copy the code

Ps

Tsconfig. Eslint. Json we added a tsconfig files in the root directory, it will be used for eslintrc. ParserOptions. Project, due to the configuration requirements incude each ts, js file. We only needed to package the code in the SRC directory, so we added this configuration file.

If eslintrc. ParserOptions. The project is configured to tsconfig. Json. All ts and JS files other than SRC file will report an error.

Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: config.ts.
The file must be included in at least one of the projects provided.eslint
Copy the code

Although you can configure the eslintrc. ParserOptions. CreateDefaultProgram but can cause significant performance loss.

issus: Parsing error: “parserOptions.project”…

Configuration tsconfig. Eslint. Json

/* tsconfig.eslint.json */
{
  "compilerOptions": {
    "baseUrl": ".",
    "resolveJsonModule": true,
  },
  "include": [
    "**/*.ts",
    "**/*.js"
  ]
}
Copy the code

Configuration. The eslintrc. Js

// .eslintrc.js
const eslintrc = {
    parser: '@typescript-eslint/parser'.// Use the TS parser
    extends: [
        'eslint:recommended'.// ESLint recommends rules
        'plugin:@typescript-eslint/recommended'.// ts recommended rules].plugins: [
        '@typescript-eslint',].env: {
        browser: true.node: true.es6: true,},parserOptions: {
        project: './tsconfig.eslint.json'.ecmaVersion: 2019.sourceType: 'module'.ecmaFeatures: {
          experimentalObjectRestSpread: true}},rules: {}, / / custom
}

module.exports = eslintrc
Copy the code

Refer to commit

36f63d

Configure a rollup

Many popular libraries, such as Vue and React, use rollup. js

The installation

Install rollup and any plug-ins to use

yarn add -D rollup rollup-plugin-babel rollup-plugin-commonjs rollup-plugin-eslint rollup-plugin-node-resolve rollup-plugin-typescript2
Copy the code

Install the babel-related libraries

yarn add -D @babel/preset-env
Copy the code

The directory structure

fly-helper
 |
 |- typings
 	 |- index.d.ts
 |- .babelrc
 |- rollup.config.ts
Copy the code

Configuration. The babelrc

/* .babelrc */ { "presets": [["@babel/preset-env", {/* Babel will turn our module to CommonJS before Rollup has a chance to do anything, causing some of the Rollup processing to fail */ "modules": false}]]}Copy the code

Configure a rollup. Config. Ts

import path from 'path'
import { RollupOptions } from 'rollup'
import rollupTypescript from 'rollup-plugin-typescript2'
import babel from 'rollup-plugin-babel'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import { eslint } from 'rollup-plugin-eslint'
import { DEFAULT_EXTENSIONS } from '@babel/core'

import pkg from './package.json'

const paths = {
  input: path.join(__dirname, '/src/index.ts'),
  output: path.join(__dirname, '/lib'),}// rollup configuration item
const rollupConfig: RollupOptions = {
  input: paths.input,
  output: [
    // Output commonJS specification code
    {
      file: path.join(paths.output, 'index.js'),
      format: 'cjs',
      name: pkg.name,
    },
    // Print the es specification code
    {
      file: path.join(paths.output, 'index.esm.js'),
      format: 'es',
      name: pkg.name,
    },
  ],
  // external: ['lodash'], // indicate which modules should be treated as external modules, as in Peer Dependencies
  // Plugins need to pay attention to the order in which they are referenced
  plugins: [
    // Verify the imported file
    eslint({
      throwOnError: true.// lint will throw an exception if there is an error
      throwOnWarning: true,
      include: ['src/**/*.ts'],
      exclude: ['node_modules/**'.'lib/**'.'*.js'],}).// Enable rollup to support the CommonJS specification, recognizing its dependencies
    commonjs(),

    // Work with CommNjs to parse third-party modules
    resolve({
      // Pass custom options to the parsing plug-in
      customResolveOptions: {
        moduleDirectory: 'node_modules',
      },
    }),
    rollupTypescript(),
    babel({
      runtimeHelpers: true.// Only convert source code, no external dependencies run
      exclude: 'node_modules/**'.// Babel does not support TS by default
      extensions: [
        ...DEFAULT_EXTENSIONS,
        '.ts',],}),],}export default rollupConfig
Copy the code

Some considerations:

  • Plugins must be used sequentially
  • External sets the tripartite library as an external module, otherwise it will be packaged and become very large

Configuration statement file

declare module 'rollup-plugin-babel'
declare module 'rollup-plugin-eslint'
Copy the code

Since some plug-ins don’t have the @types library yet, we add the declaration file manually

Have a try

Let’s add a random method under index.ts

export default function myFirstFunc (str: string) {
  return `hello ${str}`
}
Copy the code

Because the RollupOptions interface is used, direct execution will result in an error. We comment out line 2 import {RollupOptions} from ‘rollup’ and line 17 after const rollupConfig: RollupOptions.

Then execute NPX rollup –c rollup.config.ts

Index.js and index.esm.js files are generated. Files corresponding to the CommonJS specification and es specification respectively. Rollup was a big push for the ES specification, and many of our third-party libraries still use the CommonJS specification, so we build both for compatibility.

Thanks to the use of ts, it is convenient to realize the requirement of fast completion. According to the example above, after using this package in the project, the input in vscode will have the following effect

Refer to commit

0aab81

Configuration jest

Of course the tool library will write tests, let’s get started

The installation

yarn add -D @types/jest eslint-plugin-jest jest ts-jest
Copy the code

The directory structure

fly-helper
 |- test
 	|- index.test.ts
 |- jest.config.js
Copy the code

Configuration jest. Config. Js

// jest.config.js
module.exports = {
  preset: 'ts-jest'.testEnvironment: 'node',}Copy the code

Let’s write a test

// index.test.ts

import assert from 'assert'
import myFirstFunc from '.. /src'

describe('validate:'.(a)= > {
  /** * myFirstFunc */
  describe('myFirstFunc'.(a)= > {
    test(' return hello rollup '.(a)= > {
      assert.strictEqual(myFirstFunc('rollup'), 'hello rollup')})})})Copy the code

Relocation eslint

const eslintrc = {
  // ...
  extends: [
    // ...
    'plugin:jest/recommended',].plugins: [
    // ...
    'jest',].// ...
}
Copy the code

Add package. Json scripts

"test": "jest --coverage --verbose -u"
Copy the code
  • Coverage Output test coverage
  • Verbose displays the results of each test in the test suite

Have a try

yarn test
Copy the code

Is it successful 😌

Refer to commit

9bbe5b

Configuration @ Microsoft/API – extractor

When we have multiple files under SRC, packaging generates multiple declaration files.

The @Microsoft/api-Extractor library is used in order to combine all the.d.ts into one and still automatically generate documentation based on written comments.

The installation

yarn add -D @microsoft/api-extractor
Copy the code

The configuration API – extractor. Json

/* api-extractor.json */
{
  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
  "mainEntryPointFilePath": "./lib/index.d.ts",
  "bundledPackages": [ ],
  "dtsRollup": {
    "enabled": true,
    "untrimmedFilePath": "./lib/index.d.ts"
  }
}
Copy the code

Add package. Json scripts

"api": "api-extractor run".Copy the code

Give it a try

You can try writing a few more methods, package them and find multiple.d.ts files, and then execute the YARN API

Add TS Doc style comments

* @param STR - input string * @returns 'hello XXX '* @example *' 'ts * myFirstFunc('ts') => 'hello ts' * ``` * * @beta * @author ziming */
Copy the code

There will be a hint when using this method

I’ve added two methods here, see Commit below

After executing, you will find that the declarations are merged on index.d.ts. And then to delete the redundant, the back to automatically delete it 😕

😤 also has a temp folder, let’s configure gitignore or it commits. Tsdoc-metadata. json can be temporarily abandoned, can be deleted.

Typing for package.json is configured later to automatically change the location

Refer to commit

4e4b3d

After the use of methods there is such a hint, is it very convenient to use 😉

Gulp automated build

The installation

yarn add -D gulp @types/gulp fs-extra @types/fs-extra @types/node ts-node chalk
Copy the code

Configuration package. Json

  "main": "lib/index.js",
  "module": "lib/index.esm.js",
  "typings": "lib/index.d.js",

  "scripts": {
      /* ... */
      "build": "gulp build",
  }
Copy the code

Configuration gulpfile

Let’s think about the build process 🤔

  1. Delete lib files
  2. Call Rollup pack
  3. Api-extractor generates uniform declaration files and then removes redundant declaration files
  4. complete

Let’s take it one step at a time

// Delete the lib file
const clearLibFile: TaskFunc = async (cb) => {
  fse.removeSync(paths.lib)
  log.progress('Deleted lib file')
  cb()
}
Copy the code
/ / a rollup packaging
const buildByRollup: TaskFunc = async (cb) => {
  const inputOptions = {
    input: rollupConfig.input,
    external: rollupConfig.external,
    plugins: rollupConfig.plugins,
  }
  const outOptions = rollupConfig.output
  const bundle = await rollup(inputOptions)

  // Write requires traversing the output configuration
  if (Array.isArray(outOptions)) {
    outOptions.forEach(async (outOption) => {
      await bundle.write(outOption)
    })
    cb()
    log.progress('Rollup built successfully')}}Copy the code
// api-extractor collates.d.ts files
const apiExtractorGenerate: TaskFunc = async (cb) => {
  const apiExtractorJsonPath: string = path.join(__dirname, './api-extractor.json')
  // Load and parse api-extractor.json file
  const extractorConfig: ExtractorConfig = await ExtractorConfig.loadFileAndPrepare(apiExtractorJsonPath)
  // Check whether there is an index.d.ts file. This file must be accessed asynchronously first, or it will not be found later
  const isExist: boolean = await fse.pathExists(extractorConfig.mainEntryPointFilePath)

  if(! isExist) { log.error('API Extractor not find index.d.ts')
    return
  }

  / / call API
  const extractorResult: ExtractorResult = await Extractor.invoke(extractorConfig, {
    localBuild: true.// Display information in the output
    showVerboseMessages: true,})if (extractorResult.succeeded) {
    // Delete unwanted.d.ts files
    const libFiles: string[] = await fse.readdir(paths.lib)
    libFiles.forEach(async file => {
      if (file.endsWith('.d.ts') && !file.includes('index')) {
        await fse.remove(path.join(paths.lib, file))
      }
    })
    log.progress('API Extractor completed successfully')
    cb()
  } else {
    log.error(`API Extractor completed with ${extractorResult.errorCount} errors`
      + ` and ${extractorResult.warningCount} warnings`)}}Copy the code
/ / finish
const complete: TaskFunc = (cb) = > {
  log.progress('---- end ----')
  cb()
}
Copy the code

Then use a build method to put them together in order

export const build = series(clearLibFile, buildByRollup, apiExtractorGenerate, complete)
Copy the code

Give it a try

yarn build
Copy the code

Slip into the lib file and take a look at 🧐.

Refer to commit

a5370c

Changelog is automatically generated

The installation

yarn add -D conventional-changelog-cli
Copy the code

Configuration gulpfile

// gulpfile
import conventionalChangelog from 'conventional-changelog'

// Create a custom Changelog
export const changelog: TaskFunc = async (cb) => {
  const changelogPath: string = path.join(paths.root, 'CHANGELOG.md')
  // Pair the conventional-changelog -p angular-i changelog. md -w -r 0 command
  const changelogPipe = await conventionalChangelog({
    preset: 'angular',
    releaseCount: 0,
  })
  changelogPipe.setEncoding('utf8')

  const resultArray = ['# tool library update log \n\n']
  changelogPipe.on('data'.(chunk) = > {
    // The original commits path is to the submitted list
    chunk = chunk.replace(/\/commits\//g.'/commit/')
    resultArray.push(chunk)
  })
  changelogPipe.on('end'.async() = > {await fse.createWriteStream(changelogPath).write(resultArray.join(' '))
    cb()
  })
}

Copy the code

Pleasantly surprised to find that Xconvention-Changelog has found @types library, and continue to add manually

// typings/index.d.ts

declare module 'conventional-changelog'
Copy the code

Refer to commit

1f31ab

Ps

Pay attention to the use of Conventional – Changelog

  • Pay close attention to the Commit format, which uses the Angular Commit specification and automatically generates a commit starting with feat and fix
  • Each change requires an update of version before it is generated. I’ll give you an example

Optimize the development process

The installation

yarn add -D husky lint-staged
Copy the code

package.json

Without further ado, look at the code

  "husky": {
    "hooks": {
      "pre-commit": "lint-staged & jest -u"
    }
  },
  "lint-staged": {
    "*.{.ts,.js}": [
      "eslint",
      "git add"
    ]
  }
Copy the code

After that, the submitted code will be verified by Lint before passing the JEST test. Code specifications for team collaboration

Optimize the release process

package.json

/* Pushlish files */ "files": ["lib", "LICENSE", "changelo.md "," readme.md "], /* Make support tree shaking */ "sideEffects": "false", "script": { /* ... */ "changelog": "gulp changelog", "prepublishOnly": "yarn lint & yarn test & yarn changelog & yarn build" }Copy the code

PrepublishOnly can be published, verified by Lint, tested by Jest, regenerated into a Changlog, packaged, and published.

At this point, we have fulfilled all of our requirements. 🥳

Refer to commit

7f343f

Changelog example

  • So let’s pretend we’re writing the first method now. I removed the above example and added a calculate.ts

    See the repository address release/1.0.0 branch

  • Then we commit this change and commit to feat: Add calculateOneAddOne to compute the 1 + 1 method

  • Run the NPM version major command to upgrade major version 1.0.0.

    More operations for upgrade version

    The version specification refers to semantic version 2.0.0

  • Yarn Changelog look at your changelog.md automatically generated 🥳

The warehouse address

Fly – helper/release / 1.0.0

reference

TypeScript tutorial

TypeSearch

The future of TypeScript on ESLint

A Rollup. Js Chinese website

rollup – pkg.module

If you’re writing a package, strongly consider using pkg.module

Jest Chinese document

api-extractor

tsdoc

gulp

Guide to writing Commit Message and Change log