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 🤔
- Delete lib files
- Call Rollup pack
- Api-extractor generates uniform declaration files and then removes redundant declaration files
- 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