ESLint+Prettier+ husky + stylelint +lint-staged代码规范实践

Prettier、 ESLint 、stylelint、husky 、lint-staged基本知识

Prettier 代码格式化例如超过设置的行代码长度换行处理,结尾不使用分号,统一使用单引号

prettier 就是把你的代码转化成一个抽象语法树 AST 然后根据 AST 将代码按照 prettier 的风格输出即可。可以用 prettier 官方提供的检测网站来看 prettier 的转化过程。

Eslint 代码质量的校验。例如使用了未定义的变量、三等号、api语法错误、修改const变量等等

  • 命令
    1
    2
    检查 eslint src/**/*.{js,ts,tsx}
    自动修复 eslint --fix src/**/*.{js,ts,tsx}
  • eslint-config-standard配置包扩展社区中流行的最佳实践的风格指南。
  • eslint-config-prettier 关闭 Eslint 中与 Prettier 冲突的选项,只会关闭冲突的选项,不会启用Prettier的规则
  • eslint-plugin-prettier 先使用Prettier对代码进行格式化,再并对不一致的地方进行标记

stylelint stylelint 是一个强大和现代的 CSS 审查工具,有助于开发者推行统一的代码规范,避免样式错误stylelint拥有超过150条的规则,包括捕捉错误、最佳实践、控制可以使用的语言特性和强制代码风格规范。。stylelint 由 PostCSS 提供技术支持,所以它也可以理解 PostCSS 解析的语法,比如 SCSS。
命令

1
stylelint --fix src/**/*.{html,css,scss}

插件:

EditorConfig 生成 .editorconfig 配置文件,规定当前编辑器的一些设定。抹平编辑器的差异。格式化的生效策略:自定义配置>editorconfig>编辑器的setting

husky git 操作的钩子。

lint-staged 只对 git 中staged(变更)的文件进行代码格式的校验和代码质量的校验操作。而不是项目中所有的文件。

1
2
3
//报错 在lint-staged命令中移除git add 命令本身自带git add

‼ Some of your tasks use `git add` command. Please remove it from the config since all modifications made by tasks will be automatically added to the git commit index.

ESLint和Prettier区别

1、ESLint 主要包含代码格式的校验,代码质量的校验,ESLint 在出--fix自动修复功能前只会提示一些warning和error,改起来非常复杂。
2、Prettier 只是格式化代码 。
*tips:如果你觉得的eslint自带的修复功能就足够的话可以不加Prettier *

ESLint+Prettier+ husky + stylelint +lint-staged 提高前端项目质量

通过pre-commit阶段增量校验的模式,尽量避免对老旧代码的影响;稳健地逐步完善老项目的强制校验和格式化提高前端项目质量、统一项目代码风格

1
yarn add husky lint-staged prettier eslint-plugin-prettier eslint-config-prettier stylelint stylelint-config-prettier stylelint-config-standard stylelint-prettier -D

我在项目中的配置可能不是很完美,有问题可以提出来
.eslintrc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"env": {
"amd": true,
"browser": true,
"node": true,
"es6": true
},
"extends": [
"react-app",
"plugin:prettier/recommended",
"prettier/react"
],
"plugins": [
"prettier"
],
"parser": "babel-eslint",
"rules": {
"prettier/prettier": "error"
}
}

.stylelintrc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
"defaultSeverity": "error",
"extends": [
"stylelint-config-recommended",
"stylelint-config-standard",
"stylelint-prettier/recommended",
],
"rules": {
"selector-pseudo-class-no-unknown": [true, {
ignorePseudoClasses: ["global"]
}],
"length-zero-no-unit": null,
"indentation": 2,
"max-empty-lines": 1,
"block-no-empty": true,
"block-opening-brace-newline-after": "always-multi-line",
"block-opening-brace-space-after": "always-single-line",
"block-opening-brace-space-before": "always",
"block-closing-brace-empty-line-before": "never",
"declaration-empty-line-before": "never",
"declaration-block-no-duplicate-properties": true,
"declaration-block-no-redundant-longhand-properties": true,
"shorthand-property-no-redundant-values": true,
"no-empty-source": true,
"no-eol-whitespace": true,
"no-extra-semicolons": true,
"no-invalid-double-slash-comments": true,
"no-missing-end-of-source-newline": true,
"at-rule-no-unknown": null,
},
}

.editorconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2 # 用两个空格代替制表符;
end_of_line = lf # win用cr lf,linux/unix用lf,mac用cr。统一window和mac
charset = utf-8
trim_trailing_whitespace = true# 在保存时删除尾部的空白字符;
insert_final_newline = true# 在文件结尾添加一个空白行;
max_line_length = 160# 每行代码最大宽度 160
[*.md]
trim_trailing_whitespace = false

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
{
"name": "xxx_front",
"version": "0.1.0",
"private": true,
"dependencies": {
"antd-mobile": "^2.3.1",
"axios": "^0.19.0",
"babel-plugin-import": "^1.12.2",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"chart.js": "^2.9.4",
"copy-to-clipboard": "^3.2.0",
"crypto-js": "^3.1.9-1",
"customize-cra": "^0.8.0",
"http-proxy-middleware": "^0.20.0",
"js-cookie": "^2.2.1",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"node-sass": "^4.14.1",
"qs": "^6.9.0",
"react": "^16.11.0",
"react-app-rewired": "^2.1.4",
"react-document-title": "^2.0.3",
"react-dom": "^16.11.0",
"react-loadable": "^5.5.0",
"react-redux": "^7.1.1",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-scripts": "3.2.0",
"react-sticky": "^6.0.3",
"redux": "^4.0.4",
"redux-thunk": "^2.3.0",
"url-parse": "^1.4.7",
"webpack": "4.41.0"
},
"scripts": {
"start": " react-app-rewired start",
"build:analyze": "set REACT_APP_BUILD_ENV=production && react-app-rewired build --analyze",
"lint": "eslint src/**/*.{js,ts,tsx}",
"fix": "prettier --write src/**/*.{js,ts,tsx}",
"lint:style": "stylelint --fix src/**/*.{html,css,scss}"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{css,scss}": [
"stylelint --fix",
"prettier --write"
],
"src/**/*.{js,ts,tsx}": [
"eslint --fix",
"prettier --write"
]
},
"browserslist": {
"production": [
"> 1%",
"last 5 versions",
"IOS > 8",
"Android > 4.6",
"UCAndroid >= 9",
"QQAndroid >= 8.2",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"eslint-config-prettier": "^7.2.0",
"eslint-plugin-prettier": "^3.3.1",
"husky": "^4.3.8",
"lint-staged": "^10.5.3",
"prettier": "^2.2.1",
"stylelint": "^13.9.0",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^20.0.0",
"stylelint-prettier": "^1.1.2",
"webpack-bundle-analyzer": "^4.3.0",
"webpack-cli": "^3.3.10"
}
}

提交commit之后

校验成功

校验失败

vscode插件推荐。

EditorConfig:生成 .editorconfig 配置文件,规定当前编辑器的一些设定。
ESLint:代码质量检查。
styleLint:css代码质量检查。
Prettier:格式化代码
Code Spell Checker:单词拼写检查。
Indent-Rainbow:彩虹缩进,缩进不规范时会标红提示。

vscode 的 setting.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"workbench.colorTheme": "Dracula Soft",
"editor.formatOnSave": true,//保存时使用VSCode 自身格式化程序格式化
"javascript.format.enable": false,//关闭编辑器对 js 文件的格式化,交给 ESLint 来做格式化,否则会格式化两次,解决editor.formatOnSave的兼容问题
"editor.codeActionsOnSave": {
"source.fixAll": true,
// For ESLint
"source.fixAll.eslint": true,
// For TSLint
"source.fixAll.tslint": true,
// For Stylelint
"source.fixAll.stylelint": true
},
"eslint.probe": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
}