大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

在日常项目开发中,ESLint常常扮演者可有可无的角色,我们想让它来帮助我们检查代码,同时又害怕它带来的报错无法处理;本文带你深入的了解ESLint的配置以及原理。

ESLint是一个插件化的代码检测工具,正如它官网描述的slogan:

可组装的JavaScript和JSX检查工具

ESLint不仅可以检测JS,还支持JSX和Vue,它的高可扩展性让它能够支持更多的项目。

ESLint的前辈们

提到ESLint,我们就不得不提及他的前辈们JSLint和JSHint,以及它们的区别;首先就是JSLint,它是由Douglas Crockford开发的;JSLint的灵感来源于C语言的检查工具Lint,Lint最初被发明用来扫描C语言源文件以便找到其中的错误,后来随着语言的成熟以及编译器能够更好的找到问题,Lint工具也逐渐不再被需要了。

JavaScript最开始被发明只是用来在网页上做一些简单的工作(点击事件、表单提交等),随着JS语言的发展完善以及项目复杂程度的增加,急需一个用来检查JS语法或者其他问题的校验工具,因此JSLint就诞生了;它是由Douglas Crockford在2010年开源的第一款针对JS的语法检测工具,它和Lint做着相同的事,扫描JS的源文件来找到错误;它内部也是通过fs.readFile来读取文件然后逐行来进行检查。

JSLint Logo

我们可以在全局安装jslint,然后jslint source.js对我们的代码进行检查;JSLint刚开始确实帮助很多JS开发者节省了不少排查错误的时间,但是JSLint的问题也很明显:所有的配置项都内置不可配置,因此你要用JSLint只能遵循Douglas Crockford老爷子自己定义的代码风格和规范;再加上他本身推崇爱用不用的传统,不像开发者开放配置或者修改他觉得对的规则,因此很多人也无法忍受他的规则。

由于JSLint让很多人无法忍受,所以Anton Kovalyov基于JSLint开发了JSHint,它的初衷就是为了能让开发者自定义规则lint rules,因此提供了丰富的配置项,给开发者极大的自由;同时它也提供了一套相当完善的编辑器插件,我们常用的VIM、Sublime、Atom、Vs Code等都有插件支持,方便开发。

JSHint Logo

JSHint一开始就保持了开源软件的风格,并且由社区来驱动,因此一推出就很快发展起来,我们熟知的一些项目或者公司也使用了JSHint,比如:Facebook、Google、Jquery、Disqus等。

JSHint相比于JSLint,最大的特点就是可配置,我们可以在项目中放入一个.jshintrc的配置文件,JSLint就会加载配置文件用于代码分析,配置文件的部分内容如下:

{// 禁止有未使用的变量"unused": true,// 禁止有未定义的变量"undef": true,// 无视没有加分号行尾"asi": true,// 全局变量"globals": {"jQuery": true}
}

由于JSHint是基于JSLint开发的,因此JSLint的一些问题也继承下来了,比如不易扩展以及不容易直接根据报错定位到具体的配置规则等;在2013年,Zakas大佬发现JSHint无法满足自己定制化规则的需要,因此设想开发一个基于AST的Linter,可以动态执行额外的规则,同时可以很方面的扩展规则,于是在13年6月份开源推出了全新的ESLint。

ESLint Logo

ESLint号称下一代的JS Linter工具,它的灵感来源于PHP Linter,将源码解析成AST,然后检测AST是否符合规则;ESLint最开始使用esprima解析器将源码解析成AST,然后就可以使用任意规则来检测AST是否符合预期,这也是ESLint高可扩展的原因。

刚开始ESlint的推出并没有撼动JSHint的霸主地位,由于ESlint需要将源码转为AST,而JSHint直接检测源文件字符串,因此执行速度比JSHint慢很多;真正让ESLint实现弯道超车的是ES6的出现。

2015年,ES6规范发布后,由于大部分浏览器支持程度不高,因此需要Babel将代码转换编译成ES5或者更低版本;同时由于ES6变化很大,短期内JSHint无法完全支持,这时ESLint的高扩展性的优点显现出来了,不仅可以扩展规则,连默认的解析器也能替换;Babel团队就为ESLint开发了babel-eslint替换默认的解析器esprima,让ESLint率先支持ES6。

配置

ESLint被设计成完全可配置的,我们可以用多种方式配置它的规则,或者配置要检测文件的范围。

初始化

如果想在现有的项目中引入eslint,我们可以在项目中进行初始化:

npm i eslint --save-dev
npx eslint --init

在经过一系列问答后,会在项目根目录创建一个我们熟悉的.eslintrc.js配置文件;安装后就可以通过命令行对项目中的文件需要检测了:

# 检测单个文件
npx eslint file1.js file2.js
# 检测src和scripts目录
npx eslint src scripts

一般我们会把eslint命令行配置到packages.json中:

"scripts": {"lint": "npx eslint src scripts","lint:fix": "npx eslint src scripts --fix","lint:create": "npx eslint --init"
}

这里有一个--fix后缀,是ESLint提供自动修复基础错误的功能,我们运行lint:fix后发现有一些报错信息消失了,代码也改变了;不过它只能修复一些基础的不影响代码逻辑的错误,比如代码末尾加上分号、表达式的空格等等。

ESLint默认只会检测.js后缀的文件,如果我们想对更多类型的文件进行检测,比如.vue、.jsx,可以使用--ext选项,参数用逗号分隔:

"scripts": {"lint": "npx eslint --ext .js,.jsx,.vue src",
}

对于一些公共的js,或者测试脚本,不需要进行检测,我们可以通过在项目根目录创建一个.eslintignore告诉ESLint去忽略特定的目录或者文件:

public/
src/main.js

除了.eslintignore中指定的文件或目录,ESLint总是忽略/node_modules/*/bower_components/*中的文件;因此对于一些目前解决不了的规则报错,但是我们需要打包上线,在不影响运行的情况下,我们就可以利用.eslintignore文件将其暂时忽略。

ESLint一共有两种配置方式,第一种方式是直接把lint规则嵌入源代码中;

/* eslint eqeqeq: "error" */
var num = 1
num == '1'

eqeqeq代表eslint校验规则,error代表校验报错级别,后面会详细说明;这个eslint校验规则只会对该文件生效:

eqeqeq

我们还可以使用其他注释,更精确地管理eslint对某个文件或某一行代码的校验:

/* eslint-disable */
alert('该注释放在文件顶部,eslint不会检查整个文件')/* eslint-enable */
alert('重新启用eslint检查')/* eslint-disable eqeqeq */
alert('只禁止某一个或多个规则')/* eslint-disable-next-line */
alert('下一行禁止eslint检查')alert('当前行禁止eslint检查') // eslint-disable-line

第二种方式是直接把lint规则放到我们的配置文件中,上面init初始化生成的.eslintrc.js就是一个配置文件,官方还提供了其他几种配置文件名称(优先级从上到下):

.eslintrc.js
.eslintrc.yaml
.eslintrc.yml
.eslintrc.json
.eslintrc
package.json

一般情况下我们使用.eslintrc.js就可以了。

配置详解

我们详细看下.eslintrc.js文件内部有哪些配置选项:

module.exports = {"globals": {},"env": {"browser": true,"es2021": true},"extends": "eslint:recommended","parse": "babel-eslint","parserOptions": {"ecmaVersion": 12,"sourceType": "module"},"rules": {}
};

首先是我们的globals,ESLint会检测未声明的变量,并发出报错,比如node环境中的process,浏览器环境下的全局变量console,以及我们通过cdn引入的jQuery定义的$等;我们可以在globals中进行变量声明:

{"globals": {// true表示该变量可读写,false表示变量是只读"$": true,"console": false}
}

但是node或者浏览器中的全局变量很多,如果我们一个个进行声明显得繁琐,因此就需要用到我们的env,这是对环境定义的一组全局变量的预设:

{"env": {"browser": true,"node": true,"jquery": true}
}

更多的环境参数可以看ESLint声明环境。

然后就是我们的解析器parseparserOptions;我们上面说到ESLint可以更换解析器,"parse": "babel-eslint"就是用来指定要使用的解析器,它有以下几个选择:

  • esprima:ESLint最开始使用的解析器

  • espree:默认,ESLint自己基于esprima v1.2.2开发的一个解析器

  • babel-eslint:一个对Babel解析器的包装,使其能够与ESLint兼容。

  • @typescript-eslint/parser:将TypeScript转换成与estree兼容的形式,以便在ESLint中使用。

那么这几个解析器怎么选择呢?如果你想使用一些先进的语法(ES6789),就使用babel-eslint(需要npm安装);如果你想使用typescript,就使用@typescript-eslint/parser。

选好了解析器,我们可以通过parserOptions给解析器传入一些其他的配置参数:

{"parser": "babel-eslint","parserOptions": {// 代码模块类型,可选script(默认),module"sourceType": "module",// es版本号,默认为5,可以使用年份2015(同6)"ecamVersion": 6,// es 特性配置"ecmaFeatures": {"globalReturn": true, // 允许在全局作用域下使用 return 语句"impliedStrict": true, // 启用全局 strict mode "jsx": true // 启用 JSX}},
}

规则

ESLint可以配置大量的规则,我们可以在配置文件的rules属性自定义需要的规则:

{"rules":{// "semi": "off","semi": 0,// "quotes": "warn","quotes": 1,// "no-console": "error""no-console": 2}
}

对于检验规则,有3个报错等级:

  • "off" 或 0:关闭规则

  • "warn" 或 1:开启规则,warn级别的错误 (不会导致程序退出)

  • "error" 或 2:开启规则,error级别的错误(当被触发的时候,程序会退出)

有些规则没有属性,只需控制开启还是关闭;有些规则可以传入属性,我们通过数组的方式传入参数:

{"rules":{// 代码缩进,使用tab缩进,switch语句的case缩进级别,1表示2个空格"indent": ["error", "tab", { "SwitchCase": 1 }],// 引号,双引号"quotes": ["error", "double"],// 在语句末尾使用分号"semi": ["error", "always"]}
}

对于刚接触ESLint的同学,看到这么多的规则肯定很懵逼,难道要一条一条来记么?肯定不是的;项目的ESLint配置文件并不是一次性完成的,而是在项目开发中慢慢完善起来的,因为并不是所有的规则都是我们项目所需要的。因此我们可以先进行编码,在编码的过程中使用npm run lint校验代码规范,如果报错,可以通过报错信息去详细查看是那一条规范报错:

规范报错查看

比如这里的报错no-unused-vars我们可以看到它来自第六行,再去文档查找,发现是我们在js中有一个定义了却未使用的变量;在团队协商后可以进一步来确定项目是否需要这条规范。

扩展

如果每条规则都需要团队协商配置还是比较繁琐的,在项目开始配置时,我们可以先使用一些业内已经成熟的、大家普遍遵循的编码规范(最佳实践);我们可以通过extends字段传入一些规范,它接收String/Array:

{"extends": ["eslint:recommended","plugin:vue/essential","@vue/prettier","eslint-config-standard"]
}

extends可以使用以下几种类型的扩展:

  • eslint:开头的ESLint官方扩展,有两个:eslint:recommended(推荐规范)和eslint:all(所有规范)。

  • plugin:开头的扩展是插件类型扩展

  • eslint-config:开头的来自npm包,使用时可以省略eslint-config-,比如上面的可以直接写成standard

  • @:开头的扩展和eslint-config一样,是在npm包上面加了一层作用域scope

需要注意的是:多个扩展中有相同的规则,以后面引入的扩展中规则为准。

eslint:recommended推荐使用的规则在规则列表的右侧用绿色√标记。

规范报错查看

插件类型的扩展一般先通过npm安装插件,以上面的vue为例,我们先来安装:

npm install --save-dev eslint eslint-plugin-vue

安装后一个插件中会有很多同类型扩展可供选择,比如vue就有以下几种扩展:

  • plugin:vue/base:基础

  • plugin:vue/essential:必不可少的

  • plugin:vue/recommended:推荐的

  • plugin:vue/strongly-recommended:强烈推荐

针对扩展中的规则,我们也能够通过rules来对它进行覆写:

{"extends": ["plugin:vue/recommended"],"rules": {// 覆写规则"vue/no-unused-vars": "error"}
}

除了上面的eslint-config-standard,还有以下几个比较知名的编码规范:

编码规范

不过需要注意的是,很多规范不仅需要安装扩展本身,还需要配合插件,比如eslint-config-standard,我们还需要安装下面几个插件才能有效:

npm i eslint-config-standard -D
npm i eslint-plugin-promise eslint-plugin-import eslint-plugin-node -D

插件

在Webpack中,插件是用来扩展功能,让其能够处理更多的文件类型以及功能,ESLint中的插件也是同样的作用;虽然ESLint提供了几百种规则可供选择,但是随着JS框架和语法的发展,这么多规则还是显得不够,因为官方的规则只能检查标准的JS语法;如果我们写的是vue或者react的jsx,那么ESLint就不能检测了。

这时就需要安装ESLint插件,用来定制一些特色的规则进行检测;eslint插件以eslint-plugin-开头,使用时可以省略;比如我们上面检测.vue文件就用到eslint-plugin-vue插件;需要注意的是,我们在配置eslint-plugin-vue这个插件时,如果仅配置"plugins": ["vue"],vue文件中template内容还是会解析失败。

这是因为不管是默认的espree还是babel-eslint解析器都无法解析.vue中template的内容;eslint-plugin-vue插件依赖vue-eslint-parser解析器,而vue-eslint-parser解析器只会解析template内容,不会检测script中的JS内容,因此我们还需要指定一下解析器:

{"extends": ["eslint:recommended"],"plugins": ["vue"],"parser": "vue-eslint-parser","parserOptions": {"parser": "babel-eslint","ecmaVersion": 12,"sourceType": "module",},
}

上面parserOptions.parser不少同学肯定看的有点迷糊,这是由于外层的解析器只能有一个,我们已经用了vue-eslint-parser就不能再写其他的;因此vue-eslint-parser的做法是在解析器选项中再传入一个解析器选项用来处理script中的JS内容。

如果想让ESLint检测vue文件,确保将.vue后缀加入--ext选项中。

而react配置则较为简单了,引入插件,选择对应的扩展规则即可:

{"extends": ["eslint:recommended","plugin:react/recommended"],"parserOptions": {// 启用jsx语法支持"ecmaFeatures": {"jsx": true},"ecmaVersion": 12,"sourceType": "module"},"plugins": ["react"],
}

配合prettier

虽然ESLint会对我们的代码格式进行一些检测(比如分号、单双引号等),但是并不能完全统一代码风格,我们还需要一个工具Prettier;Prettier是什么?Prettier是一个支持很多语言的代码格式化工具,官网用了一个“贬义”的单词来形容它opinionated,翻译过来就是固执己见的。

Prettier

Prettier还有以下四个特点:

  • An opinionated code formatter

  • Supports many languages

  • Integrates with most editors

  • Has few options

那么为什么Prettier要用opinionated这个词呢?每个团队成员可能会用不同的编辑器或是不同的插件,每个插件也会有自己的格式化规范,这样就导致了我们在开发时代码风格极大的不统一,甚至造成不必要的冲突;Prettier就给我们定义好了风格,按照它的风格来(是不是很像JSLint);但是又没有完全封闭,开放了一些必要的设置,这也是最后一点few options的含义;因此我们只需要将代码的美化交给Prettier来做就好了。

首先还是安装,我们将所需的插件进行安装,这里用到prettier的三个包:

npm i prettier eslint-plugin-prettier eslint-config-prettier

首先就是这个eslint-plugin-prettier插件,它会调用prettier对你的代码风格进行检查,其原理是先使用prettier对你的代码进行格式化,然后与格式化之前的代码进行对比,如果过出现了不一致,这个地方就会被prettier进行标记。

被标记后Prettier并不会有任何提示,我们还需要对标记后的代码进行报错处理,在rules中进行添加配置:

{"plugins": ["prettier"],"rules": {"prettier/prettier": "error",}
}

Prettier报错

如果不希望Prettier影响项目打包,我们也可以将prettier的报错由error改为warn

借助ESLint的自动修复--fix,我们可以修复这种简单的样式问题;那如果我们想自定义一些样式怎么办呢?没关系,虽然Prettier是一个固执己见的工具,但是人家也是开放了一些配置可供我们进行自定义的,我们可以在项目中新建一个.prettierrc.json文件:

{// 尾逗号"trailingComma": "es5",// 缩进长度"tabWidth": 4,// 代码末尾分号"semi": false,// 单引号"singleQuote": true,// 单行代码最大长度"printWidth": 100,// 对象字面量的括号"bracketSpacing": true,// 箭头函数参数加括号"arrowParens": "always",
}

这里简单贴一些常用的,我们可以在官网选项配置找到更多的配置规则。

这样配置后虽然能修复代码了,但是如果遇到另一个也固执己见的扩展,比如我们引入eslint-config-standard这个扩展,它也有自己的代码风格;如果通过Prettier格式化,standard不干了;如果通过standard自动修复,那么Prettier又要报错了,两边都是大爷这可咋整呢?

可咋整

机智的Prettier已经帮我们考虑到这个问题了,利用extends中最后一个覆盖前面扩展的特性,我们将eslint-config-prettier配置在extends最后,就能够关闭一些与Prettier的规则:

{"extends": ["standard", "prettier"],"plugins": ["prettier"],"rules": {"prettier/prettier": "error",}
}

另外eslint-plugin-prettier插件也附带有plugin:prettier/recommended扩展配置,可以同时启用插件和eslint-config-prettier扩展,因此我们可以只需要配置recommended就可以了:

{"extends": ["standard", "plugin:prettier/recommended"],"rules": {"prettier/prettier": "error",}
}

Vue中为了支持Prettier,也将eslint-plugin-prettier和eslint-config-prettier整合到一起,放到了node_modules/@vue/eslint-config-prettier目录中(加了一层作用域),因此我们在Vue脚手架生成的项目经常能看到@vue/prettier这个扩展,打开它的目录发现其本质是一样的:

module.exports = {plugins: ['prettier'],extends: [require.resolve('eslint-config-prettier'),require.resolve('eslint-config-prettier/vue')],rules: {'prettier/prettier': 'warn'}
}

Node 社群

我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

 “分享、点赞、在看” 支持一波

一文彻底读懂ESLint相关推荐

  1. 【Web技术】1114- 一文彻底读懂ESLint

    总字数:3,706 | 阅读时间:13分钟 在日常项目开发中,ESLint常常扮演者可有可无的角色,我们想让它来帮助我们检查代码,同时又害怕它带来的报错无法处理:本文带你深入的了解ESLint的配置以 ...

  2. 一文彻底读懂物联网关键技术之——ZigBee!

    一文彻底读懂物联网关键技术之--ZigBee! 本文采用问答形式向你详细地介绍了方方面面,不夸口的说,你所需要知道的关于 ZigBee的一切,在这里基本可以了解到! 在智能硬件和物联网领域,时下大名鼎 ...

  3. 一文深入浅出读懂NoSQL

    一文深入浅出读懂NoSQL 2016-11-25 Runoot.com ICT架构师技术交流 NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL".在现 ...

  4. 一文极速读懂 Gene Ontology (GO)数据库

    一.介绍 官方:基因本体(GO)知识库是有关基因功能的全球最大信息来源. 这些知识既是人类可读的,也是机器可读的,并且是生物医学研究中大规模分子生物学和遗传学实验的计算分析的基础. 在读懂基因本体论( ...

  5. 一文能读懂车载与Android的关系

    文章目录 1 Android Auto 1.1 核心功能 1.1.1 Google Assistant 1.2 兼容的车型和应用 1.3 App 1.3.1 开发 1.3.2 设计 1.4 无线 2 ...

  6. 一文彻底读懂优秀开源产品MyBatis一级缓存设计!

    孙玄 奈学教育CEO 读完需要 3 分钟 速读仅需 1 分钟 孙玄, 现任奈学教育科技创始人&CEO ,毕业于浙大,前百度资深研发工程师.前 58 集团技术委员会主席/高级系统架构师到前转转公 ...

  7. 一文彻底读懂MySQL事务的四大隔离级别

    前言 之前分析一个死锁问题,发现自己对数据库隔离级别理解还不够深入,所以趁着这几天假期,整理一下MySQL事务的四大隔离级别相关知识,希望对大家有帮助~ 事务 什么是事务? 事务,由一个有限的数据库操 ...

  8. 一个文档读懂计算机网络

    计算机网络 1.互联网协议入门 我们每天使用互联网,你是否想过,它是如何实现的? 全世界几十亿台电脑,连接在一起,两两通信.上海的某一块网卡送出信号,洛杉矶的另一块网卡居然就收到了,两者实际上根本不知 ...

  9. java虚拟机_一文彻底读懂Java虚拟机!(JVM)

    提到Java虚拟机(JVM),可能大部分人的第一印象是"难",但当让我们真正走入"JVM世界"的时候,会发现其实问题并不像我们想象中的那么复杂.唯一真正令我们恐 ...

最新文章

  1. 辞职之后的思考--激励
  2. [转载].NET中高效能的socket编程
  3. 正确理解Mysql的列索引和多列索引
  4. 3ds max 渲染清晰面片的边缘
  5. gradle使用技巧之全局变量
  6. 获取对象的属性,并且判断对象属性是否存在
  7. python数据字符_python数据清洗系列之字符串处理详解
  8. Codeforces 52C
  9. 容器技术Docker K8s 12 容器服务Kubernetes版ACK详解-使用镜像快速创建无状态应用
  10. JAVA锁和volatile的内存语义volatile的使用场景
  11. vs2019找不着工具箱了_解决vs2010中工具箱的不见问题
  12. 罗尔定理、拉格朗日中值定理和柯西中值定理和用他们证明不等式、
  13. ngx-datatable中文教程
  14. 顺丰android架构师,顺丰数据库运维架构.pdf
  15. Python-docx 读写 Word 文档:读取正文、表格文本信息、段落格式、字体格式等
  16. mysql如何收费,mysql收费吗
  17. RK3188 5.1平台PCM2708 USB声卡调试
  18. [C#] UI跨执行绪
  19. 嵌入式系统课程设计:基于JSoup的鸿蒙教务查询软件
  20. mysql 5.7 远程授权_MySQL5.7创建用户并授权,设置允许远程连接

热门文章

  1. 字符串内置对象方法与Math内置对象方法的简介
  2. 基于PHP的图书管理系统(图片详情版)
  3. 汉密尔顿和安全车都很抢眼
  4. 大IPD之——学习华为的任职资格体系管理(十九)
  5. 引入非线性激励函数的作用
  6. Windows系统文件被faust勒索病毒加密勒索病毒解密恢复,电脑中病毒了怎么修复?
  7. 计算机小红点案例,联想电脑的小红点用来做什么?原来是这样,学会这招还可以节省耗电...
  8. Love is over?Over is Love?
  9. ios 打印 详细错误日志_ios 打印日志注意的点
  10. 转载:OpenGL显示文字