React + typescript: Eslint, stylelint, code formatting tool prettier, eslint, stylelint, prettier Husky + Lint-staged code that only Lint-modified each commit and CommitLint to normalize commit messages
Project address: React-typescript-boilerplate
eslint
Find and fix problems in your JavaScript code
There are many lint tools available in the community, such as ESLint, stylelint, TSLint, HTMLLint, MarkDownLint, etc. Lint on the one hand can help maintain team members to maintain a good code style, on the other hand can help us detect bad code smell, reduce the possibility of bugs, improve code quality. It should be noted that the Lint tool has some formatting capabilities, but the main function is not to format code, which should be handed over to a specialized formatting tool. In this project, we are going to format code using Prettier.
Since you plan to write React in TypeScript, choose a Typescript-enabled Lint tool. The most popular typescript-enabled Lint tools are tsLint and ESLint. Last February 2019, the TSLint team announced that tsLint would be scrapped, instead maintaining a set of tools that integrate TypeScript into ESLint. For details see this issue and this blog: TSLint in 2019.
I don’t see any reason to opt for TSLint for new projects in 2020. Eslint’s TypeScript plugins are pretty mature, although they still have a lot of bugs.
Most front-end build tools use Node to write modules to provide apis. Some also provide command-line tools that essentially parse user input and call the Node API. Options can then be configured through configuration files, plug-ins can be integrated, and configurations can be shared through NPM packages.
Eslint is no exception. Configuring ESLint recommends using the interactive configuration generator provided by the ESLint command line tool. Many packages can be installed globally or locally. We chose to install locally because there is no way to ensure that someone else will install the project globally, and that they will all be using the same version.
Install eslint:
The # -d parameter indicates a development dependency
yarn add eslint -D
Copy the code
To call esLint’s built-in configuration generator:
npx eslint --init
Copy the code
NPX is a command that comes with NPM 5.2. X is the same as the x in the file type descriptor for execute. Eslint will be used locally if it is installed locally, go to global if it is not installed locally, download esLint in a temporary directory if it is not installed globally, and delete it when it is finished. NPM scripts is easier to use than NPM scripts, you don’t have to add — before the parameter like NPM scripts. Setting up ESLint in Your JavaScript Project with VS Code Setting up ESLint in your JavaScript Project with VS Code
-
How would you like to use ESLint?
We choose the third item: To check syntax, find Problems, and Enforce code style. If we choose the other items, we will not be asked whether we choose Google, Airbnb or Standard style
-
What type of modules does your project use?
We chose JavaScript modules (import/export), including node scripts such as webpack configuration which we will write using TS, so we chose ESM
-
Which framework does your project use?
Obviously react
-
Does your project use TypeScript?
This step must be Y. Only by telling the initializer that we use TypeScript will it help us configure TypeScript ESLint Parser, plugins, and other configurations
-
Where does your code run?
Here we choose both Browser and node because we need to write some node code
-
How would you like to define a style for your project?
Use a popular style guide
-
Which style guide do you want to follow?
Choose Airbnb’s code style
-
What format do you want your config file to be in?
We chose the most flexible configuration method: javascript. Although the js configuration file is more flexible than the json configuration file, the js configuration file cannot use the json validate function provided by VSCode.
-
Would you like to install them now with npm?
Select Y to install dependencies immediately. Although we are using YARN, NPM should not be used to install dependencies, and installing dependencies with NPM would also generate package-lock.json that is not available to us. Package.lock. json and yarn.lock are used to lock dependent versions. The reason why I choose to install dependencies immediately is that if you do not install dependencies immediately, you will have to check which dependencies to install when you want to use YARN to install dependencies again. I think it is very troublesome.
After installation, delete node_modules, package-lock.json, and yarn.lock, reinstall dependencies using YARN, and upgrade to the latest version:
# install dependencies
yarn
# Upgrade to the latest version
yarn upgrade --latest
Copy the code
From the configuration generator that comes with ESLint we generate.eslintrc.js:
// Formatted.eslintrc.js
module.exports = {
env: {
browser: true.es6: true.node: true,},extends: ['plugin:react/recommended'.'airbnb'].globals: {
Atomics: 'readonly'.SharedArrayBuffer: 'readonly',},parser: '@typescript-eslint/parser'.parserOptions: {
ecmaFeatures: {
jsx: true,},ecmaVersion: 2018.sourceType: 'module',},plugins: ['react'.'@typescript-eslint'].rules: {}};Copy the code
As you can see, the default parser is replaced with @typescript-eslint/parser for non-typescript projects, and the @typescript-esLint plugin is added.
Let’s make the following modifications first:
-
Check the instructions for eslint-config-airbnb, which states that to enable the React hooks check, you need to add “extends”: “airbnb/hooks” to.eslintrc.js
-
Modify parserOptions ecmaVersion for 2020, wet 😂 vying for the new era
-
Check out the @typescript-esLint/eslint-Plugin documentation, which states that we can enable some of its recommended rules by adding extends: ‘plugin:@typescript-eslint/recommended’.
-
In order for eslint-plugin-import to properly resolve ts, TSX, JSON suffixes, we also need to specify the allowed suffixes, add the setttings field, and add the following configuration:
// .eslintrc.js { settings: { 'import/resolver': { node: { // Specify the suffix for eslint-plugin-import resolution extensions: ['.ts'.'.tsx'.'.js'.'.json'],},},},}Copy the code
-
In order for eslint-plugin-import to properly parse paths mappings in tsconfig.json, we need to install eslint-import-resolver-typescript:
yarn add eslint-import-resolver-typescript -D Copy the code
Modify the Settings field:
// .eslintrc.js { settings: { 'import/resolver': { typescript: { // configure eslint-import-resolver-typescript to read tsconfig.json // We don't need it yet // directory: [resolve('./src/tsconfig.json'), resolve('./scripts/tsconfig.json')],}},}},Copy the code
Add some of the best ESLint plugins in the community:
yarn add eslint-plugin-eslint-comments eslint-plugin-promise eslint-plugin-unicorn -D
Copy the code
Eslint-plugin-eslint-comments are used for comments on lint eslint directives, such as eslint-disable comments that detect useless ones. Eslint-plugin-unicorn is a plugin for eslint-resorhus that provides cyclic dependency detection, File name case style constraints and other very useful rules set.
There are still a number of bugs in TypeScript pairing with eslint-plugin-import. One of the bugs is that the import/extensions rule doesn’t handle file extensions correctly:
To find related issues, go to eslint-plugin-import github issue and search for import/extensions typescript. My current solution is to change the import/ Extension rule configuration:
'import/extensions': [
'2,
'ignorePackages',
{
ts: 'never',
tsx: 'never',
json: 'never',
js: 'never'
},
],
Copy the code
Another bug to mention is this issue: no-useless-constructor: Cannot read property ‘body’ of null;} Cannot read property ‘body’ of null;} Cannot read property ‘body’ of null;} Cannot read property ‘body’ of null. Such as:
declare module 'size-plugin' {
import { Plugin } from 'webpack'; interface SizePluginOptions { writeFile? : boolean; }class SizePlugin extends Plugin {
No-useless-constructor: Cannot read property 'body' of null
constructor(options? : SizePluginOptions); } export = SizePlugin; }Copy the code
My current solution is to add the following two rules:
rules: {
'no-useless-constructor': 'off'.'@typescript-eslint/no-useless-constructor': 'error',},Copy the code
We also need to disable some rules for.d.ts files. We will later implement webPack-related Node scripts in the script folder and adjust some rules for this folder as well:
// .eslintrc.js
{
overrides: [{files: ['**/*.d.ts'].rules: {
'import/no-duplicates': OFF,
},
},
{
files: ['scripts/**/*.ts'].rules: {
'import/no-extraneous-dependencies': OFF,
},
},
],
}
Copy the code
I won’t mention any other custom rule tweaks, but you can go straight to the final configuration:.eslintrc.js.
There are still some problems with this configuration, for example, many rules conflict with Prettier, which we will address later.
stylelint
A mighty, modern linter that helps you avoid errors and enforce conventions in your styles
For stylelint, I usually refer directly to Ant Design’s StyLint configuration. Add.stylelintrc.json to the project root path and copy it to make a simple change:
// .stylelintrc.json
{
"extends": [
"stylelint-config-standard"."stylelint-config-rational-order"."stylelint-config-prettier"]."plugins": [
"stylelint-order"."stylelint-declaration-block-no-ignored-properties"."stylelint-scss"]."rules": {
"comment-empty-line-before": null."declaration-empty-line-before": null."function-name-case": "lower"."no-descending-specificity": null."no-invalid-double-slash-comments": null
},
/ / add "* * / typings / * * / *" : https://github.com/stylelint/vscode-stylelint/issues/72
"ignoreFiles": ["node_modules/**/*"."src/assets/**/*"."dist/**/*"."**/typings/**/*"]}Copy the code
The SRC /assets folder is intended to hold some resource files, such as third-party CSS libraries. Lint is not required. There is a bug in the stylelint plugin from VSCode. The stylelint file will display an error by default, so I added “**/typings/**/*” to ignore the.d.ts file:
According to the configuration file above, we need to install the corresponding NPM package:
yarn add stylelint stylelint-config-standard stylelint-config-rational-order stylelint-config-prettier stylelint-order stylelint-declaration-block-no-ignored-properties stylelint-scss -D
Copy the code
Like esLint, there is a conflict with Prettier.
prettier
An opinionated code formatter
Opinionated means that the formatter does not give the user a choice but formats according to a set of community consensus, best practices, and best looking code styles. There were very few options, and I counted just 20 in total.
First we have to install Prettier:
yarn add prettier -D
Copy the code
Add.prettierrc to the project root path:
{
"trailingComma": "all"."tabWidth": 4."semi": true."singleQuote": true."endOfLine": "auto"."printWidth": 100."overrides": [{"files": "*.md"."options": {
"tabWidth": 2}}}]Copy the code
A brief explanation of why some options are configured this way:
-
‘trailingComma’ : ‘all’, which supports comma insertion in function arguments as well
-
Semi: true, personal habit
-
“SingleQuote “: true, personal habit, wouldn’t it be nice to hit shift less?
-
“EndOfLine “: “auto”, just like EditorConfig, use the operating system default line break
-
“PrintWidth “: 100, I think the default maximum line width of 80 is too short and wastes editor space
-
Formatting a Markdown file “tabWidth”: 2 because prettier inserts extra Spaces in an unordered list when formatting a Markdown file
A normal unordered list would be formatted as:
- 1 - 2 - 3 Copy the code
But without tabWidth, Prettier formats:
- 1, 2, 3Copy the code
The giant ugly 😤
Linters and Prettier
It is strongly recommended to read the official documentation of Prettier with Linters, which tends to be the most up-to-date and authoritative.
We know that Lint is used to check code style, prettier is used to format code. Think about it: if Prettier set indentation to 4 Spaces while ESLint was configured to indent 2 Spaces, esLint would definitely report indentation errors when we formatted code.
The purpose of this article is to solve problems with linters rules that conflict with Prettier, in a simple way, by disabling rules that would contradict Prettier’s formatting.
Install the esLint plugin eslint-config-prettier, which disables all rules where Prettier conflicts with prettier.
yarn add eslint-config-prettier -D
Copy the code
Add ‘prettier’, ‘prettier/react’, ‘prettier/@typescript-eslint’ to extends configuration:
// .eslintrc.js
{
extends: [
'airbnb'.'airbnb/hooks'.'plugin:eslint-comments/recommended'.'plugin:import/typescript'.'plugin:react/recommended'.'plugin:@typescript-eslint/recommended'.'plugin:unicorn/recommended'.'prettier'.// Eslint-plugin-react is specifically supported
'prettier/react'.// Specifically supports @typescript-eslint/eslint-plugin
'prettier/@typescript-eslint',]}Copy the code
Prettier is placed last because it gives Prettier a chance to disable all the conflicting rules that she already has in extends.
For stylelint, install the stylelint-config-prettier plug-in:
yarn add stylelint-config-prettier -D
Copy the code
Add “stylelint-config-prettier” to the end of the extends array:
// .stylelintrc.json
{
"extends": [
"stylelint-config-standard"."stylelint-config-rational-order"."stylelint-config-prettier"],}Copy the code
lint-staged
Run linters on git staged files
Each time we submit code, we lint and format the code first to make sure that the team’s code style is consistent. In order to achieve this, only the code we change will be processed each time Lint and formatting is performed, that is, the code stored in the Git stage area. There are two popular schemes in the community:
- pretty-quick
- lint-staged
Lint-staged codes we chose to use Lint-Staged because pretty- Quick is simple and only provides prettier formatting stage code, which cannot be configured with ESLint or stylelint and cannot be configured from configuration files. Lint-satged is a more flexible way to configure esLint, stylelint, prettier at the same time.
To automate lint and formatting every time we commit, we need to attach a hook to git commit. Husky makes it easy to configure git hooks.
First install Husky and Lint-staged:
yarn add husky lint-staged -D
Copy the code
Git commit:
// package.json
{
"husky": {
"hooks": {
Lint-staged configuration will be read from package.json after git commit calls lint-staged commands
"pre-commit": "lint-staged"}}},Copy the code
Json “ling-passage” field to configure Lint-passage:
// package.json
{
"lint-staged": {
// Call eslint for ts, TSX,js files
"*.{ts,tsx,js}": [
"eslint -c .eslintrc.js"].// Call stylelint for CSS,less, SCSS files
"*.{css,less,scss}": [
"stylelint --config .stylelintrc.json"].// Prettier supports formatting of many types of files
"*.{ts,tsx,js,json,html,yml,css,less,scss,md}": [
"prettier --write"]}}Copy the code
Where does prettier’s –write argument work? For example, a call to 🌰 from the command line where prettier A.js prints formatted code to the console, does not modify the original file, and writes the formatted code to a.js with –write. One thing to note is that if you read some tutorials or projects where lint-staged configuration has been added with a Git Add step, the console will warn you:
⚠ Some of your tasks use
git add
command.
The reason for this is simple: Starting from V10, lint-staged files that have been modified from the original staged sections will be automatically Git Add, so you don’t need to add git Add yourself.
commitlint
commitlint
helps your team adhering to a commit convention. By supporting npm-installed configurations it makes sharing of commit conventions easy.
Commitlint is a tool for lint commit messages. Here’s an example:
I know some people like to submit code directly to three points… This is a bad habit, and you’re not taking advantage of the Commit Message at all, which is bad for project management. The standardized writing of commit message has many benefits, such as facilitating us to retrieve the submission history, directly generating Changelog with Xconventional – Changelog, and associated Github issue, etc.
Husky + CommLint will check the specification of the commit message and terminate the commit if it does not meet the specification.
Dependencies required by the installation:
yarn add @commitlint/cli @commitlint/config-conventional -D
Copy the code
@commitlint/ config-Conventional is an officially recommended Angular style commitlint configuration that provides a handful of lint rules similar to esLint’s extend.
The default type of commit it supports is:
["build"."ci"."chore"."docs"."feat"."fix"."perf"."refactor"."revert"."style"."test"]
Copy the code
Add the commLint configuration to the.commitlintrc.js root directory of the project:
// .commitlintrc.js
module.exports = {
extends: ['@commitlint/config-conventional'].rules: {
'type-enum': [
2.'always'.// More deps than the default, used to indicate dependency upgrades, downgrades, new commits, etc
['build'.'ci'.'chore'.'deps'.'docs'.'feat'.'fix'.'perf'.'refactor'.'revert'.'style'.'test']],}};Copy the code
Add git commit-msg hook:
// package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"."commit-msg": "commitlint -c .commitlintrc.js -E HUSKY_GIT_PARAMS"}}},Copy the code
When the commit-msg hook is called, the environment variable HUSKY_GIT_PARAMS is temporarily set to the path of the commit Messsge file, and commitLint is sent to the Commit Message in the file.
If you want to interactively edit commit messages on the command line, take a look at Commitizen. This project is not suitable for us, but we still think that the configuration needs to be tailored to the specific business. Our general-purpose template project is not necessary. I look at Angular and VUE – Next Lint commit messages. They are commitLint and Commitizen. Git commit-msg: git commit-msg: git commit-msg
We then configure automatic generation of Changelog, local installation conventional- Changelog – CLI:
yarn add conventional-changelog-cli -D
Copy the code
Add an NPM script:
// package.json
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
}
Copy the code
NPM Run Changelog generates Angular style Changelog. Convention-changelog reads the Commit message of type such as fix and feat in the commit history and automatically generates changelog.
Next, we discussed how to insert emojis using Commilint. We learned that the format of a commit message looks like this:
// The entire line is called header<type>(<scope>): <subject> // Empty line <body> // empty line <footer> Add Component Navbar // feat is type // component is scope // 'add Component Navbar' is subject // There is no body and footerCopy the code
Git emoji format:
:emoji_string:
Copy the code
If you commit with the following emoji commit message:
git commit -m ':bug: fix: xxx'
Copy the code
Commitlint and other tools should parse the first colon as type, meaning that the content before the colon on the left side of the emoji is interpreted as type. In this case, type is an empty string. So use the commit Message above to report an error that you did not enter type.
Commitlint cannot pass commitLint without changing the type configuration of CommilInt. One solution is to add a type :bug: Fix, but in this case, xconventional – Changelog-CLI will not extract the commit mesage to Changelog, it only recognizes the fix: XXX but not the bug: fix: XXX. Therefore, in the current configuration, if we want to insert emoji, we suggest using the way below. Although I think this is not pretty, it is a compromise solution at present.
git commit -m "chore: :memo: improve docs and config json"
Copy the code
second commit
Add several NPM scripts commonly used for Lint:
{
"scripts": {
"lint": "yarn run lint-eslint && yarn run lint-stylelint"."lint-eslint": "eslint -c .eslintrc.js --ext .ts,.tsx,.js {src,scripts}/**/*.{ts,tsx,js}"."lint-stylelint": "stylelint --config .stylelintrc.json src/**/*.scss --syntax scss",}}Copy the code
As you can see, I configure scripts for ESLint and stylelint with prefixes and arguments, and some projects configure script names with arguments with prefixes: arguments, that is, colons as delimiters. I think that’s bad, because some tools support the form YARN :scriptName to perform NPM scripts, such as Concurrently.
Suppose you have multiple NPM scripts: yarn:watch-node, yarn:watch-node, and yarn:watch-css. This tool supports one command to execute them in parallel:
concurrently yarn:watch-node yarn:watch-js yarn:watch-css
Copy the code
If you use a colon as a delimiter, you say:
concurrently yarn:watch:node yarn:watch:js yarn:watch:css
Copy the code
This may seem confusing, as those who do not know this might think that the following colon is also an argument of CONCURRENTLY, so NPM scripts with parameters do not use colons as separators.
Do one more yarn upgarde –latest to get into the habit of upgrading dependencies every day, so that you don’t get to know which dependency is causing many dependency upgrades at the same time. However, the company’s project must not do so, easy to lead to a bug continuous overtime.
Now that we’re done configuring react + typescript from scratch in the second installment of the react + typescript series, we’ll commit the code again:
git add -A
git commit -m 'build: integrate eslint, stylelint, prettier, lint-staged, commi
tlint'
The master branch and the Github remote repository were associated with the -u parameter
git push
Copy the code
This concludes the second article, and the third, on WebPack configuration, will be the most dry and probably the longest of the four. We will introduce how to use TypeScript to write express + WebPack devServer middleware as devServer, integrate some useful and cool Webpack plug-ins, optimize Babel configuration, optimize production environment packaging, etc.
For more details, we recommend looking directly at the source code at the react-typescript-Boilerplate project. If you find this article useful to you, you can appreciate star 😁. If you have any questions or improvements to this article, please feel free to comment and email.
This article is original content, first published in personal blog, reproduced please indicate the source.