1.ESLint
1.1 ESLint 安装
(1)脚手架自动安装
如果是采用脚手架如Vue-Cli创建项目,在创建项目时就可以选择安装ESLint,安装完成后,会自动在项目根目录生成一个.eslintrc.js文件,里面已经生成了ESLint的初始化默认配置。
如果没有申城.eslintrc.js文件,则使用下面命令:
eslint --init
(2)手动安装
如果是已经存在一个项目,并且想要安装ESLint,可以通过npm的方式进行安装。
npm install -g eslint //需要全局安装,使用 -g
npm i -g babel-eslint
安装完成后,保存就可以自动校验。
安装完成后,可以执行下面命令进行ESLint的初始化配置。
下面命令有可能会不执行;
eslint --init
经过一系列一问一答的环节后,你会发现在你项目根目录已经生成了一个 .eslintrc.js文件,该文件主要用来进行ESLint的配置。
1.2 运行EsLint 检查文件
当我们配置好.eslintrc.js文件后,我们就可以通过运行ESLint相关命令,对指定文件进行检查,假设当前的项目目录如下所示:
其中,.eslintrc.js文件的配置如下,这里采用了Vue-Cli创建项目后给出的默认配置。
module.exports = {
// *
// * 默认情况下,ESLint会在所有父级目录里寻找配置文件,一直到根目录。
// * 为了将ESLint限制在一个特定的项目,设置root: true;
// * ESLint一旦发现配置文件中有 root: true,就会停止在父级目录中寻找。
// *
root: true,
// 指定解析器
// babel-ESLint: 一个对Babel解析器的包装,使其能够与ESLint兼容。
// parser: 'babel-eslint',
// 设置解析器能帮助ESLint确定什么是解析错误。
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module',
// 指定js版本。语法上的支持
ecmaVersion: 6
},
// 脚本在执行期间访问的额外的全局变量
// globals: {},
// env: 指定脚本的运行环境
env: {
// 一个环境定义了一组预定义的全局变量。
browser: true,
// 会自动开启es6语法支持。
es6: true,
node: true
},
// 配置文件从基础配置中继承已启用的规则。
// *
// * eslint:recommended 启用核心规则,在规则页面中被标记为 √ 的。
// *
extends: [
// plugin:(此处不能有空格)包名/配置名称。解析时plugin是解析成 eslint-plugin-vue。如果有空格会解析失败,eslint-plugin- vue。
// plugin可以省略包名的前缀 eslint-plugin-
'plugin:vue/essential',
'eslint:recommended'
// 也可以指定另一个基本配置文件的绝对路径或相对路径
],
// *
// * 每个规则有【3】个错误级别。
// * off或0: 关闭该规则;
// * warn或1: 开启规则,使用警告级别的错误,不会导致程序退出;
// * error或2: 开启规则,使用错误级别的错误,当被触发的时候,程序会退出。
// *
rules: {
'semi': 2,
// *
// * 【==== Possible Errors ====】
// * 这些规则与JavaScript代码中可能的错误或逻辑错误有关。
// */
// 强制"for"循环中更新子句的计算器朝着正确的方向移动
'for-direction': 2,
// 禁止function定义中出现重名参数
'no-dupe-args': 2,
// 禁止对象字面量中出现重复的key
'no-dupe-keys': 2,
// 禁止出现重复的case标签
'no-duplicate-case': 2,
// 禁止对catch子句的参数重新赋值
'no-ex-assign': 2,
// 禁止对关系运算符的左操作数使用否定操作符
'no-unsafe-negation': 2,
// 禁止出现令人困惑的多行表达式
'no-unexpected-multiline': 2,
// 禁止在return、throw、continue、break语句之后出现不可达代码
'no-unreachable': 2,
// 禁止在finally语句块中出现控制流语句
'no-unsafe-finally': 2,
// 要求使用isNaN()检查NaN
'use-isnan': 2,
// 强制typeof表达式与有效的字符串进行比较
'valid-typeof': 2,
// 还可以写表达式,厉害了~
'no-debugger': 'off',
'no-console':'error',
// *
// * 【==== Best Practices ====】
// * 这些规则是关于最佳实践的,帮助你避免一些问题。
// *
// 强制 getter 和 setter在对象中成对出现
'accessor-pairs': 2,
// 强制所有控制语句使用一致的括号风格
'curly': [2, 'multi-line'],
// 强制在点号之前和之后一致的换行
'dot-location': [2, 'property'],
// 要求使用 ===和 !==
'eqeqeq': [2, 'allow-null'],
// 禁用arguments.caller 或 arguments.callee
'no-caller': 2,
// 禁止使用空解构模式
'no-empty-pattern': 2,
// 禁止eval()
'no-eval': 2,
// 禁止使用类似eval()的方法
'no-implied-eval': 2,
// 禁止扩展原生类型
'no-extend-native': 2,
// 禁止不必要的.bind()调用
'no-extra-bind': 2,
// 禁止case语句落空
'no-fallthrough': 2,
// 禁止数字字面量中使用前导和末尾小数点
'no-floating-decimal': 2,
// 禁用__iterator__属性
'no-iterator': 2,
// 禁用标签语句
'no-labels': [
2, {
'allowLoop': false,
'allowSwitch': false
}
],
// 禁用不必要嵌套块
'no-lone-blocks': 2,
// 禁止使用多个空格
'no-multi-spaces': 2,
// 禁止使用多行字符串
'no-multi-str': 2,
// 禁止对String,Number 和 Boolean 使用new操作符
'no-new-wrappers': 2,
// 禁用八进制字面量
'no-octal': 2,
// 禁止在字符串中使用八进制转义序列
'no-octal-escape': 2,
// 禁止使用__proto__属性
'no-proto': 2,
// 禁止多次声明同一变量
'no-redeclare': 2,
// 禁止在return语句中使用赋值语句
'no-return-assign': [2, 'except-parens'],
// 禁止自我赋值
'no-self-assign': 2,
// 禁止自我比较
'no-self-compare': 2,
// 禁用逗号操作符
'no-sequences': 2,
// 禁止抛出异常字面量
'no-throw-literal': 2,
// 禁止不必要的.call()和.apply()
'no-useless-call': 2,
// 禁止不必要的转义字符
'no-useless-escape': 2,
// 禁用with语句
'no-with': 2,
// 要求IIFE使用括号括起来
'wrap-iife': 2,
// 要求或禁止Yoda条件。 if("red" === color) { //字面量在前,变量在后 }
'yoda': [2, 'never'],
// 比较绝不能是Yoda条件(需要变量在前,字面量在后)
// *
// * 【==== ECMAScript 6 ====】
// * 这些规则只与ES6有关,即通常所说的ES2015。
// *
// 强制箭头函数前后使用一致的空格
'arrow-spacing': [
2,
{
'before': true,
'after': true
}
],
// 要求在构造函数中有super()调用
'constructor-super': 2,
// 强制generator函数中*号周围使用一致的空格
'generator-star-spacing': [
2,
{
'before': true,
'after': true
}
],
// 禁止修改类声明的变量
'no-class-assign': 2,
// 禁止修改const声明的变量
'no-const-assign': 2,
// 禁止类成员中出现重复的名称
'no-dupe-class-members': 2,
// 禁止 Symbolnew 操作符和 new 一起使用
'no-new-symbol': 2,
// 禁止在构造函数中,在调用super()之前使用 this 或 super
'no-this-before-super': 2,
// 禁止在对象中使用不必要的计算属性
'no-useless-computed-key': 2,
// 禁止不必要的构造函数
'no-useless-constructor': 2,
// 禁止模板字符串中嵌入表达式周围空格的使用
'template-curly-spacing': [2, 'never'],
// 强制yield*表达式中的*周围使用空格
'yield-star-spacing': [2, 'both'],
// 要求使用const声明那些声明后不再被修改的变量
'prefer-const': 2,
// *
// * 【==== Stylistic Issues ====】
// * 这些规则是关于代码风格的。
// *
// 获取当前执行环境的上下文时,强制使用一致的命名(此处强制使用 'that')。
'consistent-this': [2, 'that'],
// 禁止或强制在代码块中开括号前和闭括号后有空格 { return 11 }
'block-spacing': [2, 'always'],
// 强制在代码块中使用一致的大括号风格
'brace-style': [2, '1tbs', { 'allowSingleLine': true }],
// 强制使用驼峰拼写法命名规定
'camelcase': [0, { 'properties': 'always' }],
// 要求或禁止末尾逗号
'comma-dangle': [2, 'never'],
// 强制在逗号前后使用一致的空格
'comma-spacing': [2, { 'before': false, 'after': true }],
// 强制在逗号前后使用一致的空格
'comma-style': [2, 'last'],
// 要求或禁止文件末尾存在空行
'eol-last': 2,
// 强制使用一致的缩进
'indent': [2, 2, { 'SwitchCase': 1 }],
// 强制在JSX属性中一致地使用双引号或单引号
'jsx-quotes': [2, 'prefer-single'],
// 要求构造函数首字母大写
'new-cap': [2, { 'newIsCap': true, 'capIsNew': false }],
// 要求构造无参构造函数时有圆括号
'new-parens': 2,
// 禁用Array构造函数
'no-array-constructor': 2,
// 禁止空格和tab的混合缩进
'no-mixed-spaces-and-tabs': 2,
// 禁止出现多行空行
'no-multiple-empty-lines': [2, {
// 最大连续空行数
max: 2
}],
// 禁止在函数标识符和其调用之间有空格
'func-call-spacing': 2,
// 禁止行尾空格
'no-trailing-spaces': 2,
// 禁止可以在有更简单的可替代的表达式时使用三元操作符
'no-unneeded-ternary': [2, {
// 允许表达式作为默认的赋值模式
'defaultAssignment': true
}],
// 禁止属性前有空白
'no-whitespace-before-property': 2,
// 强制函数中的变量要么一起声明要么分开声明
'one-var': [2, { 'initialized': 'never' }],
// 强制操作符使用一致的换行符
'operator-linebreak': [
2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}
],
// 要求或禁止块内填充
'padded-blocks': [2, 'never'],
// 强烈使用一致的反勾号``、双引号""或单引号''
'quotes': [0, 'single', {
// 允许0符串使用单引号或者双引号,只要字符串中包含了一个其他引号,否则需要转义
'avoidEscape': true,
// 允许字符串使用反勾号
'allowTemplateLiterals': true
}],
// 禁止使用分号代替ASI(自动分号插入)
'semi': [0, 'never'],
// 强制分号之前和之后使用一致的空格
'semi-spacing': [2, { 'before': false, 'after': true }],
// 强制在块之前使用一致的空格
'space-before-blocks': [2, 'always'],
// 强制在圆括号内使用一致的空格
'space-in-parens': [2, 'never'],
// 要求操作符周围有空格
'space-infix-ops': 2,
// 强制在一元操作符前后使用一致的空格
'space-unary-ops': [2, { 'words': true, 'nonwords': false }],
// 强制在注释// 或/*使用一致的空格
'spaced-comment': [1, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
// 强制在大括号中使用一致的空格
'object-curly-spacing': [2, 'always', {
'objectsInObjects': false
}],
// 禁止或强制在括号内使用空格
'array-bracket-spacing': [2, 'never'],
// 强制要求在对象字面量的属性中键和值之间使用一致的间距
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
// *
// * 【==== Node.js and CommonJS ====】
// * 这些规则是关于Node.js 或 在浏览器中使用CommonJS的。
// *
// 要求回调函数中有容错处理
'handle-callback-err': [2, '^(err|error)$'],
// 禁止调用 require 时使用new操作符
'no-new-require': 2,
// 禁止对__dirname和__filename进行字符串连接
'no-path-concat': 1,
// 强制在function的左括号之前使用一致的空格
'space-before-function-paren': [2, 'never'],
// *
// * 【==== Possible Errors ====】
// * 这些规则与JavaScript代码中可能的错误或逻辑错误有关。
// *
// 禁止条件表达式中出现赋值操作符
'no-cond-assign': 2,
// 禁止在正则表达式中使用控制字符
'no-control-regex': 0,
// 禁止在正则表达式中使用空字符集
'no-empty-character-class': 2,
// 禁止不必要的布尔转换
'no-extra-boolean-cast': 2,
// 禁止不必要的括号
'no-extra-parens': [2, 'functions'],
// 禁止对function声明重新赋值
'no-func-assign': 2,
// 禁止在嵌套块中出现变量声明或function声明
'no-inner-declarations': [2, 'functions'],
// 禁止RegExp构造函数中存在无效的正则表达式字符串
'no-invalid-regexp': 2,
// 禁止在字符串和注释之外不规则的空白
'no-irregular-whitespace': 2,
// 禁止把全局对象作为函数调用
'no-obj-calls': 2,
// 禁止正则表达式字面量中出现多个空格
'no-regex-spaces': 2,
// 禁用稀疏数组
'no-sparse-arrays': 2,
// *
// * 【==== Variables ====】
// * 这些规则与变量声明有关。
// *
// 禁止删除变量
'no-delete-var': 2,
// 不允许标签与变量同名
'no-label-var': 2,
// 禁止将标识符定义为受限的名字
'no-shadow-restricted-names': 2,
// 禁止未声明的变量,除非它们在/*global */注释中被提到
'no-undef': 2,
// 禁止将变量初始化为undefined
'no-undef-init': 2,
// 禁止出现未使用的变量
'no-unused-vars': [2, { 'var': 'all', 'args': 'none' }],
// *
// * 【==== 配置定义在插件中的规则 ====】
// * 格式: 插件名/规则ID
// *
//
'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }]
}
}
当我们想对某个文件进行检查时,只需要在当前目录打开命令行窗口,输入以下命令,就可以对某个文件或某个目录下的所有文件进行检查。如果执行完命令后什么也没有输出,就说明我们的代码已经通过ESLint检查,可以放心提交代码。
但是如果出现以下提示或报错,就说明我们的代码没有通过ESLint的检查,需要按照提示进行修改。
eslint src/main.js // 检查src目录下的main.js
main.js内容
let name = "zhagnsan";
console.log(name);
第一个错误是定义的变量没有使用。
第二个错误是不能使用console.
这两个我们在 .eslintrc.js 都有定义。
// 禁止出现未使用的变量
'no-unused-vars': 2,
'no-console':'error',
1.3 如何跳过检查
在实际的使用场景中,我们可能存在某些文件或某行代码,希望能够跳过ESLint的检查,下面主要介绍了几种跳过ESLint检查的方式:
(1)使用注释跳过ESLint的检查
- 块注释: 使用如下方式,可以在整个文件或者代码块禁用所有规则或者禁用特定规则:
/* eslint-disable */
alert("该注释放在文件顶部,整个文件都不会出现 lint 警告");
/* eslint-disable */
alert("块注释 - 禁用所有规则");
/* eslint-enable */
/* eslint-disable no-console, no-alert */
alert("块注释 - 禁用 no-console, no-alert 特定规则");
/* eslint-enable no-console, no-alert */
- 行注释: 使用如下方式可以在某一特定的行上禁用所有规则或者禁用特定规则:
alert("禁用该行所有规则"); // eslint-disable-line
// eslint-disable-next-line
alert("禁用该行所有规则");
/* eslint-disable-next-line no-alert */
alert("禁用该行 no-alert 特定规则");
alert(
"禁用该行 no-alert, quotes, semi 特定规则"
); /* eslint-disable-line no-alert, quotes, semi*/
(2)创建.eslintignore文件忽略某些文件的检查
在项目根目录创建.eslintignore文件,在该文件中添加需要跳过检查的文件名称,ESLint将会跳过这些文件的检查。如下所示,ESLint将会跳过dist、
node_modules和package.json文件的检查。
dist
node_modules
package.json
1.4 Eslint 配置详解
eslint
默认没有规则,需要手动配置 .eslintrc.*
中添加规则。
// .eslintrc.js
module.exports = {}
1.root
默认情况下,ESLint 会在所有父级目录里寻找配置文件,一直到根目录。如果你想要你所有项目都遵循一个特定的约定时,这将会很有用,但有时候会导致意想不
到的结果。为了将 ESLint 限制到一个特定的项目,在你项目根目录下的 package.json 文件或者 .eslintrc.* 文件里的 eslint Config 字段下设置 “root”: true。
ESLint 一旦发现配置文件中有 “root”: true,它就会停止在父级目录中寻找。
module.exports = {
root: true,
}
2.项目级与目录级的配置
一般来说,对于一个项目,如果在多层目录中,需要使用不同的 ESLint 规则时,如下方的例子: src/eslintrc.js 目录级的配置,对于 src 目录下的内容来说,
它的权限会高于根目录下的项目级配置,但是 ESLint 也会合并根目录下的配置。如果我们在 src/eslintrc.js 添加 root: true,那么 ESLint 就会认为 src 目录
为根目录,不再向上查找配置。
project
--src
----eslintrc.js
--eslintrc.js
3.parser
与 parserOptions
解析器(parser)
配置解析项目的规则。
/*
默认: esprima
@typescript-eslint/parser - ts 解析器
@babel/eslint-parser - babel 解析器
*/
module.exports = {
parser: '@typescript-eslint/parser',
}
解析器选项(parserOptions)
搭配
parser
,指定你想要支持的 JavaScript 语言选项。
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 6, // 默认设置为 3,5(默认), 你可以使用 6、7、8、9 或 10 来指定你想要使用的 ECMAScript 版本。你也可以用使用年份命名的版本号指定为 2015(同 6),2016(同 7),或 2017(同 8)或 2018(同 9)或 2019 (same as 10)
sourceType: "module", // 设置为 "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)
ecmaFeatures: { // 配置你想使用的额外的语言特性
globalReturn: false, // 允许在全局作用域下使用 return 语句
jsx: true, // 启用 jsx
impliedStrict: false, // 启用全局 strict mode (如果 ecmaVersion 是 5 或更高)
experimentalObjectRestSpread: false // 启用实验性的 object rest/spread properties 支持
}
},
}
设置环境 (env)
设置您的脚本在哪种环境中运行。每个环境都会带来一组特定的预定义全局变量。可以简单理解为批量设置全局变量,这些环境不是互斥的,因此您一次可以定义多个环境。
module.exports = {
env: {
// 常用
browser: true, // 浏览器全局变量
node: true, // Node.js 全局变量和 Node.js 作用域
commonjs: true, // CommonJS 全局变量和 CommonJS 作用域 (启用此环境用于使用 Browserify/WebPack 的 browser-only 代码)
shared-node-browser: true, // Node.js 和 Browser 通用的全局变量
es6: true, // 启用除 modules 以外的所有 ECMAScript 6 特性 (这会自动将 `ecmaVersion` 解析器选项设置为 6)
es2017: true, // 添加所有 ECMAScript 2017 的全局变量并且自动设置 `ecmaVersion` 解析器选项设置为 8
es2020: true, // 添加所有 ECMAScript 2020 的全局变量并且自动设置 `ecmaVersion` 解析器选项设置为 11
es2021: true, // 添加所有 ECMAScript 2021 的全局变量并且自动设置 `ecmaVersion` 解析器选项设置为 12
worker: true, // web workers 全局变量
// 不常用
amd: true, // 根据 amd 规范定义 `require()` 和 `define()` 作为全局变量
mocha: true, // 添加所有 Mocha 测试全局变量
jasmine: true, // 为版本 1.3 和 2.0 添加所有 Jasmine 测试全局变量
jest: true, // Jest 全局变量
phantomjs: true, // PhantomJS 全局变量
protractor: true, // Protractor 全局变量
qunit: true, // QUnit 全局变量
jquery: true, // jQuery 全局变量
greasemonkey: true, // GreaseMonkey 全局变量
prototypejs: true, // Prototype.js 全局变量
shelljs: true, // ShellJS 全局变量
meteor: true, // Meteor 全局变量
mongo: true, // MongoDB 全局变量
applescript: true, // AppleScript 全局变量
nashorn: true, // Java 8 Nashorn 全局变量
serviceworker: true, // Service Worker 全局变量
atomtest: true, // Atom 测试助手全局变量
embertest: true, // Ember 测试助手全局变量
webextensions: true, // WebExtensions 全局变量
}
}
全局变量(globals)
当访问当前源文件内未定义的变量时,no-undef 规则将发出警告。如果你想在一个源文件里使用全局变量,推荐你在 ESLint 中定义这些全局变量,这样 ESLint 就不会发出警告了。
readonly
: 可读不可写writable
: 可读可写
module.exports = {
globals: {
// 自己定义的全局变量
logger: "readonly",
},
};
规则(rules)
如果不配置规则,则
eslint
也不会生效。
off
或0
- 关闭规则;warn
或1
- 开启规则,使用警告级别的错误:warn (不会导致程序退出);error
或2
- 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)。
module.exports = {
rules: {
// 需要添加封号
"semi": 2,
// 保存代码时缩进2个空格
"indent": ['error', 2],
},
};
插件(plugins)& 继承(extends)
这两者要放在一起来看,除了在当前项目自己配置一系列的规则,还可以使用社区比较成熟的方法,这样就不用在自己的项目中去配置一堆内容,同时还可以根据团队的习惯,对某些规则进行改写。
1.plugins
plugin 插件主要是为 eslint 新增一些检查规则,举个例子:eslint-plugin-react 就会对 react 项目做了一些定制的eslint 规则, eslint-plugin-react-hooks 就是针对 react/hooks 的定制的一系列规则。
简单的说,此时只是让 eslint 能够识别这些规则,但是这些规则还没有加到项目中,此时就需要我们就可以手动的在 rules 添加要使用的规则,如:
//.eslintrc.js
module.exports = {
plugins: [
'eslint-plugin-react'
],
rules: {
'eslint-plugin-react/jsx-boolean-value': 2
}
}
2.extends:
其实没个项目的配置,基本上都是大同小异的,没必要没启动一个新项目,就重新配置一份。 estends 的作用,就是继承社区整理好的配置规则,如: eslint-plugin-react 为了方便其他人使用,它默认实现了两种最佳实践 all 以及 recommened,这样我们就可以直接使用它配置好的规则。
//.eslintrc.js
module.export = {
plugins: [
'eslint-plugin-react'
],
extends: [
'eslint-plugin-react/recommended'
],
rules: {
// 也可以在当前项目中修改继承的一些配置项
'eslint-plugin-react/jsx-boolean-value': 2
}
}
1.5 安装Vscode Eslint 插件
2. Prettier
2.1 什么是Prettier
Prettier是一个代码格式化工具,可以格式化代码,但不具备代码检查功能,它可以通过解析代码并使用自己的规则重新打印它,并考虑最大行长来强制一致的样式,并在必要时包装代码,如今,它已成为解决所有代码格式问题的优选方案,支持多种语言,可以将ESLint和Prettier结合使用,提高代码质量。
2.2 为什么要用Prettier
上面Prettier的定义一看,是不是觉得和ESLint差不了多少?那么,有了ESLint,为什么还要用Prettier呢?
其实呀,ESLint虽然是一个代码检测工具,可以检测代码质量问题并给出提示,但是提供的格式化功能有限,在代码风格上面做的不是很好,并且也只能格式化
JS,不支持CSS,HTML等语言。而在代码风格上面,Prettier具有更加强大的功能,并且能够支持包括 JavaScript、TypeScript、各种 CSS、Vue 和 Markdown 等前端绝大部分的语言和文件格式。因此,我们一般会将ESLint和Prettier一起结合起来使用,用ESLint进行代码校验,用Prettier统一代码风格。
2.3 安装Prettier
(1)脚手架自动安装
如果是采用脚手架如Vue-Cli创建项目,在创建项目时就可以选择安装Prettier,安装完成后,会自动在项目根目录生成一个.eslintrc.js文件,里面的默认配置中已经包含了prettier的相关扩展。
(2)手动安装
如果已经存在一个项目,并且想要安装Prettier,可以通过npm的方式进行安装。
npm install prettier --save-dev -g
2.4 安装eslint-config-prettier
安装好Prettier之后,我们还需要安装eslint-config-prettier,这是因为eslint和prettier里面的一些规则可能会存在冲突,这个时候我们就需要安装eslint-config-prettier,并且关掉所有和prettier冲突的eslint配置。
通过npm安装eslint-config-prettier。
npm install eslint-config-prettier@6.0.0 --save-dev
安装好eslint-config-prettier之后,接下来我们就需要关掉所有和prettier冲突的eslint配置。这里只需要在.eslintrc.js的extends中将prettier设置为最后一个
extends 即可,相当于用 prettier 的规则,覆盖掉 eslint:recommended 的部分规则。
extends: ["eslint:recommended", "prettier"],
2.5 安装eslint-plugin-prettier
接下来,我们还需要安装eslint-plugin-prettier,eslint-plugin-prettier的作用时是将prettier 的能力集成到eslint中,使得我们在运行eslint检查我们的代码时,
能够按照prettier的规则检查代码规范性,并进行修复。
使用npm安装eslint-plugin-prettier。
npm install eslint-plugin-prettier
安装eslint-plugin-prettier后,需要对.eslintrc.js进行配置。
{
"rules":{
"prettier/prettier":"error"
},
"plugins": ["prettier"],
}
除了上面这种配置之外,我们也可以直接将上面两个步骤结合在一起,使用下面的配置就可以。
{
"extends": [
"eslint:recommended",
"plugin:prettier/recommended"
]
}
2.6 配置文件
Prettier和ESLint一样,支持我们通过配置文件的方式,实现自定义配置,覆盖原来的Prettier配置。
我们可以在根目录创建.prettierrc文件,.prettierrc文件支持写入YAML,JSON的配置格式,并且支持.yaml,.yml,.json和.js后缀。在平时的开发中,我们团队一般会选择创建.prettierrc.js文件,实现对prettier配置的覆盖。
在.prettierrc.js文件中,我们可以对prettier的默认配置进行修改。
2.7 忽略某些文件的格式化
Prettier和ESLint一样,也支持忽略对某些文件的格式化。如果我们存在一些不需要格式化的文件,可以在根目录创建.prettierignore文件,并且将不需要格式化的文件或目录名称写在该文件中。
dist
node_modules
.eslintignore
.prettierignore
2.8 VScode 安装Prettier插件
3. 配置settings.json文件
安装好插件之后,我们还需要设置VSCode的settings.json文件,实现保存代码时就自动执行ESLint检查。VSCode的setting.json设置分为工作区和用户两个级
别,其中用户区会对所有项目生效,而工作区的设置只会对当前项目生效。
(1)用户区settings.json配置
点击VSCode左下角的设置按钮,选择Settings,选择以文本编辑形式打开settings.json,并且在setting.json中加入以下代码。配置完成之后,当我们保存某个文件时,就可以自动对当前文件进行ESLint检查,并且自动对一些错误进行修复啦。
第一步: 打开设置
第二步: 可以在可视化界面设置
第三步: 可以在文本编辑器打开
{
// #每次保存的时候自动格式化
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
(2)工作区settings.json配置
除了配置用户区的settings.json之外,我们也可以配置工作区的settings.json,工作区的配置只会对当前项目生效。
首先,我们需要在项目根目录创建.vscode目录,并且在该目录下创建settings.json文件。
接着,在settings.json中加入以下代码,配置完成后,当我们保存该项目中某个文件时,也会自动对该文件进行ESLint检查,并且自动修复一些问题。
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
},
"eslint.validate": ["typescript", "javascript", "vue"]
}
4. 配置 EditorConfig文件
上面在安装VSCode插件时,我们提到了要安装EditorConfig for VS Code插件,那这个插件需要怎么起作用呢?
首先,我们需要在项目根目录创建.editorconfig文件。创建完成之后,这个文件里面定义的代码规范规则会高于编译器默认的代码规范规则。
接着,我们只需要在.editorconfig文件中加入我们想要覆盖的编译器的配置,比如下面的配置定义了缩进为2个空格,那么就算编译器默认的是4个空格的缩进,最后也会按照我们的.editorconfig配置,按照2个空格进行缩进。
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = auto
5. Stylelint
Stylelint是一个强大的,现代的代码检查工具,与ESLint类似,Stylelint能够通过定义一系列的编码风格规则帮助我们避免在样式表中出现错误。
目前在开源社区上,关于CSS Lint的解决方案主要包括了csslint、SCSS-Lint和Stylelint等几种。而由于Stylelint在技术架构上基于AST 的方式扩展CSS,除原生 CSS 语法,其也支持 SCSS、Less 这类预处理器,并且也有非常多的第三方插件,因此我们团队选择了Stylelint作为CSS Lint工具。
官方文档:https://stylelint.io/
5.1 安装 Stylelint
5.1.1 安装Stylelint
可以选采用npm安装Stylelint。其中,stylelint-config-standard是Stylelint的标准配置。如果想使用airbn
或prettier的规范,也可以将stylelint-config-standard改为stylelint-config-airbnb或stylelint-config-prettier。
npm install stylelint stylelint-config-standard --save-dev -g
5.1.2 安装适配预处理语法的插件
如果我们项目中采用了如sass或less等css预处理器,那么可以安装适配预处理语法的插件。以less为例,需要安装stylelint-less插件。
npm install stylelint-less --save-dev
5.1.3 安装CSS属性排序插件
我们也可以选择安装stylelint-order插件。该插件能够强制我们按照某个顺序编写css,比如先写定位,再写盒模型,再写内容区样式,最后写CSS3相关属性,这 样可以更好的保证我们代码的可读性。
npm install stylelint-order --save-dev
5.2 Stylelint配置
5.2.1 Stylelint配置方式
安装好Stylelint之后,就需要对Stylelint进行配置。Stylelint的配置方式包括了以下几种:
-
在package.json中添加stylelint属性并添加规则
-
在.stylelintrc文件中指定,.stylelintrc文件支持添加一个文件扩展名来区分 JSON,YAML 或 JS 格式,如创建.stylelintrc.json、.stylelintrc.yaml、.stylelintrc.yml或.stylelintrc.js文件
-
在stylelint.config.js文件中指定,该文件将会exports一个配置对象
在这里,我们选择了在项目根目录创建.stylelintrc.js来配置Stylelint。
在.stylelintrc.js文件中,我们可以指定要配置的内容,下面给出了一个配置文件的例子。
其中,该配置文件采用了stylelint-config-standard标准配置,并且添加了stylelint-order插件用于CSS属性
排序,在rules中,可以指定声明块内属性的顺序,也可以自定义CSS检查规则。比如定义了color-hex-
case为lower,表示CSS文件的颜色值都必须小写,否则会报错。
module.exports = {
plugins: ['stylelint-order'],
extends: ['stylelint-config-standard'],
rules: {
// 指定声明块内属性的字母顺序
'order/properties-order': [
'position',
'top',
'right',
'bottom',
'left',
'z-index',
'display',
'float',
'width',
'height',
'max-width',
'max-height',
'min-width',
'min-height',
'padding',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'margin',
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'margin-collapse',
'margin-top-collapse',
'margin-right-collapse',
'margin-bottom-collapse',
'margin-left-collapse',
'overflow',
'overflow-x',
'overflow-y',
'clip',
'clear',
'font',
'font-family',
'font-size',
'font-smoothing',
'osx-font-smoothing',
'font-style',
'font-weight',
'hyphens',
'src',
'line-height',
'letter-spacing',
'word-spacing',
'color',
'text-align',
'text-decoration',
'text-indent',
'text-overflow',
'text-rendering',
'text-size-adjust',
'text-shadow',
'text-transform',
'word-break',
'word-wrap',
'white-space',
'vertical-align',
'list-style',
'list-style-type',
'list-style-position',
'list-style-image',
'pointer-events',
'cursor',
'background',
'background-attachment',
'background-color',
'background-image',
'background-position',
'background-repeat',
'background-size',
'border',
'border-collapse',
'border-top',
'border-right',
'border-bottom',
'border-left',
'border-color',
'border-image',
'border-top-color',
'border-right-color',
'border-bottom-color',
'border-left-color',
'border-spacing',
'border-style',
'border-top-style',
'border-right-style',
'border-bottom-style',
'border-left-style',
'border-width',
'border-top-width',
'border-right-width',
'border-bottom-width',
'border-left-width',
'border-radius',
'border-top-right-radius',
'border-bottom-right-radius',
'border-bottom-left-radius',
'border-top-left-radius',
'border-radius-topright',
'border-radius-bottomright',
'border-radius-bottomleft',
'border-radius-topleft',
'content',
'quotes',
'outline',
'outline-offset',
'opacity',
'filter',
'visibility',
'size',
'zoom',
'transform',
'box-align',
'box-flex',
'box-orient',
'box-pack',
'box-shadow',
'box-sizing',
'table-layout',
'animation',
'animation-delay',
'animation-duration',
'animation-iteration-count',
'animation-name',
'animation-play-state',
'animation-timing-function',
'animation-fill-mode',
'transition',
'transition-delay',
'transition-duration',
'transition-property',
'transition-timing-function',
'background-clip',
'backface-visibility',
'resize',
'appearance',
'user-select',
'interpolation-mode',
'direction',
'marks',
'page',
'set-link-source',
'unicode-bidi',
'speak',
],
// 颜色值要小写
'color-hex-case': 'lower','number-leading-zero': 'always',
},
};
5.2.2 Stylelint配置项
在上面的配置文件中,我们主要定义了一个配置对象,接下来将对常用的配置项进行介绍。
(1)plugins
plugins定义了一个数组,该配置项允许我们使用第三方插件,在该数组中,需要包含“定位器”标识出你要使用的插件,一个“定位器”可以是一个 npm 模块名,一
个绝对路径,或一个相对于要调用的配置文件的路径。
一旦声明了插件,在rules中需要为插件的规则添加选项,就像其他标准的规则一样。你需要查看插件的文档去了解规则的名称。
{
"plugins": [
“stylelint-order",
"../special-rule.js"
],
"rules": {
"order/properties-order": [],
"plugin/special-rule": "everything"
}
}
(2)extends
extends定义了一个数组,该配置项允许我们extend一个已存在的配置文件(无论是你自己的还是第三方的配置)。当一个配置继承了里一个配置,它将会添加自己 的属性并覆盖原有的属性。比如下面的代码,我们就extend了Stylelint的标准配置。
{
"extends": "stylelint-config-standard",
"rules": {
"indentation": "tab",
"number-leading-zero": null
}
}
如果extends中包含多个配置项,那么数组中的每一项都优先于前一项,也就是说第二项会覆盖第一项,第三项会覆盖第一项和第二项,最后一项将覆盖其它所有项。
{
"extends": [
"stylelint-config-standard",
"./myExtendableConfig"
],
"rules": {
"indentation": "tab"
}
}
3)rules
rules定义了一个对象,属性名为规则名称,属性值为规则取值,它告诉Stylelint该检查什么,该怎么报错,所有的规则都是默认关闭的。我们可以通过该选项开
启相应规则,进行相应的检测。所有规则必须显式的进行配置,因为没有默认值。
规则名称主要由两个部分组成,第一部分描述该规则应用于什么东西,第二部分表示该规则检查了什么。
"number-leading-zero"
// ↑ ↑
// the thing what the rule is checking
当规则名称应用于整个样式表时只包含第二个部分:
"no-eol-whitespace"
"indentation"
// ↑
// what the rules are checking
当规则名称不同时,规则取值也不同。我们可以将某个规则设置为null禁用该规则。
{
"rules": {
"at-rule-blacklist": string|[],
"at-rule-empty-line-before": "always"|"never",
"at-rule-name-case": "lower"|"upper",
"block-no-empty": null,
...
}
}
除了规则本身的取值之外,Stylelint还支持一些自定义配置,允许给规则传递一个数组,数组第一项是规则取值,第二项是自定义配置。
"selector-pseudo-class-no-unknown": [true, {
"ignorePseudoClasses": ["global"]
}]
通过自定义配置,我们可以指定:
- severity:错误级别,取值为”warning"或"error",默认情况下,所有规则的错误级别都为"error",通过defatuleServerity,可以修改错误级别的默认值
// error-level severity examples
{ "indentation": 2 }
{ "indentation": [2] }
// warning-level severity examples
{ "indentation": [2, { "severity": "warning" } ] }
{ "indentation": [2, {
"except": ["value"],
"severity": "warning"
}]
}
- message:当一个规则被触发时,如果你想实现一个自定义的消息,可以给规则的传递"message“作为第二选项,如果提供,将替代提供的任何标准的消息。例如,以下规则配置会使用一些自定义的消息:
"color-hex-case": [ "lower", {
"message": "Lowercase letters are easier to distinguish from numbers"
} ],
"indentation": [ 2, {
"ignore": ["block"],
"message": "Please use 2 spaces for indentation. Tabs make The Architect grumpy.",
"severity": "warning"
} ]
}
(4)processors
Processors是Stylelint的钩子函数,只能用在命令行和Node API,不适用于PostCSS插件。Processors可以使Stylelint检测非样式表文件中的CSS。例如,可以检测HTML内中
使用Processors的话,需要在配置中添加一个”processors“数组,包含“定位器”标识出你要使用的 processors。同上面的extends,一个“定位器”可以是一个 npm 模块名,一个绝对路径,或一个相对于要调用的配置文件的路径。
{
"processors": ["stylelint-html-processor"],
"rules": {..}
}
如果你的processor有选项,把它们放到一个数组里,第一项是“定位器”,第二项是选项对象。
{
"processors": [
"stylelint-html-processor",
[ "some-other-processor", { "optionOne": true, "optionTwo": false } ]
],
"rules": {..}
}
5.2.3 忽略特定文件的检查
在实际的使用场景中,我们可能存在某些文件或某行代码,希望能够跳过Stylelint的检查或禁用某些规则,下面主要介绍了几种跳过Stylelint检查的方式:
(1)使用注释禁用规则
使用/* stylelint-disable */,可以在代码片段禁用所有规则或禁用特定规则。
/* stylelint-disable */
a {}
/* stylelint-enable */
/* stylelint-disable selector-no-id, declaration-no-important */
#id {
color: pink !important;
}
/* stylelint-enable */
使用/* stylelint-disable-line */,可以在个别行上禁用规则。
#id { /* stylelint-disable-line */
color: pink !important; /* stylelint-disable-line declaration-no-important */
}
使用/* stylelint-disable-next-line */,可以在下一行禁用规则。
#id {
/* stylelint-disable-next-line declaration-no-important */
color: pink !important;
}
(2)创建.stylelintignore忽略某些文件的检查
在项目根目录创建.stylelintignore文件。
在.stylelintignore中写入需要跳过Stylelint检查的文件名称,比如下面的代码将会忽略dist,node_modules和package.json文件的Stylelint检查。
dist
node_modules
package.json
5.3 执行Stylelint检查
安装配置好Stylelint之后,我们就可以运行Stylelint命令,对指定的文件进行CSS语法检查,其中,–fix表示自动修复Stylelint错误。
运行Stylelint命令后,如果什么也没有输出,就说明我们的文件已经通过Stylelint的检查。如果输出报错信息,就说明没有通过Stylelint的检查,需要根据错误信
息对代码进行修复。
// 对某个文件进行检查
stylelint "src/App.vue" --fix
// 对指定后缀名的文件进行检查
stylelint "src/*.{html,vue,css,saas,scss,less}" --fix
除了直接在命令行运行Stylelint命令方式之外,我们也可以在package.json中自定义Stylelint的启动命令。如下面代码所示,配置好package.json之后,我们通过运行npm run lint:css就能够对指定文件进行Stylelint检查。
{
"scripts": {
"serve": "cross-env NODE_ENV=development vue-cli-service serve --mode dev",
"serve:test": "cross-env NODE_ENV=test vue-cli-service serve --mode test",
"serve:prod": "cross-env NODE_ENV=production vue-cli-service serve --mode prod",
"build:dev": "cross-env NODE_ENV=production vue-cli-service build --mode dev",
"build:test": "cross-env NODE_ENV=production vue-cli-service build --mode test",
"build:prod": "cross-env NODE_ENV=production vue-cli-service build --mode prod",
"lint": "vue-cli-service lint",
"lint:css": "stylelint **/*.{vue,htm,html,css,sss,less,scss,sass} --fix"
},
}
5.4 安装Stylelint插件
为了让我们在编写代码的过程中,能够实时提示Stylelint错误,并且在保存文件时,能够自动对当前文件进行Stylelint检查和修复,我们可以在VSCode中安装 Stylelint插件。
在VSCode的EXTENSIONS中找到Stylelint插件,点击install就可以安装Stylelint插件。
在 vscode 中安装插件:stylelint-plus
当然也可以选择普通的 stylelint 插件,不过 plus 版本有保存即 fix 的功能
5.5 配置settings.json文件
安装好Stylelint插件之后,我们还需要配置VSCode的settings.json文件,让我们的代码在保存时,就能够按照规范对CSS样式进行检查及自动fix。VSCode的settings.json设置分为工作区和用户区两个级别。其中,用户区的设置会对所有项目生效,工作区的设置只能对当前项目生效。
(1)用户区settings.json配置
点击VSCode左下角的设置按钮,选择Settings,并且选择以文本编辑的方式打开settings.json,在settings.json中加入以下代码。
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {"source.fixAll.stylelint": true // 保存时是否自动 stylelint 修复
},
}
(2)工作区settings.json配置
在项目根目录创建.vscode目录,并且在该目录下创建settings.json文件。
在settings.json中加入以下代码。
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": true // 保存时是否自动 stylelint 修复
}
}
配置好用户区或工作区的settings.json后,当我们修改了某个文件的CSS代码,并且保存时,就会发现能够对当前文件自动进行stylelint检查和修复了。
6.Commitizen
6.1 提交规范
那么,什么样的提交说明才能符合规范的说明呢?不同的团队可以制定不同的规范,当然,我们也可以直接使用目前流行的规范,比如[Angular Git Commit
Guidelines。接下来将会对目前流行的Angular提交规范进行介绍。
6.1.1 提交格式
符合规范的Commit Message的提交格式如下,包含了页眉(header)、正文(body)和页脚(footer)三部分。其中,header是必须的,body和footer可以
忽略。
<type>(<scope>): <subject>
// 空一行
<body>
// 空一行
<footer>
6.1.2 页眉设置
页眉(header)通常只有一行,包括了提交类型(type)、作用域(scope)和主题(subject)。其中,type和subject是必须的,scope是可选的。
2.2.1 提交类型
提交类型(type)用于说明此次提交的类型,需要指定为下面其中一个:
2.2.2 作用域
作用域(scope)表示此次提交影响的范围。比如可以取值api,表明只影响了接口。
2.2.3 主题
主题(subject)描述是简短的一句话,简单说明此次提交的内容。
6.1.3 正文和页脚
正文(body)和页眉(footer)这两部分不是必须的。
如果是破坏性的变更,那就必须在提交的正文或脚注加以展示。一个破坏性变更必须包含大写的文本 BREAKING CHANGE,紧跟冒号和空格。脚注必须只包含 BREAKING CHANGE、外部链接、issue 引用和其它元数据信息$。例如修改了提交的流程,依赖了一些包,可以在正文写上:BREANKING CHANGE:需要重新npm install,使用npm run cm代替git commit。
下面给出了一个Commit Message例子,该例子中包含了header和body。
chore: 引入commitizen
BREANKING CHANGE:需要重新npm install,使用npm run cm代替git commit
当然,在平时的提交中,我们也可以只包含header,比如我们修改了登录页面的某个功能,那么可以这样写 Commit Message。
feat(登录):添加登录接口
6.2 什么是Commitizen
虽然有了规范,但是还是无法保证每个人都能够遵守相应的规范,因此就需要使用一些工具来保证大家都能够提交符合规范的Commit Message。常用的工具包
括了可视化工具和信息交互工具,其中Commitizen是常用的Commitizen工具,接下来将会先介绍Commitizen的使用方法。
Commitizen是一个撰写符合上面Commit Message标准的一款工具,可以帮助开发者提交符合规范的Commit Message。
6.2.1 安装Commitizen
可以使用npm安装Commitizen。其中,cz-conventional-changelog是本地适配器。
npm install commitizen cz-conventional-changelog --save-dev
6.2.2 配置Commitizen
安装好Commitizen之后,就需要配置Commitizen,我们需要在package.json中加入以下代码。其中,需要增加一个script,使得我们可以通过执行npm run cm 来代替git commit,而path为cz-conventional-changelog包相对于项目根目录的路径。
”script": { "cm: "git-cz"},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
配置完成之后,我们就可以通过执行npm run cm来代替git commit,接着只需要安装提示,完成header、body和footer的编写,就能够编写出符合规范的
Commit Message。
6.2.3 可视化提交工具
除了使用Commitizen信息交互工具来帮助我们规范Commit Message之外,我们也可以使用编译器自带的可视化提交工具。接下来,将会介绍VSCode可视化提
交工具的使用方法。
在VSCode的EXTENSIONS中找到 git-commit-plugin插件,点击install进
行安装。
安装完成之后,可以通过git add添加要提交的文件,接着,在Source Control点击show git commit template图标,开始编写Commit Message信息。
](https://img2020.cnblogs.com/blog/831247/202109/831247-20210929192640897-947164044.png)
接下来只需要按照指引进行Commit Message的编写。
当编写完成之后,可以得到符合规范的Commit Message,这个时候就可以放心将Commit Message及所修改的文件进行提交啦。
7.Husky
首先,先来介绍一下Husky的安装和相关配置。
7.1 什么是git hook
在介绍Husky之前,我们先来看什么是git hook,也就是常说的Git钩子。
和其它版本控制系统一样,Git能在特定的重要动作发生时触发自定义脚本。有两组这样的钩子:客户端的和服务器端的。 客户端钩子由诸如提交和合并这样的操 作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。 你可以随心所欲地运用这些钩子。
其中,客户端钩子我们可能用的比较多,客户端钩子通常包括了提交工作流钩子、电子邮件工作流钩子和其它钩子。这些钩子通常存储在项目的.git/hooks目录下,我们需要关注的主要是提交工作流钩子。提交工作流钩子主要包括了以下四种:
-
pre-commit:该钩子在键入提交信息前运行。 它用于检查即将提交的快照。如果该钩子以非零值退出,Git 将放弃此次提交,你可以利用该钩子,来检查代码风格是否一致。
-
prepare-commit-msg:该钩子在启动提交信息编辑器之前,默认信息被创建之后运行。 它允许你编辑提交者所看到的默认信息。
-
commit-msg:该钩子接收一个参数,此参数存有当前提交信息的临时文件的路径。 如果该钩子脚本以非零值退出,Git 将放弃提交,因此,可以用来在提交通过前验证项目状态或提交信息。
-
post-commit:该钩子一般用于通知之类的事情。
在上面的钩子中,我们需要关注
pre-commit
和commit-msg
钩子。
7.2 什么是husky
husky 是常见的git hook工具,使用 husky 可以挂载Git钩子,当我们本地进行git commit或git push等操作前,能够执行其它一些操作,比如进行ESLint检查,
如 果不通过,就不允许commit或push。
7.3 安装husky
安装husky,可以使用npm进行安装。
npm install husky --save-dev
7.4 配置husky
安装好husky之后,还需要对husky进行配置。不同版本的husky配置方法有些不同,这里主要对4.3.8版本的配置进行介绍。
首先,我们需要先安装配置好ESLint或Stylelint,并且在package.json中加入以下代码。
"husky": {
"hooks": {
"pre-commit": "eslint src/**/*.{js,jsx,ts,tsx}",
}
}
接着,当我们执行git commit时,就会触发pre-commit钩子,并且执行对应命令,这里将会指定目录下的文件进行ESLint检查,如果ESLint检查不通过,是无法进行commit的。
在安装并配置好husky之后,如果发现在commit时不能触发pre-commit,可以试着重新安装husky,并且重启VSCode。
7.5 只使用husky的问题
使用husky虽然能够帮助我们在commit或push前执行一些指令,但是如果只使用husky,仍然存在下面这些问题:
-
在某次提交时,我们只修改了某个文件,但是只使用husky会把所有的文件都运行一遍Lint检查,时间成本太高。此外,有些项目会在中途才加上husky,但是在commit时husky也会对其它未修改的历史代码进行检查,可能会一下子报了很多错误,这个时候我们更希望只对当前修改过的文件进行检查,而不是对项目中的代码都进行检查。
-
husky的钩子只能执行一个指令,但是有时候我们希望能够在git commit之前执行多个指令,比如执行ESLint、Stylelint或Commitlint等操作。
为了解决上面的问题,就需要结合Lint-staged一起使用。
8.Lint-staged
8.1 什么是Lint-staged
Lint-staged可以在git staged阶段的文件上执行Linters,简单说就是当我们运行ESlint或Stylelint命令时,可以通过设置指定只检查我们通过git add添加到暂存区的文件,可以避免我们每次检查都把整个项目的代码都检查一遍,从而提高效率。
其次,Lint-staged允许指定不同类型后缀文件执行不同指令的操作,并且可以按步骤再额外执行一些其它shell指令。
8.2 安装Lint-staged
安装Lint-staged,可以使用npm进行安装。
npm install lint-staged --save-dev -g
8.3 配置
安装好了Lint-staged之后,就需要配置Lint-staged。我们可以在package.json中加入以下代码,这里需要先安装配置好husky,ESLint和Stylelint。
"husky": {
"hooks": {
"pre-commit": "lint-staged",
}
},
"lint-staged": {
"*.vue": [
"eslint --fix",
"stylelint --fix",
"git add"
],
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"git add"
],
"*.{htm,html,css,sss,less,scss,sass}": [
"stylelint --fix",
"git add"
]
}
当我们执行git commit时,就会触发husky的pre-commit钩子,调用lint-staged命令。而lint-staged包含了对*.vue,.{js,jsx,ts,tsx},.{htm,html,css,sss,less,scss,sass}类型文件的操作。以*.vue为例,当匹配到后缀名为.vue的文件时,就会分别执行以下操作:
- 首先会执行eslint --fix命令,对.vue文件执行ESLint检查,并且自动修复一些JS格式问题
- 接着会执行stylelint --fix命令,对.vue文件的CSS执行Stylelint检查,并且自动修复一些CSS格式问题
- 最后,若前面的指令都执行通过,那么将通过git add命令将文件重新加入到本地的git commit中,如果没有执行通过,那么将不能commit
9. Commitlint
9.1 什么是Commitlint
在使用Git提交代码时,通常都需要填写提交说明,也就是Commit Message。在前面的文章中,已经介绍了如何使用Commitizen或可视化工具编写符合规范的Commit Message。然而有些同学可能还是会使用git commit方式提交一些不符合规范的Commit Message。为了禁止不符合规范的Commit Message的提交,我们就需要采用一些工具,只有当开发者编写了符合规范的Commit Message才能够进行commit。而Commitlint就是这样一种工具,通过结合husky一起使用,可以在开发者进行commit前就对Commit Message进行检查,只有符合规范,才能够进行commit。
9.2 安装Commitlint
使用npm安装Commitlint相关依赖包。
npm install @commitlint/cli @commitlint/config-conventional --save-dev
9.3 配置Commitlint
安装好Commitlint之后,就需要配置Commitlint,可以在根目录创建commitlint.config.js文件进行配置。
在comminlint.config.js中加入以下代码,表示使用config-conventional规范对提交说明进行检查。具体的规范配置可以查看:https://github.com/conventional-changelog/commitlint
module.exports = { extends: ['@commitlint/config-conventional'] };
接下来,需要在package.json中加入commit-msg钩子。
"husky": {
"hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
配置好了之后,当我们进行git commit时,就会触发commit-msg钩子,执行commintlint命令,并且读取commitlint.config.js中的规则对我们的提交说明进行检查,如果校验不通过,将不能提交。
10.Git检查工作流
在介绍完Husky,Commitlint和Lint-staged之后,接下来,我们就可以将这几个工具结合起来,打造完整的Git检查工作流。下面给出了一份示例代码,其中,该项目采用了Vue-cli进行构建,下面是该项目对应的package.json文件。
{
"name": "lan-xen-ui",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"prepare": "husky install",
"pretty-quick": "pretty-quick",
"cm": "git-cz"
},
"dependencies": {
"core-js": "^3.6.5",
"eslint-plugin-prettier": "^3.4.1",
"vue": "^2.6.11"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.15",
"@vue/cli-plugin-eslint": "~4.5.15",
"@vue/cli-service": "~4.5.15",
"babel-eslint": "^10.1.0",
"commitizen": "^4.2.4",
"cz-conventional-changelog": "^3.3.0",
"eslint": "^6.7.2",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-vue": "^8.7.1",
"prettier": "^2.6.2",
"stylelint": "^14.8.1",
"stylelint-config-standard": "^25.0.0",
"stylelint-less": "^1.0.5",
"stylelint-order": "^5.0.0",
"vue-template-compiler": "^2.6.11"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
],
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.vue": [
"eslint --fix",
"stylelint --fix",
"git add"
],
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"git add"
],
"*.{htm,html,css,sss,less,scss,sass}": [
"stylelint --fix",
"git add"
]
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
}
配置好package.json之后,当我们进行git commit提交时,首先将会触发pre-commit钩子,调用lint-staged命令,并且会对不同后缀的文件执行不同的检查。接着,还将会触发commit-msg钩子,调用commitlint对我们的提交说明进行检查。如果其中一个无法通过检查,将无法提交。