起初我只是想让代码跑起来,至于里面的配置是什么意思,每个npm包之间又有什么关系,不好意思,我并不关心。但是,时间一长,强烈的求知欲就会驱使你去探索(因为项目中用了,怕面试被问到,一句玩笑)。
所以,关于这篇文章:理清楚各个npm包各有什么作用,之间有什么联系,以及常见的配置。
官方文档:ESLint
Find and fix problems in your JavaScript code
ESLint statically analyzes your code to quickly find problems. It is built into most text editors and you can run ESLint as part of your continuous integration pipeline.
--官方文档
代码质量非常容易理解,比如 eqeqeq这个把双等改三等的规则: ==
改成 ===
,这样的规则可以有效地避免一些 Magic Code Bug。
代码风格也是很容易理解,比如不喜欢加分号就加一条规则 semi规则:
{
"semi": [2, "never"]
}
代码千万行,安全第一行;前端不规范,同事两行泪
安装ESLint包有两种方式:
npm i eslint -D
vue create 创建项目过程中选择 lint
首先,
eslint_test
npm init -y
(创建 package.json)然后,直接安装eslint包:npm i eslint -D
注意安装结果:node_moduels 中下载了很多包
生成ESLint配置文件
ESLint 可以创建独立的配置文件 .eslintrc.js,也可以 直接在 package.json 中配置
支持 JavaScript、JSON 或者 YAML 文件三种格式(
.eslintrc.*
),会在创建过程中让我们选择使用哪种文件格式
执行 node_modules/.bin
文件夹里的 eslint脚本 来创建配置文件
包含完整脚本路径的命令:./node_modules/.bin/eslint --init
也可以用 npx 来执行 (推荐):npx eslint --init
(npx是随node一起安装的,能去 .bin 目录 里找 目标脚本文件,简化执行脚本的语法)
创建配置文件过程中,需要选择配置:
.eslintrc.js
ESLint执行
npx eslint ./需要检查语法的文件路径
编辑器上使用
我们用编辑器上安装eslint集成,可以在编写代码时,就会出现错误或者警告提示,不用每次执行eslint 来知道是否有问题。
配置文件格式
npx eslint --init
创建配置文件时,有提供配置文件的格式给我们选择:
eslint 加载的优先级是 : js > yaml > json,所以我们最好选择 js格式
JS格式使用模式
CommonJS
如果选择了 JavaScript modules
,那么就会是使用 export 导出配置数据
推荐:CommonJS
env节点
"env": {
"browser": true,
"commonjs": true,
"es2021": true
}
globals节点
"globals": {
"_": true // 可以读取,可以修改
"$": false // 可以读取,不能修改
}
globals
节点来手动配置全局成员插件(plugins)
"plugins": ["standard","promise","react"],
extends 节点
"extends": [
"standard" // "eslint-config-standard"
]
eslint-config-standard
规范eslint-config-
,直接写成 standard
解析器(parser)
默认情况下ESLint使用Espree解析器,这里我们可以修改它的默认设置。
parser": "babel-eslint",
parser: '@typescript-eslint/parser',
parserOptions 节点
"parserOptions": {
"ecmaVersion": 6, //ES的版本,默认为5
"sourceType": "module", //指定源代码存在的位置,script | module,默认为script。
"ecmaFeatures": { //指定要使用其他那些语言对象
"experimentalObjectRestSpread": true,//启用对对象的扩展
"jsx": true, //启用jsx语法
"globalReturn":true, //允许return在全局使用
"impliedStrict":true //启用严格校验模式
}
}
env
节点配置rules 节点
"rules": {
}
规则的错误等级有三种:
例子:
{
"rules": {
"eqeqeq": "off",
"curly": "error",
"quotes": ["error", "double"]
}
}
extends
和 plugins
的区别⭐通常 EsLint 中默认提供了一系列内置的 Rules 规则提供给我们进行配置,从而检测我们的 JavaScript 代码。
但是在某些特定条件下,内置的一些规则并不能满足我们的代码检查。
所以此时我们就要基于该情况做一些特殊的拓展了,Plugin 的作用正是处理这些功能而生。
比如,通常在我们使用 Eslint 来检查我们的代码时,需要将解析器替换为 @typescript-eslint/parser
的同时针对于一些 TypeScript 特定语法我们还需要使用 @typescript-eslint/eslint-plugin
来支持一些特定的 TS 语法检查。
这里我们额外安装的 @typescript-eslint/eslint-plugin
中就包含了一系列有关于 TS 文件检测的特殊规则。
在 EsLint 内部并不支持有关于 Ts 的一些语法,自然我们需要通过 Plugin 来拓展对应的检测规则。
如果说上述 Plugins 和 Rules 可以满足项目的 Lint 配置的话,那么 Extends 关键字可以理解为关于 Plugins 和 Rules 结合而来的最佳实践。
正如其名,Extends 表示继承的意思。通常在不同的项目中,大多数情况下都具有相同的 Lint 相关配置。
基于这种情况 EsLint 提供了 Extends 关键字来解决不同项目下存在的通用配置。我们可以利用 EsLint 中的 Extends 关键字来继承一些通用的配置。
比如,EsLint 官方提供了 eslint:recommended
规则,当我们在配置文件中继承 "eslint:recommended"
时,相当于启用了一系列核心规则,这些规则会被 EsLint 官方维护在 "eslint:recommended"
中定期更新:
// .eslintrc.js
module.exports = {
root: true,
parser: 'espress',
parserOptions: {
ecmaVersion: 6,
},
extends: ['eslint:recommended'],
};
// index.js
const a = 'hello world'; // error: 'a' is assigned a value but never used.eslintno-unused-vars
上述的代码可以看到,我们没有定义任何 rules 以及 plugins 。仅仅是 extends: ['eslint:recommended']
。
此时我们在 index.js
中定义了 a 变量但为使用,EsLint 会为我们检测出错误 'a' is assigned a value but never used.eslintno-unused-vars
。
其实,extends
的作用简单来说就是在项目内继承于另一份 EsLint 配置文件而已。
Extends 继承关键字存在三种写法(情况):
extends: ['eslint:recommended']
extends : ['eslint-config-airbnb']
extends: ['plugin:react/recommended']
extends: ["./node_modules/coding-standard/eslintDefaults.js"]
// .eslintrc.js
module.exports = {
"extends": [
// 直接从 EsLint 本身集成的规则继承
"eslint:recommended",
// 从一些第三方NPM包进行继承,比如 eslint-config-standard、eslint-config-airbnb
// eslint-config-* 中 eslint-config- 可以省略
"airbnb",
// 直接从插件继承规则,可以省略包名中的 `eslint-plugin`
// 通常格式为 `plugin:${pluginName}/${configName}`
"plugin:@typescript-eslint/recommended",
]
}
运行ESLint
npx eslint ./index.js // 检查 目标文件
npx eslint ./src // 检查 目标文件夹 中所有js文件
ESLint语法规范本质
前面看到,ESLint 安装时自带280多个规范,而开发时,未必都要使用,各个公司根据自己的习惯选择
所以就用了不同的选择组合:
a. ESLint内置规范包 :eslint-all / eslint-recommended
b. 标准规范包:eslint-config-standard
c. 第三方规范包(google/airbnb/facebook…)
内置规范包
已经随eslint一起下载:
eslint-all
:使用全部280多个规则
eslint-recommended
:只使用推荐的60个规则
标准规范包(需要下载)
包名:eslint-config-standard
也使用了200多个规则
下载方式:
可以在前面创建 eslint配置文件时 选择下载
手动下载,官方git地址:github.com/standard/st…
下载包:npm i eslint-config-standard -D
降低eslint版本:npm i [email protected]
(standard依赖低版本的eslint)
修改eslint配置文件中的 es版本:
第三方规范包
有很多啊,我们就拿最流行的 airbnb 来举例
包名:eslint-config-airbnb-base
:好多规则,数不过来。。。
官方npm地址:www.npmjs.com/package/esl…
手动下载:
总结:严格程度 all > airbnb-base > standard > recommended
我们的整个项目中,有一些文件是不需要eslint进行检查,我们可以用到忽略文件。
在我们的工程目录中新建一个文件,命名为“.eslintignore
”,Eslint会自动识别这个文件。
这个配置文件里面,每一行都是一个glob模式语句,具体格式如下:
.eslintignore当 ESLint 在目录上运行时,ESLint 支持文件从linting 进程中排除文件。作为单独的 CLI 参数给出的文件将免除排除。该.eslintignore文件是一个纯文本文件,每行包含一个模式。它可以位于任何目标目录的祖先中; 它会影响其包含目录中的文件以及所有子目录。
node_modules/*
**/vendor/*.js
Prettier(直译过来就是"更漂亮的")
Prettier是一个能够完全统一你和同事代码风格的利器.
一般是ESLint 与 Prettier配合使用:
ESLint 主要负责处理两种规则:格式化和代码质量问题。格式化不是它的强项,需要用 Prettier 格式化大师来处理代码风格有问题的代码。
Prettier 格式化后的代码,理论上是最好看的。正因为 Prettier 只关注格式化,所以它也可以格式化其它的文件,如 .yml
, .json
, .md
等。
先安装依赖:
npm i -D prettier # 安装依赖
下面对prettier进行配置:一共有三种方式支持对Prettier进行配置:
.prettierrc.js
文件,能够写入YML、JSON的配置格式,并且支持.yaml/.yml/.json/.js
后缀;.prettier.config.js
文件,并对外export一个对象;package.json
中新建prettier
属性。下面我们使用prettierrc.js
的方式对prettier进行配置,同时讲解下各个配置的作用。
module.exports = {
"printWidth": 80, //一行的字符数,如果超过会进行换行,默认为80
"tabWidth": 2, //一个tab代表几个空格数,默认为80
"useTabs": false, //是否使用tab进行缩进,默认为false,表示用空格进行缩减
"singleQuote": false, //字符串是否使用单引号,默认为false,使用双引号
"semi": true, //行位是否使用分号,默认为true
"trailingComma": "none", //是否使用尾逗号,有三个可选值""
"bracketSpacing": true, //对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
"parser": "babylon" //代码的解析引擎,默认为babylon,与babel相同。
}
或者我们在根目录下创建.prettierrc
文件:
{
"useTabs": false,
"tabWidth": 2,
"printWidth": 80,
"singleQuote": true,
"trailingComma": "none",
"semi": false
}
创建.prettierignore
忽略文件
/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*
一般而言,我们还需要集成 vscode-prettier
这个插件来完成自动保存格式化,在插件市场安装好了以后,在我们的.vscode/settings.json
中添加如下规则
{
"editor.formatOnSave": true, // 开启自动保存
"editor.defaultFormatter": "esbenp.prettier-vscode", // 默认格式化工具选择prettier
}
这样一来,当我们在vscode写代码的时候,便会自动格式化了。
为什么要两者配合使用?因为,第一在 ESLint 推出 --fix 参数前,ESLint 并没有自动化格式代码的功能,要对一些格式问题做批量格式化只能用 Prettier 这样的工具。第二 ESLint 的规则并不能完全包含 Prettier 的规则,两者不是简单的谁替代谁的问题。但是在 ESLint 推出 --fix 命令行参数之后,如果你觉得 ESLint 提供的格式化代码够用了,也可以不使用 Prettier。
prettier 是擅长代码格式的校验,eslint擅长代码质量的校验。虽说 eslint 也能格式校验,但是并没有 prettier 那么强势。
ESLint 和 Prettier 相互合作的时候有一些问题,对于他们交集的部分规则,ESLint 和 Prettier 格式化后的代码格式不一致。导致的问题是:当你用 Prettier 格式化代码后再用 ESLint 去检测,会出现一些因为格式化导致的 warning。
ESLint 和 Prettier 相互合作的时候有一些问题,对于他们交集的部分规则,ESLint 和 Prettier 格式化后的代码格式不一致。导致的问题是:当你用 Prettier 格式化代码后再用 ESLint 去检测,会出现一些因为格式化导致的 warning。这个时候有两个解决方案:
1.运行 Prettier 之后,再使用 eslint --fix 格式化一把,这样把冲突的部分以 ESLint 的格式为标准覆盖掉,剩下的 warning 就都是代码质量问题了。
2.在配置 ESLint 的校验规则时候把和 Prettier 冲突的规则 disable 掉,然后再使用 Prettier 的规则作为校验规则。那么使用 Prettier 格式化后,使用 ESLint 校验就不会出现对前者的 warning。
为什么不能先使用 ESLint 再使用 Prettier? 针对方案1,如果你后使用 Prettier,那么格式化后提交的代码在下一次或者别人 checkout 代码后是通不过 lint 校验的。
针对方案2,其实是可以的,但是本人在实践中看社区方案的时候有提到某些情况下 eslint --fix 和 prettier 混用会出现格式问题。所以保险起见还是先用 perttier 格式化,再用 eslint 命令校验,而不用 eslint --fix 命令去格式化。
在理想的状态下,eslint与prettier应该各司其职。eslint负责我们的代码质量,prettier负责我们的代码格式。但是在使用的过程中会发现,由于我们开启了自动化的eslint修复与自动化的根据prettier来格式化代码。所以我们已保存代码,会出现屏幕闪一起后又恢复到了报错的状态。
这其中的根本原因就是eslint有部分规则与prettier冲突了,所以保存的时候显示运行了eslint的修复命令,然后再运行prettier格式化,所以就会出现屏幕闪一下然后又恢复到报错的现象。这时候你可以检查一下是否存在冲突的规则。
查阅资料会发现,社区已经为我们提供了一个非常成熟的方案,即eslint-config-prettier + eslint-plugin-prettier。
安装插件:(vue在创建项目时,如果选择prettier,那么这两个插件会自动安装)
npm i eslint-plugin-prettier eslint-config-prettier -D
在 .eslintrc.json中extends的最后添加一个配置:
关键在于新增加的 plugin:prettier/recommended
这个规则
{
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:@typescript-eslint/recommended',
+ // 新增,必须放在最后面
+ 'plugin:prettier/recommended'
],
}
eslint-plugin-prettier
插件会调用prettier对你的代码风格进行检查,其原理是先使用prettier对你的代码进行格式化,然后与格式化之前的代码进行对比,如果过出现了不一致,这个地方就会被prettier进行标记,最后eslint自动fix按照prettier的规范修复error代码
// (重要)这个是为了 eslint 跟 prettier 可以联合使用
npm install --save-dev eslint-plugin-prettier
// (重要)这个是为了让 eslint 跟 prettier 兼容,关闭 prettier 跟 eslint 冲突的rules
npm install --save-dev eslint-config-prettier
最后再来解释下plugin:prettier/recommended
的含义,这个其实是多个eslint的配置集合,一个配置搞定,降低配置成本,下面代码就是实际eslint的原子配置:
{
"extends": ["prettier"], // 生效 eslint-config-prettier 屏蔽配置
"plugins": ["prettier"], // 生效 eslint-plugin-prettier 提示配置
"rules": {
"prettier/prettier": "error", // prettier报错的级别,红色波浪线
"arrow-body-style": "off", // 冲突无法解决,直接关闭
"prefer-arrow-callback": "off" // 冲突无法解决,直接关闭
}
}
.editorconfig
配置文件用于抹平不同编辑器或系统之间的编码差异,放在项目根目录。最常见的配置之一是 end_of_line = lf
,如果用 Windows 和 Mac 混合开发,不统一行尾符会造成 eslint 爆红。
由于不同开发者的编辑器设置不同, 故在项目中应当包含 .editorconfig,用来统一配置编辑器的换行、缩进存储格式。
配置参考:
# http://editorconfig.org
root = true
[*]
indent_style = space # 输入的 tab 都用空格代替
indent_size = 2 # 一个 tab 用 2 个空格代替
# end_of_line = lf # 换行符使用 unix 的换行符 \n
charset = utf-8 # 字符编码 utf-8
trim_trailing_whitespace = true # 去掉每行末尾的空格
insert_final_newline = true # 每个文件末尾都加一个空行
[*.md]
trim_trailing_whitespace = false # .md 文件不去掉每行末尾的空格
node包是里面的是在编译期给你报错用的,报错了会停止编译,直到你修复。 vscode插件是可视化插件 在你编写代码时候就可以看到不合规范的代码
因为我平时前端开发用的是vscode居多,所以这里暂时就介绍vscode的环境配置
在根目录的.vscode/settings.json
添加如下:
{
"eslint.enable": true, //是否开启vscode的eslint
"eslint.alwaysShowStatus": true,//是否在保存的时候自动fix eslint
"eslint.options": { //指定vscode的eslint所处理的文件的后缀
"extensions": [
".js",
".vue",
".ts",
".tsx"
]
},
"eslint.validate": [ //确定校验准则
"javascript",
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
并且确保Vscode安装过下面的插件:
如果安装了prettier插件,下面是.vscode/settings.json
中要加上的配置:
{
"editor.formatOnSave": true, //开启自动保存
"editor.defaultFormatter": "esbenp.prettier-vscode", //默认格式化工具选择prettier
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
以后只要按了保存快捷键,就会自动格式化,一步到位。
首先安装依赖:
npm i -d eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
这三个依赖分别是:
安装好这3个依赖包之后,在根目录下新建.eslintrc.js文件,该文件中定义了ESLint的基础配置,一个最为简单的配置如下所示:
module.exports = {
env:{ //指定代码的运行环境
browser: true,
node: true,
}
parser: '@typescript-eslint/parser', //定义ESLint的解析器
extends: ['plugin:@typescript-eslint/recommended'],//定义文件继承的子规范
plugins: ['@typescript-eslint'],//定义了该eslint文件所依赖的插件
parserOptions: {
project: ["./tsconfig.json"], // 告诉 eslint:tsconfig 在哪
},
}
Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
这个错误是因为:既然你默认规定 ESLint 要 lint .eslintrc.js
,可是 tsconfig.json
里又没有 include 这个文件。导致 ESLint 想 Lint .eslintrc.js
的时候,发现它又不在 Parser 的 tsconfig.json
名单列表上,就蒙逼了。
最简单的解决方法就是在在 tsconfig.json
里 include 一下就 OK 了:
{
"compilerOptions": {...},
"include": [".eslintrc.js", "src"],
"exclude": ["node_modules"]
}
或者在 .eslintignore
里添加该文件,将其忽略掉:
# 忽略 .eslintrc.js
.eslintrc.js
但是这两都不是很好的解决方法,因为除了 src
目录,正常项目中还会有很多其它普通的 .js
文件,比如 .babelrc.js
, webpack.config.js
, start.js
等配置文件。我们既想要 ESLint x Prettier 格式化这些文件,但又不想将它们放到 tsconfig.json
里做类型检查。
ESLint 正好提供了一个 overrides
配置来解决这样的问题:
module.exports = {
env: {
// 支持浏览器环境
browser: true,
// 识别 ES 的代码,使用 ECMAScript 2021 自动设置 ecmaVersion parser 为 12,
es2021: true,
// Linter .eslintrc.js 自己的时候要用 node 环境
node: true,
},
extends: [
"eslint:recommended",
"plugin:prettier/recommended"
],
overrides: [
// 处理 TS 文件
{
files: ["**/*.{ts,tsx}", "**/*.{js,jsx}"], // 只处理 ts 和 js 文件
excludedFiles: [".eslintrc.js"], // 这里禁用了 .eslintrc.js 的类型检查
parser: "@typescript-eslint/parser", // 能看懂 TypeScript
parserOptions: {
project: ["./tsconfig.json"], // 告诉 eslint:tsconfig 在哪
},
extends: [
// typescript-eslint 的推荐规则,只是这些最佳规则都是针对 TS 的
"plugin:@typescript-eslint/recommended",
// tsconfig.json 里 Type Checking 的推荐规则
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
plugins: [
// 使用 typescript x eslint 的插件
"@typescript-eslint",
],
},
],
}
上面的配置把 TypeScript 的 ESLint 配置归为一类,并只对 "**/*.{ts,tsx}", "**/*.{js,jsx}"
进行 Lint 操作,同时将 .eslintrc.js
排除掉。这样一来,ESLint 不仅可以针对这类文件来做 Linter 检查,开发者也不用把冗余的 .js
文件放到 tsconfig.json
里了。
到此为止, ESLint x TypeScript 已经完成了。
通过上面的 ESLint x TypeScript 配置,我们不难发现 ESLint 的又一大规律:
.js
文件时,可以搜索 “ESLint xxx plugin” 来解决ESLint可以通过 env
来设定 ESLint 的默认 ECMAScript parser 的版本,所以 ESLint 其实是自带有 parser 的,但是它只支持 最新版的 ECMAScript 标准。
而 JavaScript 依然在不断发展,时不时又出一些新的 API 或者提案,对于要尝鲜的开发者,ESLint 的 Parser 就解析不动 .js
了,因此,我们需要 @babel/eslint-parser。
npm i -D @babel/core @babel/eslint-parser
然后添加 .babelrc.js
,在里面写项目的 babel 规则。
然后在 overrides
里新增对 .js
的处理:
module.exports = {
env: {
// 支持浏览器环境
browser: true,
// 识别 CommonJS
node: true,
// 识别 ES 的代码,使用 ECMAScript 2021 自动设置 ecmaVersion parser 为 12,
es2021: true,
},
extends: [
"eslint:recommended", // eslint 自己的推荐规则,最佳实践最小集
"plugin:prettier/recommended", // 禁用 eslint 关于代码的风格的规则,使用 prettier 的风格
],
overrides: [
// 处理 JS 文件
{
files: ["**/*.{js,jsx}"], // 只处理 js 和 jsx 文件
parser: "@babel/eslint-parser", // 使用 babel 来解析 js 文件
parserOptions: {
sourceType: "module", // 支持 import/export
allowImportExportEverywhere: false,
ecmaFeatures: {
globalReturn: false,
},
},
},
// 处理 TS 文件
{
files: ["**/*.{ts,tsx}"], // 只处理 ts 和 js 文件
parser: "@typescript-eslint/parser", // 能看懂 TypeScript
parserOptions: {
project: ["./tsconfig.json"], // 告诉 eslint:tsconfig 在哪
},
extends: [
// typescript-eslint 的推荐规则,只是这些最佳规则都是针对 TS 的
"plugin:@typescript-eslint/recommended",
// tsconfig.json 里 Type Checking 的推荐规则
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
plugins: [
// 使用 typescript x eslint 的插件
"@typescript-eslint",
],
},
],
};
它只需要一个 eslint-plugin-vue:
npm i -D eslint-plugin-vue
我们依然可以在 overrides
中新增一条只针对 .vue
文件的配置:
overrides: [
// 处理 vue 文件
{
files: ["**/*.vue"], // 只处理 vue 文件
extends: ["plugin:vue/vue3-recommended"], // 使用 vue3 的推荐规则
}
]
这样就可以对所有 .vue
文件执行 eslint '**/*.vue' --fix
了
ESLint 再强大也只是 JavaScript 和 TypeScript 的 Linter,对样式文件 .css
, less
, scss
则需要 StyleLint。
先来安装一些必要的 NPM 包:
# StyleLint
npm i -D stylelint
# StyleLint 的 Prettier 插件,类似 eslint-plugin-prettier
npm i -D stylelint-prettier
# 禁用与 Prettier 冲突的 StyleLint 规则
npm i -D stylelint-config-prettier
# 基础规则(可选)
npm i -D stylelint-config-standard
配置 .stylelintrc.js
:
module.exports = {
"plugins": ["stylelint-prettier"],
"extends": [
"stylelint-config-standard",
"stylelint-config-prettier"
],
"rules": {
"prettier/prettier": true
}
}
不过,当要配置 less 或者 scss 还需要一点步骤。
# StyleLint 的 Less 插件
npm i -D stylelint-less
# StyleLint 的 Less 规则
npm i -D stylelint-config-recommended-less
# StyleLint 处理 customSyntax
npm i -D postcss-less
修改配置:
module.exports = {
"plugins": ["stylelint-prettier"],
"extends": [
"stylelint-config-standard",
"stylelint-config-recommended-less",
"stylelint-config-prettier"
],
"customSyntax": "postcss-less",
"rules": {
"prettier/prettier": true
}
}
对于不使用vscode的,或者没有安装eslint、preitter与stylelint插件的同学来说,就不能实现在保存的时候自动的去修复与和格式化代码。
这样提交到git仓库的代码还是不符合要求的。因此需要引入强制的手段来保证提交到git仓库的代码时符合我们的要求的。
husky是一个用来管理git hook的工具,git hook即在我们使用git提交代码的过程中会触发的钩子。
虽然我们已经要求项目使用eslint了,但是不能保证组员提交代码之前都将eslint中的问题解决掉了:
也就是我们希望保证代码仓库中的代码都是符合eslint规范的;
那么我们需要在组员执行 git commit 命令的时候对其进行校验,如果不符合eslint规范,那么自动通过规范进行修复;
那么如何做到这一点呢?可以通过Husky工具:
husky是一个git hook工具,可以帮助我们触发git提交的各个阶段:pre-commit、commit-msg、pre-push
注意,执行这里的操作的前提是已经执行了git init
命令,可能在自己建立测试文件时忘记执行git init
命令,导致命令执行失败。
# 安装哈士奇
npm install husky -D
# 添加 prepare 命令
npm set-script prepare "husky install"
# prepare 创建 bash 脚本,安装 git hooks
npm run prepare
# 添加 pre-commit 的 git hook 脚本
npx husky add .husky/pre-commit "npx eslint src --fix"
运行之后会发现在 ./.husky/pre-commit
里看到 git commit
前会运行的脚本:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# git commit 前先 eslint fix 一波
npx eslint src --fix
但是这样的命令会让每次 commit 前都把整个 src
都扫描并 fix 一次,速度太慢了,而且很容易把别人的屎山也 fix 掉,然后提交上去。
我们更希望只针对提交的文件进行 Lint 操作。
# 安装
npm i -D lint-staged
然后添加 .lintstagedrc.js
配置文件,里面对提交不同的文件进行 eslint --fix
操作。
module.exports = {
'**/*.{ts,tsx,js,jsx}': [
"eslint --cache --fix",
],
"**/*.vue": [
"eslint --cache --fix",
],
"**/*.{css,less}": [
"stylelint --cache --fix",
]
}
lint-staged
配置的含义是对提交上来不同类型的文件执行对应的 lint fix 命令。
最后在刚刚创建的 ./.husky/pre-commit
里改成执行 lint-staged
命令:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
以后每次 commit 前都会跑一次 lint-staged
,而 lint-staged
又会对提交的文件进行 ESLint Fix。
通常我们的git commit会按照统一的风格来提交,这样可以快速定位每次提交的内容,方便之后对版本进行控制。
但其实那些一串长长的英文提交信息并不是每次都手写上去。
我们可以使用一个工具:Commitizen
Commitizen 是一个帮助我们编写规范 commit message 的工具;
1.安装Commitizen
npm install commitizen -D
2.安装cz-conventional-changelog,并且初始化cz-conventional-changelog:
npx commitizen init cz-conventional-changelog --save-dev --save-exact
这个命令会帮助我们安装cz-conventional-changelog:
并且在package.json中进行配置:
这个时候我们提交代码需要使用 npx cz
:而不是使用 git commit -m “xxx”
Type | 作用 |
---|---|
feat | 新增特性 (feature) |
fix | 修复 Bug(bug fix) |
docs | 修改文档 (documentation) |
style | 代码格式修改(white-space, formatting, missing semi colons, etc) |
refactor | 代码重构(refactor) |
perf | 改善性能(A code change that improves performance) |
test | 测试(when adding missing tests) |
build | 变更项目构建或外部依赖(例如 scopes: webpack、gulp、npm 等) |
ci | 更改持续集成软件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等 |
chore | 变更构建流程或辅助工具(比如更改测试环境) |
revert | 代码回退 |
第二步选择本次修改的范围(作用域)
我们也可以在scripts中构建一个命令来执行 cz:
如果我们按照cz来规范了提交风格,但是依然有同事通过 git commit
按照不规范的格式提交应该怎么办呢?
1.安装 @commitlint/config-conventional 和 @commitlint/cli
npm i @commitlint/config-conventional @commitlint/cli -D
2.在根目录创建commitlint.config.js文件,配置commitlint
module.exports = {
extends: ['@commitlint/config-conventional']
}
3.使用husky生成commit-msg文件,验证提交信息:(对提交信息进行拦截)
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
或者手动创建文件:
我们手动创建文件 commit-msg
:该文件与pre-commit
文件同级
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit
此时我们测试用git commit 提交,失败
所以我们必须用npx cz提交,但是该命令不太熟悉,要改名
我们在package.json中新增脚本:“commit”: “cz”
整体配置如下:
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"prettier": "prettier --write .",
"prepare": "husky install",
"commit": "cz"
},
以后我们使用 npm run commit
来进行提交
如果想自己定义提交规范也是可以的,首先要下载自定义规范约束的包替换第三方规范。
npm i -D commitlint-config-cz cz-customizable
变更 commitlint.config.js 这里采用自己定义的规范,将会覆盖上面那个,所以上面那个可以不用安装:
module.exports = {
extends: ['cz'], //采用 cz 自定义的提交规范 -> .cz-config.js
};
在项目根目录创建.cz-config.js
,可以再这个文件里自定义规范(下面这是我自定义的配置)
新增.cz-config.js
文件:
'use strict'
module.exports = {
types: [
{ value: '✨新增', name: '新增: 新的内容' },
{ value: '修复', name: '修复: 修复一个Bug' },
{ value: '文档', name: '文档: 变更的只有文档' },
{ value: '格式', name: '格式: 空格, 分号等格式修复' },
{ value: '♻️重构', name: '重构: 代码重构,注意和特性、修复区分开' },
{ value: '⚡️性能', name: '性能: 提升性能' },
{ value: '✅测试', name: '测试: 添加一个测试' },
{ value: '工具', name: '工具: 开发工具变动(构建、脚手架工具等)' },
{ value: '⏪回滚', name: '回滚: 代码回退' }
],
scopes: [
{ name: 'leetcode' },
{ name: 'javascript' },
{ name: 'typescript' },
{ name: 'Vue' },
{ name: 'node' }
],
// it needs to match the value for field type. Eg.: 'fix'
/* scopeOverrides: {
fix: [
{name: 'merge'},
{name: 'style'},
{name: 'e2eTest'},
{name: 'unitTest'}
]
}, */
// override the messages, defaults are as follows
messages: {
type: '选择一种你的提交类型:',
scope: '选择一个scope (可选):',
// used if allowCustomScopes is true
customScope: 'Denote the SCOPE of this change:',
subject: '短说明:\n',
body: '长说明,使用"|"换行(可选):\n',
breaking: '非兼容性说明 (可选):\n',
footer: '关联关闭的issue,例如:#31, #34(可选):\n',
confirmCommit: '确定提交说明?(yes/no)'
},
allowCustomScopes: true,
allowBreakingChanges: ['特性', '修复'],
// limit subject length
subjectLimit: 100
}
package.json 中,将原来commit配置,变更为自定义配置:
// 使用自定义规范则使用
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
}
}
到目前为止,我们已经实现了一份较完整的代码规范配置。
以后当我们进行代码提交时,具体操作如下:
␍
eslint(prettier/prettier)如果存在.prettierrc文件添加如下配置
"endOfLine": "auto"
如果不存在该文件 打开vscode编辑器的setting.json文件添加如下配置
"prettier.endOfLine": "auto", // 结尾是 \n \r \n\r auto
这种是版本问题。
解决方案:
@vue/prettier改为prettier
原因还不知道, @vue/prettier在@vue/下没找到
在使用eslint配置时,提交出现bug:
C:\Users\USER\AppData\Roaming\npm\node_modules\ts-node\dist\index.js:729
return old(m, filename);
^
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\USER\Desktop\tindin\node_modules\node-fetch\src\index.js from C:\Users\USER\Desktop\tindin\src\api\services\unsplash.ts not supported.
Instead change the require of index.js in C:\Users\USER\Desktop\tindin\src\api\services\unsplash.ts to a dynamic import() which is available in all CommonJS modules.
at Object.require.extensions. [as .js] (C:\Users\USER\AppData\Roaming\npm\node_modules\ts-node\dist\index.js:729:20)
at Object. (C:\Users\USER\Desktop\tindin\src\api\services\unsplash.ts:23:30)
at Module.m._compile (C:\Users\USER\AppData\Roaming\npm\node_modules\ts-node\dist\index.js:735:29)
at Object.require.extensions. [as .ts] (C:\Users\USER\AppData\Roaming\npm\node_modules\ts-node\dist\index.js:737:16)
at main (C:\Users\USER\AppData\Roaming\npm\node_modules\ts-node\dist\bin.js:238:16)
at Object. (C:\Users\USER\AppData\Roaming\npm\node_modules\ts-node\dist\bin.js:351:5) {
code: 'ERR_REQUIRE_ESM'
本人参考了一些解决方案,但都未解决该问题,相关解决方式链接如下:
return old(m, filename); Error : require() of ES Module
我的解决方式: 将根目录下的 commitlint.config.js
文件后缀名改为 cjs,即 commitlint.config.cjs 文件
最常见的 eslint 和 prettier 冲突:
eslint 侧重于代码规范,而 prettier 是满足代码规范前提下的格式优化。如果两者冲突,首先肯定是符合规范的,我们只需要让 eslint 对格式的要求按照 prettier 的来就行。注意 prettier 一定要置于 extends 的最后,才不会被其他扩展覆盖。
.eslintrc.js
module.exports = {
extends: [
// ...
'plugin:prettier/recommended' //注意要放在最后
],
};
参考文章:
【一听就懂】ESLint机制浅析-整体机制与规范包
深入浅出 Eslint,告别 Lint 恐惧症
前端项目代码规范落地方案 ESlint+Prettier
前端工具小指南之Prettier
Linter上手完全指南
Eslint + Prettier + Husky + Commitlint+ Lint-staged 规范前端工程代码规范