前言:
已经有很多文章讲解eslint等工具的配置流程,不再赘述,可参考文章很多。 最近在系统的将以前的项目统一lint规范,修改了一些lint告警和错误,整理下来,仅供参考。 使用过程中能感受到standard是一套并不非常严格的规则,还是相对友好的。
我的配置
module.exports = {
root: true,
parserOptions: {
parser: "@babel/eslint-parser",
sourceType: "module"
},
env: {
es6: true,
node: true,
browser: true
},
extends: [
"plugin:vue/recommended",
"standard"
],
plugins: [
"vue"
],
rules: {
}
}
stylelint为scss扩展+recess-order+standard,后面会提加2条单独rules的原因。
module.exports = {
extends: [
"stylelint-config-standard",
"stylelint-config-recess-order"
],
plugins: [
"stylelint-scss"
],
ignoreFiles: [
"**/*.{png,jpg,jpeg,gif,bmp,swf,svg,ico}",
"**/*.{ttf,woff,eot}",
"**/*.{yml,json}"
],
rules: {
"at-rule-no-unknown": null,
"scss/at-rule-no-unknown": true
}
}
注释
-
eslintrc文件中可配置规则on/off/0/1/2/error/warning等
-
eslintignore中可配置想忽略的文件夹/文件
-
如果1,2不满足需求,想在具体代码中配置忽略,如下:
- 忽略整个文件:文件首行增加
/* eslint-disable */
- 忽略代码块:首尾增加disable和enable
/* eslint-disable */ var a =1,b=2 alert('foo'); /* eslint-enable */
- 忽略某行代码,以下4种均可
alert('foo'); // eslint-disable-line // eslint-disable-next-line alert('foo'); /* eslint-disable-next-line */ alert('foo'); alert('foo'); /* eslint-disable-line */
- 忽略某行代码的单个/多个规则,在上述基础上增加规则即可:
alert('foo'); // eslint-disable-line no-alert, quotes, semi // eslint-disable-next-line no-alert, quotes, semi alert('foo'); alert('foo'); /* eslint-disable-line no-alert, quotes, semi */ /* eslint-disable-next-line no-alert, quotes, semi */ alert('foo');
- 在vue的节点中忽略某行dom中的es校验 (场景举例:忽略对v-html的校验;需安装eslint-plugin-vue)
<!-- eslint-disable-next-line -->
<!-- eslint-disable-next-line vue/no-v-html -->
- 忽略整个文件:文件首行增加
stylelint忽略与eslint类似,不再赘述。
关于VUE扩展的强调
1.mixin文件需要在export default前增加一句// @vue/component
使检测器将其视为组件。否则扩展对mixin文件不生效。详情查看eslint
或 github
2.在standrard的eslintrc和项目本地的eslintrc中,rules没有配置任何关于vue扩展的规则,使用的就是vue-recommend的默认规则配置.下图每个文件中的规则可访问官方文档
3.项目未配置任何关于vue3的lint扩展。参考链接
ESlint规则记录
eslint-base
中文规则网站竟然不全,wolegedacao,贴个英文规则
基于eslint规则官网的顺序逐一列出standard采用的规则。
Possible Errors
1.no-async-promise-executor禁止使用异步函数作为 Promise executor
new Promise
构造函数接收一个 executor 函数作为参数,该函数具有 resolve
和 reject
两个参数
禁止该参数为异步函数,不能带async。
2.no-compare-neg-zero禁止与 -0 进行比较 (听说过,没见过,没事不要写什么负0)
3.no-cond-assign 该规则禁止在 if
、for
、while
和 do...while
语句中出现模棱两可的赋值操作符。(ex:如果在if判断中手滑少写了个等号,会报错)
4. no-constant-condition禁止在以下语句的条件中出现常量表达式:
if
、for
、while
或do...while
语句?:
三元表达式 即if(0)
if(true)
此类代码会报错
如下代码会同时触发3和4报错,首先使用了赋值单等号,赋值后成了常量。另:standard允许使用console,不允许有debugger
if (this.data = '') {
console.log('111')
}
5.no-control-regex 禁止在正则表达式中使用控制字符
在 ASCII 中,0-31 范围内的控制字符是特殊的、不可见的字符。这些字符很少被用在 JavaScript 字符串中,所以一个正则表达式如果包含这些字符的,很有可能一个错误。
const regx = /\x0D/ //回车符
console.log(regx)
//error Unexpected control character(s) in regular expression: \x0d no-control-regex
6. no-debugger 禁用debugger
7.no-dupe-args
禁止 function
定义中出现重名参数。 (ex: fucntion test(a,b,a) //error
)
8. no-dupe-keys禁止对象字面量中出现重复的 key, 即禁止对象同名属性
(ex: var myObj = {name:'Jon',name:'Lucy'} //error
)
9.no-duplicate-case switch case结构中,不允许有重复的case值
10.no-empty 禁止空代码块,会忽略包含一句注释的代码块。
standard配置为"no-empty": ["error", { "allowEmptyCatch": true }], 额外允许空的catch块
11. no-empty-character-class 禁止正则表达式中出现空字符集 (ex:/^abc[]/ 匹配个寂寞)
12.no-ex-assign禁止对catch的error重新赋值
13.no-extra-boolean-cast禁止不必要的布尔转换(auto fix)
if(!!this.passWord)
会被自动修复为if(this.passWord)
if语句会自动做布尔转换,手动多余
14.no-extra-parens禁止多余的圆括号(auto fix) standard配置为"no-extra-parens": ["error", "functions"] 即允许函数周围多余的括号。
ex: typeof (a) 会被自动修复为typeof a
15.no-func-assign禁止对函数声明重新赋值
16. no-import-assign禁止对import的变量重新赋值
import mod, { named } from "./mod.mjs"
import * as mod_ns from "./mod.mjs"
//错误举例
mod = 1 // ERROR: 'mod' is readonly.
named = 2 // ERROR: 'named' is readonly.
mod_ns.named = 3 // ERROR: the members of 'mod_ns' is readonly.
mod_ns = {} // ERROR: 'mod_ns' is readonly.
//推荐举例
mod.prop = 1
named.prop = 2
mod_ns.named.prop = 3
// Known Limitation
function test(obj) {
obj.named = 4 // Not errored because 'obj' is not namespace objects.
}
test(mod_ns) // Not errored because it doesn't know that 'test' updates the member of the argument.
17.no-invalid-regexp禁止在 RegExp
构造函数中出现无效的正则表达式。
这条报错很难单独出现。因为经常和另一条规则 prefer-regex-literals 一起出现。
正则创建形式:
/ab+c/i; //字面量形式
new RegExp('ab+c', 'i'); // 首个参数为字符串模式的构造函数
new RegExp(/ab+c/, 'i'); // 首个参数为常规字面量的构造函数
单独触发no-invalid-regexp:
const flag = 'i'
const a = new RegExp('[', flag)
console.log(a)
如果使用let b = /[/
或 let c=/'['/
这种字面量形式,解析器会直接报语法错误,但在RegExp构造函数中不会报错,所以增加了这条规则。但是很少有人这样单独定义flag和pattern来写正则,完全没有必要。如果不单独声明flag和pattern,会触发另一条规则 prefer-regex-literals standard的配置是 ["error", { "disallowRedundantWrapping": true }],
禁止构造函数中只使用字面量,多余的//包裹也会报错。
综上:除非使用动态的正则,优先采用字面量形式创建。
18.no-irregular-whitespace禁止不规则的空白。由于在Stylistic Issues风格指南中规定了各种空格规则且会自动fix,之后不会触发此规则。
19.no-loss-of-precision禁止丢失精度的数字 基础知识补一补
20. no-misleading-character-class 禁止在字符类语法中出现由多个代码点组成的字符 基础知识再补一补
21.no-obj-calls禁止把全局对象作为函数调用
错误 代码示例:
/*eslint no-obj-calls: "error"*/
var math = Math();
var json = JSON();
var reflect = Reflect();
正确 代码示例:
/*eslint no-obj-calls: "error"*/
function area(r) {
return Math.PI * r * r;
}
var object = JSON.parse("{}");
var value = Reflect.get({ x: 1, y: 2 }, "x");
22. no-prototype-builtins禁止直接调用 Object.prototypes
的内置属性。
错误 代码示例:
/*eslint no-prototype-builtins: "error"*/
var hasBarProperty = foo.hasOwnProperty("bar");
var isPrototypeOfBar = foo.isPrototypeOf(bar);
var barIsEnumerable = foo.propertyIsEnumerable("bar");
正确 代码示例:
/*eslint no-prototype-builtins: "error"*/
var hasBarProperty = Object.prototype.hasOwnProperty.call(foo, "bar");
var isPrototypeOfBar = Object.prototype.isPrototypeOf.call(foo, bar);
var barIsEnumerable = {}.propertyIsEnumerable.call(foo, "bar");
23.no-regex-spaces禁止正则表达式字面量中出现多个空格(auto fix)
24. no-sparse-arrays 禁用稀疏数组
错误示例: var items = [,]; var colors = [ "red",, "blue" ];
25. no-template-curly-in-string 禁止在常规字符串中出现模板字面量占位符语法,
即不允许var msg = "Hello ${name}!"
之类的写法
- no-unexpected-multiline禁止出现令人困惑的多行表达式。看举例更方便明白意图。
错误 代码示例:
/*eslint no-unexpected-multiline: "error"*/
var foo = bar
(1 || 2).baz();
var hello = 'world'
[1, 2, 3].forEach(addNumber);
let x = function() {}
`hello`
let x = function() {}
x
`hello`
let x = foo
/regex/g.test(bar)
正确 代码示例:
/*eslint no-unexpected-multiline: "error"*/
var foo = bar;
(1 || 2).baz();
var foo = bar
;(1 || 2).baz()
var hello = 'world';
[1, 2, 3].forEach(addNumber);
var hello = 'world'
void [1, 2, 3].forEach(addNumber);
let x = function() {};
`hello`
let tag = function() {}
tag `hello`
27. no-unreachable禁止在 return
、throw
、continue
和 break
语句之后出现不可达代码
28. no-unreachable-loop 禁止最多可进行一次迭代的循环。如在循环中写一定执行的break,如下错误示例
for (foo of bar) {
if (foo.id === id) {
doSomething(foo);
}
break;
}
29.no-unsafe-finally禁止在 finally
语句块中出现控制流语句。JavaScript 暂停 try
和 catch
语句块中的控制流语句,直到 finally
语句块执行完毕。所以,当 return
、throw
、break
和 continue
出现在 finally
中时, try
和 catch
语句块中的控制流语句将被覆盖,这被认为是意外的行为。
30.no-unsafe-negation 禁止对关系运算符的左操作数使用否定操作符 (auto fix) 该规则禁止对关系运算符的左操作数使用否定操作符。
关系运算符有:
in
运算符.instanceof
运算符.
错误 代码示例:
/*eslint no-unsafe-negation: "error"*/
if (!key in object) {
// operator precedence makes it equivalent to (!key) in object
// and type conversion makes it equivalent to (key ? "false" : "true") in object
}
if (!obj instanceof Ctor) {
// operator precedence makes it equivalent to (!obj) instanceof Ctor
// and it equivalent to always false since boolean values are not objects.
}
正确 代码示例:
/*eslint no-unsafe-negation: "error"*/
if (!(key in object)) {
// key is not in object
}
if (!(obj instanceof Ctor)) {
// obj is not an instance of Ctor
}
if(("" + !key) in object) {
// make operator precedence and type conversion explicit
// in a rare situation when that is the intended meaning
}
31.no-useless-backreference 禁止在正则表达式中使用无用的反向引用,没仔细研究
32. use-isnan ["error", {"enforceForSwitchCase": true, "enforceForIndexOf": true}], 禁止在各种判断的地方直接使用NaN,必须使用isNaN来判断,包括switch case分支和indexOf
33. valid-typeof ["error", { "requireStringLiterals": true }] typeof只能与typeof预期的几个字符串结果比较
Best Practices
1. accessor-pairs ["error", { "setWithoutGet": true, "enforceForClassMembers": true }],强制 getter 和 setter 在对象中成对出现 ,但只有setter不报错,报warning。enforceForClassMembers对class中的get,set也生效.
eslint-recommand
1. no-case-declarations no-case-declarations
eslint-plugin-vue
1. vue/require-default-prop warning Prop 'clientType' requires default value to be set
2. vue/require-prop-type-constructor error The "clientType" property should be a constructor
props: {
clientType: ''
},
针对props,要求有默认值且type为构造函数,修改如下
props: {
clientType: {
default: '',
type: String
}
},
如果为对象,如下写法将触发报错3
props: {
clientType: {
default: '',
type: Object
}
},
3. vue/require-valid-default-prop error Type of the default value for 'clientType' prop must be a function
此规则检查对于给定的type,default是否有效。Arrary和Object的default必须是函数。修改如下:
props: {
clientType: {
type: Object,
default() {
return { message: 'hello' }
}
}
},
4. vue/no-use-v-if-with-v-for vue对v-for的处理优先级高,导致每次循环都会执行一遍v-if,目前项目中有大量的v-if和v-for放在一个节点上,实实在在的影响了执行效率.推荐外层增加一层template使用v-if
<ul v-if="complete">
<TodoItem v-for="todo in todos" :todo="todo" />
</ul>
eslint-plugin-node
standrd配置了如下7条
1."node/handle-callback-err": ["error", "^(err|error)$" ] 一定要处理回调函数的error或err参数
以^开头表示正则匹配
- 如果选项是
"^(err|error|anySpecificError)$"
,则规则报告参数名称可以是err
,error
或 的未处理错误anySpecificError
。 - 如果选项为
"^.+Error$"
,则规则报告参数名称以Error
(例如,connectionError
或validationError
将匹配)结尾的未处理错误。 - 如果选择是
"^.*(e|E)rr"
,该规则报告,其中的参数名称中包含任何字符串匹配未处理的错误err
或Err
(例如err
,error
,anyError
,some_err
将匹配)。
//如下回调函数传参为data,不报错。reject特意传参new Error()是因为有另一条规则
//Expected the Promise rejection reason to be an Error prefer-promise-reject-errors
function (data) {
return Promise.reject(new Error())
})
//把data改为err或error,同样不使用,会报错 Expected error to be handled node/handle-callback-err
function (error) {
return Promise.reject(new Error())
})
2."node/no-callback-literal": "error" 调用名为cb或callback的函数时,第一个参数不能为字面量
/*如下代码会触发报错触发报错
error Unexpected literal in error position of callback node/no-callback-literal*/
mounted () {
function callback (a) {
console.log(a)
}
callback('a')
},
//注:在methods里定义callback(){}, this.callback('字面量')不会报错
/*不报错的调用*/
cb(undefined);
cb(null, 5);
callback(new Error('some error'));
callback(someVariable);
3."node/no-deprecated-api": "error" 禁用废弃的node api
//例如 url.prase废弃,推荐改为如下写法
let params = (new URL(window.location)).searchParams;
let lang = params.get('lang')
4."node/no-exports-assign": "error" 应该是不许给export直接赋值
👍 Examples of **correct** code for this rule:
/*eslint node/no-exports-assign: error */
module.exports.foo = 1
exports.bar = 2
module.exports = {}
// allows `exports = {}` if along with `module.exports =`
module.exports = exports = {}
exports = module.exports = {}
👎 Examples of **incorrect** code for this rule:
/*eslint node/no-exports-assign: error */
exports = {}
5."node/no-new-require": "error" 禁止new关键字和require一起使用
//不推荐
var appHeader = new require('app-header');
//推荐
var AppHeader = require('app-header');
var appHeader = new AppHeader();
6."node/no-path-concat": "error" 禁止带正反斜杠的字符串连接__dirname
和__filename
(不完全确定)
开发人员可能会尝试使用这些变量来创建其他文件的路径,例如:
var fullPath = __dirname + "/index.js" ;
这种方式,需要配合运行的操作系统判断的代码,官方不推荐,应使用path模块的join或resolve
var fullPath1 = path.resolve(__dirname, "index.js");
var fullPath2 = path.join(__dirname, "index.js");
报错写法举例
/*eslint node/no-path-concat: "error"*/
const fullPath1 = __dirname + "/foo.js";
const fullPath2 = __filename + "/foo.js";
const fullPath3 = `${__dirname}/foo.js`;
const fullPath4 = `${__filename}/foo.js`;
正确写法举例
const fullPath1 = path.join(__dirname, "foo.js");
const fullPath2 = path.join(__filename, "foo.js");
const fullPath3 = __dirname + ".js";
const fullPath4 = __filename + ".map";
const fullPath5 = `${__dirname}_foo.js`;
const fullPath6 = `${__filename}.test.js`;
7."node/process-exit-as-throw": "error"
执行--fix能自动修复的规则列表
no-extra-boolean-cast禁止不必要的布尔转换
no-regex-spaces禁止正则表达式字面量中出现多个空格
no-extra-parens禁止多余的圆括号(auto fix)standard配置为"no-extra-parens": ["error", "functions"] 即允许函数周围多余的括号。
no-unsafe-negation 禁止对关系运算符的左操作数使用否定操作符
standard未采用的eslint规则
no-extra-semi standard配置了无分号,覆盖此规则
no-inner-declarations禁止在嵌套的语句块中声明函数
no-dupe-else-if 禁止else if分支条件重复
中文站缺失的规则
no-dupe-else-if 禁止else if分支条件重复
此规则的错误代码示例:
/*eslint no-promise-executor-return: "error"*/
new Promise((resolve, reject) => {
if (someCondition) {
return defaultResult;
}
getSomething((err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
new Promise((resolve, reject) => getSomething((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
}));
new Promise(() => {
return 1;
});
此规则的正确代码示例:
/*eslint no-promise-executor-return: "error"*/
new Promise((resolve, reject) => {
if (someCondition) {
resolve(defaultResult);
return;
}
getSomething((err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
new Promise((resolve, reject) => {
getSomething((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
Promise.resolve(1);
no-unsafe-optional-chaining 禁止在不允许使用undefined
值的上下文中使用可选链.
可选的链接 ( ?.
) 表达式可以短路,返回值为undefined
。因此,将评估的可选链接表达式视为函数、对象、数字等,可能会导致 TypeError 或意外结果。例如:
var obj = undefined;
1 in obj?.foo; // TypeError
with (obj?.foo); // TypeError
for (bar of obj?.foo); // TypeError
bar instanceof obj?.foo; // TypeError
const { bar } = obj?.foo; // TypeError
此外,括号限制了链中短路的范围。例如:
var obj = undefined;
(obj?.foo)(); // TypeError
(obj?.foo).bar; // TypeError