一、eslint介绍
ESLint 是一个开源的 JavaScript 代码检查工具,由 Nicholas C. Zakas 于2013年6月创建。代码检查是一种静态的分析,常用于寻找有问题的模式或者代码,并且不依赖于具体的编码风格。对大多数编程语言来说都会有代码检查,一般来说编译程序会内置检查工具。
JavaScript 是一个动态的弱类型语言,在开发中比较容易出错。因为没有编译程序,为了寻找 JavaScript 代码错误通常需要在执行过程中不断调试。像 ESLint 这样的可以让程序员在编码的过程中发现问题而不是在执行的过程中。
ESLint 的初衷是为了让程序员可以创建自己的检测规则。ESLint 的所有规则都被设计成可插拔的。为了便于人们使用,ESLint 内置了一些规则,当然,你可以在使用过程中自定义规则。所有的规则默认都是禁用的。
ESLint 使用 Node.js 编写。
二、eslint配置
配置方式:
一般都采用.eslintrc.* 的配置文件进行配置, 如果放在项目的根目录中,则会作用于整个项目。如果在项目的子目录中也包含着.eslintrc文件,则对于子目录中文件的检查会忽略掉根目录中的配置,而直接采用子目录中的配置,这就能够在不同的目录范围内应用不同的检查规则,显得比较灵活。ESLint采用逐级向上查找的方式查找.eslintrc.*文件,当找到带有 “root”: true 配置项的.eslintrc.* 文件时,将会停止向上查找。
在 package.json文件里的 eslintConfig 字段进行配置。
具体配置规则:
module.exports = {
parser: 'babel-eslint', // parser指定解析器,默认的为espree。babel-eslint是一个Babel parser的包装器,这个包装器使得 Babel parser 可以和 ESLint 协调工作
parserOptions: {
ecmaVersion: 6,
sourceType: 'module', // 设置为 "script" (默认) 或 "module"(ES6)。
ecmaFeatures: { // 这是个对象,表示你想使用的额外的语言特性:
jsx: true // 启用 JSX
}
},
extends: ['eslint:recommended'], // 使用eslint推荐的规则作为基础配置,可以在rules中覆盖
plugins: ['html', 'vue', 'prettier', 'import'], // vue是eslint-plugin-vue的简写,此插件的作用是可以让eslint识别.vue中的script代码
rules: { // 0或者off表示规则关闭,出错也被忽略;1或者warn表示如果出错会给出警告(不会导致程序退出);2或者error表示如果出错会报出错误(会导致程序退出,退出码是1)
'no-console': 'off',
'prefer-const': 'error',
'prettier/prettier': 'warn',
'prefer-arrow-callback': 'warn',
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
},
globals: { // 允许在代码中使用全局变量
location: true,
setTimeout: true
}
};
详情:配置eslint
引入规则方式:
1、推荐规则:“extends”引入推荐规则
2、自定义规则以文件形式引入其它的自定义规则,
3、用rules去定义个别规则,可覆盖掉”extends”中引入的规则。
{
"extends": [
"./node_modules/coding-standard/eslintDefaults.js",
// Override eslintDefaults.js
"./node_modules/coding-standard/.eslintrc-es6",
// Override .eslintrc-es6
"./node_modules/coding-standard/.eslintrc-jsx",
],
"rules": {
"eqeqeq": "warn"
}
}
4、注释配置规则:代码文件内以注释配置的规则会覆盖配置文件里的规则,即优先级要更高。常用的就是 `eslint-disable-next-line(忽略掉下一行的lint报错)
/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');
/* eslint-enable no-alert, no-console */
三、忽略检查
1、项目目录下建立.eslintignore文件,并在其中配置忽略掉对哪些文件的检查。需要注意的是,不管你有没有在.eslintignore中进行配置,eslint都会默认忽略掉对/node_modules/** 的检查。
2、在package.json文件的 eslintIgnore 字段进行配置
四、eslint检查原理
大部分编译器工作时的三个阶段
解析:将未经处理的代码解析成更为抽象的表达式,通常为抽象语法树,即 AST。
转换:通过修改解析后的代码表达式,将其转换为符合预期的新格式。
代码生成:将转换后的表达式生成为新的目标代码。
对于eslint来说,规则校验发生在将JavaScript 代码解析为 AST 之后,遍历 AST 的过程中。eslint采用 Espree 来生成AST。
code path
指的是程序的执行路径。程序可以由若干 code path 表达,一个 code path 可能包括两种类型的对象 CodePath 和CodePathSegment。
ESLint的规则可以使用代码路径。代码路径是程序的执行路径。
if (a && b) {
foo();
}
bar();
如果 a 为真 - 检测 b 是否为 真
如果 b 为真 — 执行 foo() — 执行 bar()
如果 b 非真 — 执行 bar()
如果 a 非真,执行 bar()
转换为 AST 的表达方式
ESLint 将 code path 抽象为 5 个事件。
- onCodePathStart:
- onCodePathEnd
- onCodePathSegmentStart
- onCodePathSegmentEnd
- onCodePathSegmentLoop
可参考源码 code-path-analyzer.js,官方文档中 Code Path Analysis Details 中对 JS 中的 code path 也有很详细的描述,可以参考。
rules工作原理
eslint中的rules源码存在于lib/rules下。
每一个rules都是一个node模块,用module.exports导出一个meta对象及一个create函数。
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow unnecessary semicolons",
category: "Possible Errors",
recommended: true,
url: "https://eslint.org/docs/rules/no-extra-semi"
},
fixable: "code",
schema: [] // no options
},
create: function(context) {
return {
// callback functions
};
}
};
meta 代表了这条规则的元数据,如这条规则的类别,文档,可接收的参数 schema 等等。
create 返回一个对象,其中定义了一些在 AST 遍历访问到对应节点需要执行的方法等等。函数接受一个context对象作为参数,里面包含了例如可以报告错误或者警告的context.report()、可以获取源代码的context.getSourceCode()等方法,可以简化规则的编写。详情:使用规则
五、如何自定义rules
栗子?:禁止块级注释,当代码中使用了块级注释,eslint将报错。
// lib/rules/no-block-comments.js
module.exports = {
meta: {
docs: {
description: '禁止块级注释',
category: 'Stylistic Issues',
recommended: true
}
},
create (context) {
// 获取源代码
const sourceCode = context.getSourceCode()
return {
Program () {
// 获取源代码中所有的注释
const comments = sourceCode.getAllComments()
const blockComments = comments.filter(({ type }) => type === 'Block')
blockComments.length && context.report({
node: node,
message: 'No block comments'
})
}
}
}
}
如何使用自定义的rules
编写好的rules需要发布到npm上,作为一个eslint-plugin,在项目中下载下来才能够使用
no-block-comments.js
module.exports = {
"extends": ["../../eslintrc.vue.js"],
"plugins": [
"no-block-comments"// 可省略eslint-plugin
],
"rules": {
"no-block-comments/no-block-comments": 1 引用no-block-comments插件中的no-block-comments规则
}
};
main.js
/**
* @author Renlingling
* @date 2019-08-26
* @Description:
*/
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: {App},
template: '<App/>',
})
结果:
/Users/renlingling/eslint-config-sgfe/tests/my-project/src/main.js
3:1 warning No block comments no-block-comments/no-block-comments