【前端科普系列】主要侧重于Web前端的基础知识,但定位为大而全的系列,而不是深入的系列。适合非前端开发的同学系统了解前端,能够更好的从事前端开发工作。对于前端开发来说,尽量写通俗的科普文章。这仅适合刚刚开始的初学者。
本文在第5 章中,主要介绍了ESLint,这是前端工程中非常重要的工具,并介绍了ESLint 的历史和用法,以及基于ESLint 来保护代码仓库的优雅护城河。建造.
一、引言战国时期,强大的赵国想要一次性进攻并吞并北方的燕国,而位于两国之间的小国凉城是一个战略要地。 - 完毕。于是赵令项彦忠率领十万大军,仅四千人攻打“凉城”,凉城王向以守城闻名的墨家求助。然而,凉城等待的却是一个外表朴素、孤身作战的墨家骑士葛力。 令人惊奇的是,葛力足智多谋,指挥凉城军民四千人,抗击十万赵军,大获全胜。
“凉城”就像我们的项目仓库。 “凉城”的秩序取决于“格力”能否维持。我们的项目仓库呢?你想看到一个没有秩序、没有规则、充满混乱的城市,还是想看到一个有秩序、团结、有秩序的城市?如何才能成为程序员中的“叛逆者”?保护天空之城?
2.要了解ESLint1和ESLint是什么,我们首先看一下官网(https://eslint.org/)上它们的定义。
查找并修复JavaScript 代码中的问题
是的,您只需一句话即可找到并修复JavaScript 代码中的问题。
ESLint 最初是Nicholas C. Zakas 于2013 年6 月创建的开源项目。其目标是提供一个插件式的JavaScript代码检测工具。
那么为什么需要JavaScript 代码检查工具呢?让我们从JavaScript 的语言特性开始吧。
2. lint 工具的演变历史在C 语言开发的早期,源程序中有很多不可移植的代码,Steve Johnson 的编译器无法识别。贝尔实验室于1979年开发了基于PCC(便携式C编译器)的静态代码。一种代码分析工具,可扫描C 源文件并对源程序中的不可移植代码发出警告。这个工具被命名为lint,下面的类似代码也是如此。检查工具称为xxLint。
JavaScript 语言的历史在《前端科普系列(1):前端简史》 中进行了讨论。我们提到过JavaScript 是一种Web 脚本语言,由Netscape 公司于1995 年4 月聘用的程序员Brendan Aich 开发。其目的是将其嵌入网页并运行。提交前快速检查。
Brendan Eich 仅用了10 天就设计出了该语言的第一个版本。作者没想到JavaScript 会发展到今天这样,所以它最初的设计存在很多荒谬之处。
因此,需要代码验证工具来分析未经授权的使用情况,JavaScript 语言的lint 工具的演变历史产生了三个里程碑式的工具:JSLint、JSHint 和ESLint。
(1)创始人JSLint在2008年出版了一本非常著名的书《JavaScript语言精粹》。由于封面上的图案是一只蝴蝶,所以俗称“蝴蝶书”。虽然它是一本很薄的书,但它是所有JavaScript 初学者的必读书,应该反复阅读。这本书的作者是道格拉斯·克罗克福德。
从标题《JavaScript语言精粹》 就可以看出,整本书涵盖了JavaScript 语言的所有优秀特性。在书的最后,作者随口列出了JavaScript的缺点和弱点。在这本书中,我们看到道格拉斯是一个不能容忍自己眼睛里有瑕疵的人。因此,在本书的最后,Douglas介绍了作者在2002年开发的JSLint工具,并定义了JSLint的所有规则及其用法。如果您使用JSLint,则必须接受其所有约定。
(2)JSHint 继承过去,为未来铺路2011年12月20日,Anton Kovalyov撰写了标志性文章《Why I forked JSLint to JSHint》(https://medium.com/@anton/why-i-forked-jslint-to-jshint-73a72fd3612 )已发表。指出JSLint 存在几个主要问题。
有一些令人不安的意见,不提供配置规则,不关注社区反馈
在社区开发人员的帮助下,我们创建了JSHint,它基于JSLint 构建并添加了以下功能:
更多可配置的规则,是社区的核心要求。凭借对代码模块化命令行工具的支持、与各种IDE 的轻松集成以及诸多好处,JSLint 取代JSHint 是必然的。
(3) 重新启动ESLint。由于JSLint继承自JSHint,因此它采用JSLint Top Down Operator Precedence 《http://crockford.com/javascript/tdop/tdop.html》(Top Down Operator Precedence)技术来实现源码分析。这个需求使得JSHint 的支持变得越来越困难,而通过暴露AST 信息来支持第三方插件绝对是一个很好的解决方案。
AST:抽象语法树(https://en.wikipedia.org/wiki/Abstract_syntax_tree)
因此,《JavaScript 高级程序设计》 的作者Nicholas C. Zakas 在2013 年6 月创建了ESLint。 ESLint 将源代码解析为AST,然后对AST 进行检测以确定代码是否符合规则,为ESLint 的高扩展性奠定了坚实的基础。 ESLint 仅用100 行代码就使内核足够简单,并且规则实现与内核完全分离。
不过,ESLint 当时并没有太大的热度,因为它需要将源代码转换为AST,在执行速度上输给了JSHint,而JSHint 当时已经拥有完整的生态系统(编辑器支持)。真正让ESLint 流行起来的是ES6 的到来。
请参阅ES6 相关内容:《前端科普系列(1):前端简史》。
ES6 发布后,JSHint 由于添加了许多新语法,短时间内将无法提供支持,但ESLint 只需要一个合适的解析器,可以执行lint 检查。此时Babel提供了对ESLint的支持,并开发了babel-eslint,使ESLint成为支持ES6语法的最快的lint工具。
3.如何使用ESLint 既然了解了ESLint工具的历史意义和发展历程,那么我们就来看看如何使用ESLint。
1. 为您的项目安装ESLint。先决条件:Node.js (=6.14)、npm 版本3 或更高版本。
//创建一个新的demo项目目录并初始化npm项目。
npm 初始化
//安装eslint。我们建议将其安装为项目的开发依赖项。
npm i-D eslint
//初始化eslint配置文件。它没有全局安装,因此不能直接使用eslint --init 。
./node_modules/.bin/eslint --init
在初始化过程中,您将被要求做出几个配置选择,包括如何使用ESLint。选择第三个选项,因为它具有最多的功能。
当您选择每个ESLint 使用配置时,会在项目的根目录中生成一个.eslintrc.js 配置文件,并安装所需的npm 包。演示中安装的npm 软件包有:eslint-config-standard、eslint-plugin-import、eslint-plugin-node、eslint-plugin-promise、eslint-plugin-standard。
演示中的选择是:
初始化后生成的设置如下。具体设置项的含义将在后面解释。
//.eslintrc.js
模块. 导出={
env: {
es2020: 是的,
节点: 正确
},
扩展: [
'标准'
],
解析器选项: {
ecma版本: 11,
sourceType: '模块'
},
规则: {
}
}
需要强调的是,在选择编码风格时,我们选择了更通用的标准。 (标准链接:https://github.com/standard/standard/blob/master/docs/README-zhcn.md)
然后使用ESLint 检查并修复您的代码。首先,在演示项目中,创建一个新的src 目录,并创建一个新的Index.js 文件,其中包含以下内容:
//src/index.js
令a=10。
设b=15。
令总和=a + d。
控制台.log(总计);
同时在package.json中添加eslint命令eslint src/**来检查src目录下的所有文件。
//包.json
'脚本': {
'eslint': 'eslint src/**'
}
当我在demo 目录中运行npm run eslint 时,结果是:
正如你所看到的,检查了相当多的错误。除了样式之外,还包括标准规范中指定的规则,例如“let 必须替换为const”和“不能使用密封数字”。它还会检查语法错误,例如、 并一一提示。
如果我想自动修复检测到的问题怎么办?eslint 支持使用--fix 参数。将package.json 中的eslint 命令更改为eslint src/** --fix。
如果我再次运行npm run eslint,结果是:
如果打开src/index.js 文件,您将看到内容已更改。
//src/index.js
常数a=10
常数b=15
常数和=a + d
控制台.log(总计)
您会发现ESLint 会自动修复它可以修复的样式问题,并且还为它无法自动修复的问题提供提示。
更多关于eslint cli配置参数的信息,请参见官网的详细介绍(cli:https://cn.eslint.org/docs/user-guide/command-line-interface)。
至此,我们已经“挖了壕沟”,但河里没有水,敌人若来,我们可以畅通无阻。这完全依赖于开发者有意识地手动运行npm run eslint 来完成。那么“护城河”实际上是如何工作的呢?我们首先了解ESLint 的一般配置意味着什么,然后我们将在“如何维护优雅的护城河”中更详细地介绍它。
2. 常用配置规则初始化后,会在项目根目录下生成一个.eslintrc.js 文件,用于存放所有eslint 配置项。
模块. 导出={
env: {
es2020: 是的,
节点: 正确
},
扩展: [
'标准'
],
解析器选项: {
ecma版本: 11,
sourceType: '模块'
},
规则: {
}
}
(1)环境变量和全局变量
demo env 配置为相应的环境定义了一组预定义的全局变量。从前面的例子中我们了解到,ESLint 会检测未定义的变量并报告错误,但有些是执行环境或框架提供的全局变量,例如jQuery 提供的$ 。
在JavaScript 源代码文件中,使用以下格式的注释指定全局变量:/* global $ */
const dom=$('id')
要在配置文件中配置全局变量,请在包含要使用的每个全局变量的对象上设置全局配置属性。对于每个全局变量,将相应的键值设置为“可写”以允许重写变量,或设置为“只读”以不允许重写变量。例如:{
'全球': {
'$': '只读'
}
}
使用偏好。为了避免上述两种方案中逐一设置每个全局变量的麻烦,ESLint 预置了一大组环境全局变量。例如,如果你想使用jQuery提供的全局变量,你只需添加它们即可。在环境设置中设置jquery:true。 demo环境配置中,es2020:true表示添加es2020语法特性,node:true表示添加节点内所有全局变量。其他环境请参考官网《指定环境:https://cn.eslint.org/docs/user-guide/configuring#specifying-environments》相关章节。
(2).eslintrc.js中的扩展规则用于配置ESLint规则。具体配置规则请参考官网《如何配置规则:https://cn.eslint.org/docs/user-guide/configuring#configuring-rules》和《所有规则的说明:https://cn.eslint.org/docs/rules/》。同样为了方便,我这里就不详细解释了。 ESLint 使用高级设置来启用一组性别规则。例如,在演示中,通过extends 配置了一组符合标准的规则,因此该规则没有配置任何规则。
ESLint 支持三种类型的扩展:
以“eslint:”开头的官方ESLint 扩展。
包含eslint:推荐和eslint:全部。 eslint:recommished 是一组推荐规则,eslint:all 是ESLint 的所有规则,但不推荐,因为它们可以随时被ESLint 更改。
共享扩展。
通过npm 包提供一组共享配置。包名前缀必须是eslint-config-。 extends 属性值可以省略包名前缀eslint-config-。演示标准对应于package.json 中“eslint-config-standard”包提供的规则集。
由插件提供的扩展。
演示初始化后,您会注意到插件包(例如eslint-plugin-node)依赖于eslint-config-standard。这些插件包将自动安装。它还提供了一些扩展规则。
例如,以下代码在节点模块中被错误地编写,并且为了让ESLint 检测到此错误,您必须将eslint-plugin-node 包提供的规则添加到您的扩展中。
//src/index.js
导出={
foo: 1
}
//.eslintrc.js
扩展: [
'标准',
'plugin:node/推荐'
]
eslint-plugin-node 是默认安装的,因此对于已卸载的插件包,如果想使用它提供的规则,则不需要手动安装插件包。
(3) 在讨论上面的扩展时,我们已经提到了如何将扩展的配置加载到插件中。既然已经有这么多可用的扩展,为什么还需要插件呢?ESLint 在使用Vue 的单文件组件时无能为力,因为它只能检查标准的JavaScript 语法。目前,相应的框架提供了支持插件,可以自定义具体的检查规则。插件与扩展类似,有固定前缀eslint-plugin-。配置时也可以省略该前缀。
为Vue 添加了新的单文件组件:运行npm run eslint 后,我发现它没有任何效果,并且无法检查.vue 中的错误。此时,需要安装eslint-plugin-vue插件。 -在。
//src/index.vue
npm i-D eslint-插件-vue
安装后,在.eslintrc.js中配置插件。有两种方法。
使用plugins={配置module.exports
插件: ['vue']
}
配置完成后,执行npm run eslint,可以看到没有检查src/index.vue文件。可以看到plugins: ['vue']只是声明了eslint-plugin-vue提供的规则。但是需要在规则中一一指定哪些以及如何使用。因此,您通常使用第二种方法来配置您的插件。
带有扩展的配置。这是之前配置扩展的方法。模块. 导出={
extends: ['plugin:vue/推荐']
}
这样插件就会被加载,并且插件提供的规则也会被成功检查,如下图所示。
(4)解析器及其配置模块.exports={
解析器选项: {
ecma版本: 11,
sourceType: '模块'
}
}
demo中的parserOptions是一个解析器配置,默认只支持ES5语法,但是可以通过解析器配置来设置支持的ES版本。例如,演示中的ecmaVersion:11 表示支持ES11(以及ES2020)语法。这里需要注意的是,解析器设置仅支持语法。此版本中添加的新全局变量仍必须通过env 配置来支持。相关说明和详细的解析器设置请参考官网。解析器配置:https://cn.eslint.org/docs/user-guide/cconfiguring#specifying-parser-options)。
ESLint 默认使用(ESPree: https://github.com/eslint/espree) 作为解析器,但您可以通过parser 字段指定不同的解析器。指定解析器请参考官网。
**那么为什么需要指定解析器呢? **ESLint 的默认解析器只支持已经成为ES 标准的语法功能,因此它不支持实验性的或需要Babel 翻译的语法。语法(Flow、TypeScript 等)由@babel/Babel 提供。你会发现一般情况下不需要指定第三方解析器。
指定@babel/eslint-parser 作为ESLint 的解析器后,您开发的源代码首先会根据Babel 的配置转换为ESLint 支持的代码(参考《前端科普系列(4):Babel——把 ES6 送上天的通天塔》)。使用AST 并维护源代码行数和列数以帮助识别输出错误。指定@babel/eslint-parser 是不够的。解析器的唯一功能是将ESLint 不理解的语法特征转换为ESLint 理解的语法特征。然而,这也需要使用规则本身。如果您提供了@babel/eslint-plugin 插件,只有使用相应的规则,ESLint 才能成功检测到您的代码。
更多信息请参见官方文档(@babel/eslint-parser:https://github.com/babel/babel/tree/master/eslint/babel-eslint-parser)。
至此,总体配置已经介绍完毕。更多配置信息请参见ESLint官网文档:Configuring(ESLint:https://cn.eslint.org/docs/user-guide/cconfiguring)。
4.如何保护优雅的护城河如上所述,我们目前所做的只是“挖护城河”,但由于河里没有水,如果敌人想来,他们可以畅通无阻地穿过它。源代码发现完全依赖于开发人员有意识地手动运行npm run eslint。那么“护城河”实际上是如何运作的呢?
1.享受开发第一个要求是在开发过程中进行代码发现,而不是在代码开发完成后运行npm run eslint 并检查错误。此时,您可能已经有大量错误。
以VS Code编辑器为例(其他编辑器应该有类似的插件),安装ESLint扩展插件。该编辑器插件读取当前项目的.eslintrc.js 配置并显示不符合编辑器规则的错误。
首先,您会注意到有问题的文件在目录树中变成红色。当您点击该文件时,相应行上会显示错误消息,您可以轻松修复它。不过,聪明的同学可能已经注意到,npm run eslint不仅检测index.js中的错误,还检测index.vue中的错误,总共7个错误。编辑器仅检测index.js 中的错误。
事实证明,编辑器的ESLint插件默认只能检测.js文件。您需要调整编辑器的ESLint 插件的设置以支持.vue 文件的检测。
如图1所示:
找到插件的配置条目。添加对VUE 文件的支持是特定于项目的,并非所有项目都是VUE 项目,因此请在工作区中启用该设置。将vue 添加到Validata 配置。
正如你所看到的,index.vue 文件也变成了红色,我们也可以检测到其中的错误,并且项目中的所有七个错误都显示在编辑器的“问题”栏中。这与以下效果相同:运行npm 并运行eslint。这样,您在开发过程中会收到错误提示,但只需按照提示进行更改即可。但是,运行npm run eslint 会自动修复任何可以修复的问题,例如将let 更改为const。请等待这些问题。
那么,是否可以自动修复开发过程中检测到的错误呢?
一共有三个选项,您可以根据自己的喜好进行选择。
保存时自动修复设置。
显示VS Code 编辑器的命令面板,找到ESLint 插件提供的修复命令。
将ESLint 插件提供的修复命令设置为您首选的快捷键,然后使用该快捷键进行修复。我发现自动修复此时仅适用于Index.js 文件。同样,需要配置ESLint插件来支持Vue文件的自动修复。
2、将乐趣进行到底现在可以在开发过程中检测到错误,并让开发人员立即修复问题,但这取决于开发同学的意识。此时即使提交代码,如果向仓库提交错误的代码也会失败。这种情况下,需要使用husky拦截git操作,并在git操作之前再次运行代码检测。
huskinpm i -D 安装和配置husky
//包.json
{
'哈士奇': {
'挂钩': {
'预提交': 'eslint src/** --fix'
}
}
}
此时demo源代码有问题,未通过ESLint检查,所以提交前检查src下的所有文件。这可以防止开发人员忘记修复ESLint 检测到的问题。
对于较旧的项目,可能已经存在许多导致ESLint 检查失败的遗留样式问题。目前,不可能一一解决所有问题,阻止发送总会产生后果。此外,单次发送不需要每次都检查src 下的所有文件。因此,您应该使用lint 暂存工具来仅检测当前正在更改的部分。
lint-staged npm i -D 安装和配置lint-staged
//包.json
{
'哈士奇': {
'挂钩': {
'预提交': 'lint-staged'
}
},
'lint-staged': {
'*.{js,vue}': [
'eslint --修复',
“git 添加”
]
}
}
具体配置见(lint-staged:https://github.com/)
okonet/lint-staged) 官网文档。示例中配置表示的是,对当前改动的 .js 和 .vue 文件在提交时进行检测和自动修复,自动修复完成后 add 到 git 暂存区。如果有无法修复的错误会报错提示。 3、安装“黑匣子”飞机上都装有黑匣子,当出现故障时,可以很方便的回溯航行记录,发现问题。我们的代码仓库也一样,每次提交都应该有记录。但每个开发同学提交时输入的信息各不一样,没有统一的格式,导致后面回溯提交记录时眼花缭乱,效率很低。 接下来看下,如何约束提交,来守住优雅得提交日志这道大门。 commitizen是用来格式化 git commit message 的工具,它提供了一种问询式的方式去获取所需的提交信息。 cz-conventional-changelog是用来规定提交时需要输入哪些信息,譬如提交的类型是修复问题还是功能开发,提交影响范围等等,cz-conventional-changelog 是官网提供的规则,完全可以根据项目实际情况自已开发适合的规则。 standard-version提交信息并约束后,提交的日志信息就会比较统一,使用 standard-version 很容易自动生成提交的日志 CHANGELOG 文件。 安装并配置npm i -D commitizen cz-conventional-changelog standard-version //package.json { "scripts": { "c": "git-cz", "version": "standard-version" }, "standard-version": { "changelogHeader": "# Changelog\n\n所有项目的变更记录会记录在如下文件.\n", "dryRun": true }, "config": { "commitizen": { "path": "cz-conventional-changelog" } } } 配置完成后,使用 npm run c 来提交修改,会如现如下图所示的问询式的交互提示,根据规则要求填写对应的内容就好了。 通过此方式提交,提交的日志是格式统一的,然后就是使用 npm run version 来生成 CHANGELOG 文件了。 standard-version 会自动 bump 项目的版本号,并生成两个版本之间的提交日志记录文件,然后打个版本 tag 上传到仓库。更多关于 standard-version 的功能请参考官网文档(standard-version:https://github.com/conventional-changelog/standard-version)。 4、最后一道防线现在开发如果使用 npm run c 来提交修改,那么一切都会非常美好,可是万一开发忘了使用 npm run c 来提交修改,直接使用 git 命令,或者其它工具提交改动,怎么办?如何守好最后一道防线? 答案就是在提交时对提交信息进行校验,如果不符合要求就不让提交,并提示。校验的工作由(commitlint:https://github.com/conventional-changelog/commitlint)来完成,校验的时机则由husky来指定。(husky:https://github.com/typicode/husky#readme) 继承了 Git 下所有的钩子,在触发钩子的时候,husky 可以阻止不合法的 commit,push 等等。 安装并配置// 安装工具包 npm install --save-dev @commitlint/{config-conventional,cli} // 生成 commitlint 配置文件 echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js @commitlint/cli 用来执行检查,@commitlint/config-conventional 是检查的标准,即提交的信息是否符合这个标准的要求,只有符合要求才允许提交。 生成配置文件,指定要使用的规范,同时增加 husky 中的 'commit-msg' 钩子。配置完成后,再通过非 npm run c 途径的提交都会被拦截并报错。 // package.json { "husky": { "hooks": { "pre-commit": "lint-staged", "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } } } 错误提交时的校验 五、总结基于 ESLint ,我们成功化身为程序员界的‘革离’,守好了我们的战场,让属于我们的天空之城干净纯粹、整齐划一,在优雅里翱翔!