ESLint 检查代码质量

利用 ESLint 检查代码质量

其实很早的时候就想尝试 ESLint 了,但是很多次都是玩了一下就觉得这东西巨复杂,一执行检查就是满屏的error,简直是不堪入目,遂放弃。直到某天终于下定决心深入看了文档,才发现其实挺简单的,只是当时没有看到合适入门教程而已。我相信很多人也有着跟我一样的经历,所以希望将自己的踩坑心得记录下来,让后来者更轻易地掌握 ESLint 的使用,因为它确实是个好东西。

JavaScript 是一门神奇的动态语言,它在带给我们编程的灵活性的同时也悄悄埋下了一些地雷。除了基本的语法错误能在程序一启动的时候被检测到之外,很多隐含的错误都是在运行的时候才突然地蹦出来。除非你的程序有着 100% 的测试覆盖率,否则说不定哪天就会因为一个xxx is undefined而导致程序崩溃,而为了避免这样的错误可能你只需要在提交代码的时候用工具静态分析一下,仅此而已。

ESLint 是一个插件化的 javascript 代码检测工具,它可以用于检查常见的 JavaScript 代码错误,也可以进行代码风格检查,这样我们就可以根据自己的喜好指定一套 ESLint 配置,然后应用到所编写的项目上,从而实现辅助编码规范的执行,有效控制项目代码的质量。

手把手入门

在开始使用 ESLint 之前,我们需要通过 NPM 来安装它:

$ npm install -g eslint

我从 Gist 上找到了自己几年前写的一个小函数,将其保存为文件merge.js

function merge () {
  var ret = {};
  for (var i in arguments) {
    var m = arguments[i];
    for (var j in m) ret[j] = m[j];
  }
  return ret;
}

console.log(merge({a: 123}, {b: 456}));

然后执行node merge.js确保它是可以正确运行的(输出结果为{ a: 123, b: 456 })。

接着我们执行以下命令来使用 ESLint 检查:

$ eslint merge.js

可以看到,没有任何输出结果。这是因为我们没有指定任何的配置,除非这个文件是有语法错误,否则应该是不会有任何提示的。现在我们先使用内置的eslint:recommended配置,它包含了一系列核心规则,能报告一些常见的问题。

首先新建 ESLint 配置文件.eslintrc.js

module.exports = {
  extends: ‘eslint:recommended‘,
};

重新执行eslint merge.js可以看到输出了 2 个错误:

/example/merge.js
  10:1  error  Unexpected console statement  no-console
  10:1  error  ‘console‘ is not defined      no-undef

? 2 problem (2 error, 0 warnings)

这两条提示信息还是足够我们搞清楚是怎么回事的:

  • Unexpected console statement no-console - 不能使用console
  • ‘console‘ is not defined no-undef - console变量未定义,不能使用未定义的变量

针对第 1 条提示,我们可以禁用no-console规则。将配置文件.eslintrc.js改为这样:

module.exports = {
  extends: ‘eslint:recommended‘,
  rules: {
    ‘no-console‘: ‘off‘,
  },
};

说明:配置规则写在rules对象里面,key表示规则名称,value表示规则的配置,具体说明见下文。

重新执行检查还是提示no-undef

/example/merge.js
  10:1  error  ‘console‘ is not defined  no-undef

? 1 problem (1 error, 0 warnings)

这是因为 JavaScript 有很多种运行环境,比如常见的有浏览器和 Node.js,另外还有很多软件系统使用 JavaScript 作为其脚本引擎,比如 PostgreSQL 就支持使用 JavaScript 来编写存储引擎,而这些运行环境可能并不存在console这个对象。另外在浏览器环境下会有window对象,而 Node.js 下没有;在 Node.js 下会有process对象,而浏览器环境下没有。

所以在配置文件中我们还需要指定程序的目标环境:

module.exports = {
  extends: ‘eslint:recommended‘,
  env: {
    node: true,
  },
  rules: {
    ‘no-console‘: ‘off‘,
  },
};

再重新执行检查时,已经没有任何提示输出了,说明merge.js已经完全通过了检查。

配置文件

ESLint 还可以在项目的package.json文件中指定配置,直接将上文中的module.exports的值写到eslintConfig里面即可:

{
  "name": "my-package",
  "version": "0.0.1",
  "eslintConfig": {
    "extends": "eslint:recommended",
    "env": {
      "node": true
    },
    "rules": {
      "no-console": "off"
    }
  }
}

另外还可以在执行eslint命令时通过命令行参数来指定,详细文档可以参考这里:Configuring ESLint - 配置

规则

每条规则有 3 个等级:offwarnerroroff表示禁用这条规则,warn表示仅给出警告,并不会导致检查不通过,而error则会导致检查不通过。

有些规则还带有可选的参数,比如comma-dangle可以写成[ "error", "always-multiline" ]no-multi-spaces可以写成[ "error", { exceptions: { "ImportDeclaration": true }}]

规则的详细说明文档可以参考这里:Rules - 规则

使用共享的配置文件

上文我们以eslint:recommended为基础配置,然后在此之上修改no-console这条规则。而在大多数时候,我们可能会根据自己个人或团队的习惯,定制更多的规则,比如限定缩进是 2 个空格和使用单引号的字符串等。而如果每一个项目都要这样写到.eslintrc.js文件上,管理起来会比较麻烦。

我们可以将定义好规则的.eslintrc.js文件存储到一个公共的位置,比如public-eslintrc.js

module.exports = {
  extends: ‘eslint:recommended‘,
  env: {
    node: true,
  },
  rules: {
    ‘no-console‘: ‘off‘,
    ‘indent‘: [ ‘error‘, 2 ],
    ‘quotes‘: [ ‘error‘, ‘single‘ ],
  },
};

然后将原来的.eslintrc.js文件改成这样:

module.exports = {
  extends: ‘./public-eslintrc.js‘,
};

为了验证这样的修改是否生效,将merge.js中的var ret = {};这一行前面多加一个空格,再执行 ESLint 检查:

/example/merge.js
  2:4  error  Expected indentation of 2 space characters but found 3  indent

? 1 problem (1 error, 0 warnings)

这时候提示的是缩进只能为 2 个空格,而文件的第 2 行却发现了 3 个空格,说明公共配置文件public-eslintrc.js已经生效了。

我们还可以使用已经发布到 NPM 上的 ESLint 配置,这些配置的模块名一般以eslint-config-为前缀,比如我在学习 ESLint 时自己编写的一个配置名为eslint-config-lei。要使用这个配置,先执行以下命令安装它:

$ npm install -g eslint-config-lei

注意:由于我们的eslint命令是全局安装的,所有用到的eslint-config-*模块也必须全局安装,否则将无法正确载入。这是一个已知的 Bug,参考这里:Error: Cannot read config package for shareable config using global eslint #4822

然后将.eslintrc.js文件改成这样:

module.exports = {
  extends: ‘lei‘,
};

再执行 ESLint 检查,可以看到输出如下的提示:

/example/merge.js
   1:15  warning  Unexpected space before function parentheses  space-before-function-paren
   2:3   error    Unexpected var, use let or const instead      no-var
   3:8   error    Unexpected var, use let or const instead      no-var
   4:5   error    Unexpected var, use let or const instead      no-var
   5:10  error    Unexpected var, use let or const instead      no-var
  10:19  warning  A space is required after ‘{‘                 object-curly-spacing
  10:26  warning  A space is required before ‘}‘                object-curly-spacing
  10:29  warning  A space is required after ‘{‘                 object-curly-spacing
  10:36  warning  A space is required before ‘}‘                object-curly-spacing

? 9 problems (4 errors, 5 warnings)

ESLint 配置文件中的extends还可以用来指定各种来源的配置引用,具体说明可以参考以下链接:

代码格式化

ESLint 规则列表页面,我们发现有些规则的旁边会带有一个橙色扳手图标,表示在执行eslint命令时指定--fix参数可以自动修复该问题。

接着上文使用eslint-config-lei配置的检查,我们尝试在执行检查时添加--fix参数:

$ eslint merge.js --fix

执行完毕,没有发现任何提示。再打开merge.js文件发现已经变成了这样:

function merge() {
  const ret = {};
  for (const i in arguments) {
    const m = arguments[i];
    for (const j in m) ret[j] = m[j];
  }
  return ret;
}

console.log(merge({ a: 123 }, { b: 456 }));

主要的变化有以下三部分:

  • 声明函数时,函数名与参数列表的空格不见了:merge ()修改为merge()
  • var声明的变量变成了const声明:var ret = {}修改为const ret = {}
  • 对象的内容与花括号之间增加了空格:{a: 123}修改为{ a: 123 }

我们可以利用这个特性来自动格式化项目代码,这样就可以保证代码书写风格的统一。

发布自己的配置

前文关于「共享的配置文件」一小节已经提到,可以在extends中指定一个文件名,或者一个eslint-config-开头的模块名。为了便于共享,一般推荐将其发布成一个 NPM 模块。

其原理就是在载入模块时输出原来.eslintrc.js的数据。比如我们可以创建一个模块eslint-config-my用于测试。

新建文件eslint-config-my/index.js

module.exports = {
  extends: ‘eslint:recommended‘,
  env: {
    node: true,
    es6: true,
  },
  rules: {
    ‘no-console‘: ‘off‘,
    ‘indent‘: [ ‘error‘, 2 ],
    ‘quotes‘: [ ‘error‘, ‘single‘ ],
  },
};

再新建文件eslint-config-my/package.json

{
  "name": "eslint-config-my",
  "version": "0.0.1",
  "main": "index.js"
}

为了能让eslint正确载入这个模块,我们需要执行npm link将这个模块链接到本地全局位置:

$ npm link eslint-config-my

然后将文件.eslintrc.js改成这样:

module.exports = {
  extends: ‘my‘,
};

说明:在extends中,eslint-config-my可简写为my

在执行eslint merge.js检查,可看到没有任何错误提示信息,说明eslint已经成功载入了eslint-config-my的配置。如果我们使用npm publish将其发布到 NPM 上,那么其他人通过npm install eslint-config-my即可使用我们共享的这个配置。

另外可以参考我自己写的一个 ESLint 配置模块:eslint-config-lei

关于共享 ESLint 配置的详细文档可参考:Shareable Configs - 可共享的配置

例外情况

尽管我们在编码时怀着严格遵守规则的美好愿景,而凡事总有例外。定立 ESLint 规则的初衷是为了避免自己犯错,但是我们也要避免不顾实际情况而将其搞得太过于形式化,本末倒置。

ESLint 提供了多种临时禁用规则的方式,比如我们可以通过一条eslint-disable-next-line备注来使得下一行可以跳过检查:

// eslint-disable-next-line
var a = 123;
var b = 456;

在上面的示例代码中,var a = 123不会受到检查,而var b = 456则右恢复检查,在上文我们使用的eslint-config-lei的配置规则下,由于不允许使用var声明变量,则var b这一行会报告一个error

我们还可以通过成对的eslint-enableeslint-disable备注来禁用对某一段代码的检查,但是稍不小心少写了一个eslint-disable就可能会导致后面所有文件的检查都被禁用,所以我并不推荐使用。

详细使用方法可以参考文档:Disabling Rules with Inline Comments - 使用行内注释禁用规则

总结

刚开始接触 ESLint 时觉得太难,是因为过太过于迷信权威。比如 Airbnb 公司的 JavaScript 风格,在 GitHub 上受到了很大的好评,其实我自己也非常认可这样的编码风格。但每个团队都会根据自己的的实际情况来定制不同的东西,我们并不能随便照搬过来。所以当使用eslint-config-airbnb这个配置进行 ESLint 检查时,满屏都是errorwarning,从而觉得这东西根本没啥卵用。

另外我也犯了「大忌」:直接使用eslint-config-airbnb这种某个公司高度定制化的配置,而不是eslint:recommended这样保守的。而且是直接用来检查整个项目好几十个 JS 文件,可想而知那是怎样的画面(本文最后版本的merge.js文件使用airbnb的配置,总共 12 行的代码就提示了 8 个问题:? 8 problems (7 errors, 1 warning))。

本文的目的是让读者以一个比较低的姿态开始接触 ESLint,先学会简单地配置规则,如果要更深入地定制自己的规则,建议阅读「相关链接」中的 ESLint 文档。

相关链接

关于作者

老雷 : Web开发者、 一登后端架构师、 《Node.js实战》作者之一
个人主页: http://ucdok.com
GitHub: https://github.com/leizongmin

时间: 2024-10-23 14:22:04

ESLint 检查代码质量的相关文章

使用eslint检查代码质量

1.安装 全局安装 npm install eslint -g 局部安装 npm install eslint --save 2.初始化一个配置文件 eslint --init 执行后根据项目需要回答几个问题,最后会在根目录生成一个.eslintrc.js文件: module.exports = { "env": { "browser": true, "es6": true }, "extends": "eslint

IDEA中关闭sonar代码质量检测

笔者在IDEA中禁用了SonarLint等各种配置,还是无效,后来在网上找到说是插件的bug, There was a bug in SonarLint for IntelliJ that prevented the configuration to be properly saved. It was fixed in the latest version 2.3.2: https://jira.sonarsource.com/browse/SLI-106 About the performan

提高php代码质量 36计

1.不要使用相对路径 常常会看到: ? 1 require_once('../../lib/some_class.php'); 该方法有很多缺点: 它首先查找指定的php包含路径, 然后查找当前目录. 因此会检查过多路径. 如果该脚本被另一目录的脚本包含, 它的基本目录变成了另一脚本所在的目录. 另一问题, 当定时任务运行该脚本, 它的上级目录可能就不是工作目录了. 因此最佳选择是使用绝对路径: ? 1 2 3 4 define('ROOT' , '/var/www/project/'); re

如何提高C#代码质量

本文将<Effective C# Second Edition>一书中适用于 Unity 游戏引擎里使用 C# 的经验之谈进行了提炼,总结成为21条(一开始总结的是22条,后来发现第22条也是.NET的特性,Unity版本的mono并没有实现,所以严格意义上来说是21条)准则,供各位快速地掌握这本书的知识梗概,在 Unity 中写出更高质量的 C# 代码. <Effective C# Second Edition>一书原本有50条原则,但这50条原则是针对C#语言本身以及.NET来

追求代码质量: 用 AOP 进行防御性编程

原文出处: IBM中国 开发人员测试的主要缺点是:绝大部分测试都是在理想的场景中进行的.在这些情况下并不会出现缺陷 —— 能导致出现问题的往往是那些边界情况. 什么是边界情况呢?比方说,把 null 值传入一个并未编写如何处理 null 值的方法中,这就是一种边界情况.大多数开发人员通常都不能成功测试这样的场景,因为这没多大意义.但不管有没有意义,发生了这样的情况,就会抛出一个 NullPointerException,然后整个程序就会崩溃. 本月,我将为您推荐一种多层面的方法,来处理代码中那些

Findbug在项目中的运用--提高代码质量

 FindBugs是一个静态分析工具,它检查类或者 JAR文件,将字节码与一组缺陷模式进行对比以发现可能的问题.有了静态分析工具,就可以在不实际运行程序的情况对软件进行分析 第一 手动安装 在Eclipse点击菜单中Help-->菜单 第二:输入地址: http://findbugs.cs.umd.edu/eclipse,出现版本列表: 按照一步步提示安装重启即可 =================================================== 2) (Re-)star

MDU某产品OMCI模块代码质量现状分析

说明 本文参考MDU系列某产品OMCI模块现有代码,提取若干实例以说明目前的代码质量. 本文旨在就事论事,而非否定前人(没有前人的努力也难有后人的进步).希望以史为鉴,不破不立,最终产出高质量的代码. 一  质量现状 不考虑业务实现,现有的OMCI模块代码质量不甚理想.无论是理解上手.修改扩展和测试排障,可以用举步维艰形容.尤其是二层通道计算相关代码,堪比令史前动物无法自拔的"焦油坑". 本节将不考虑流程设计,仅就函数粒度列举目前存在的较为突出的代码质量问题. 1.1 巨型函数 通过S

第01篇 提高代码质量插件

我使用插件对我的代码进行分析,我这里使用的checkStyle的插件,还有很多其他的插件,用了一个,其他都差不多,还有一个PMD的插件, 一直重来没有注重代码规范,所以这里我开始注意 第一步:安装CheckStyle插件 ? ? ? ? 出现如下窗口之后,选择ADD ? ? ? ? 之后,Namd的名称一般都是插件名称,路径为下载路径 直接update, 添加更新源地址:http://eclipse-cs.sf.net/update/, 也可以从http://sourceforge.net/pr

团队代码中Bug太多怎么办?怎样稳步提高团队的代码质量

最近负责的Android APP项目,由于团队成员变动.界面改版导致代码大幅修改等原因,产品发布后屡屡出现BUG导致的程序崩溃. 经过对异常统计和代码走读,BUG主要集中在空指针引起的NullPointerException和RuntimeException异常,这也是Android项目中最容易导致崩溃的根源. 导致这些BUG的原因主要是: 1.对项目架构不熟悉,缺乏整体思考: 2.写代码逻辑不周密,思考不全面: 3.对代码的BUG和程序的稳定性重视不足: 4.项目较为复杂,多界面跳转.数据结构