说一说前端代码检查

2019-12-04 09:59:03 浏览数 (1)

本文作者:IMWeb Terrance 原文出处:IMWeb社区 未经同意,禁止转载 In computer programming, lint was the name originally given to a particular program that flagged some suspicious and non-portable constructs (likely to be bugs) in C language source code. The term is now applied generically to tools that flag suspicious usage in software written in any computer language.

代码检查很重要,原因有三:

  1. 避免低级bug:一些常见代码问题,如果在编译或运行前不能及时发现,代码中的语法问题会直接导致编译或运行时错误,影响开发效率和代码质量;
  2. 统一代码习惯:每一个团队或个人都会有一些代码规范或者代码习惯,为了便于后期维护和阅读,我们编写的代码也需要符合一定的格式规范;
  3. 保证线上代码质量:在版本管理中,我们需要在提交或发布之前自动执行一些代码检查工作,确保我们的代码符合最终版本要求。

通常,代码编辑器(或IDE)的插件会帮我们做一些静态语法检查的工作,但是如何自定义语法规则,如何集成到开发流程中,仍然需要我们花一些时间去了解。

这里主要针对前端领域的js、css代码静态分析来进行总结。

ESLint

In order to help people write standard-compliant code from the start and avoid wasting time during code reviews, a set of ESLint configuration files have been added to the code base so that JavaScript can be analyzed automatically.This automatic linting can happen either while coding, in a code editor, or when using the command line.

提到ESLint,你大概会想到JSLint、JSHint或者JSCS,那么他们有什么区别呢?

  • JSLint是其中最老的工具。它根据作者的经验,定义了一套js规则,但用户无法更改或拓展这些规则,只能被迫接受,而且报错也不够友好;
  • JSHint在JSLint的基础上进行了一些改进,用户可以更改规则,但仍然不能自定义新的规则,而且存在强制和分散两种模式,配置十分混乱;
  • JSCS开始支持自定义规则和插件,报错定位也更加准确,但仅仅支持代码风格的检查,无法检查出一些简单的潜在bug;
  • ESLint是最新出来的工具,它被设计的容易拓展、拥有丰富的可自定义规则和插件、支持ES6和JSX,另外输出也更加友好。

使用方法如下:

代码语言:javascript复制
eslint foo.js

foo.js
  0:0  warning  File ignored because of your .eslintignore file. Use --no-ignore to override.
✖ 1 problem (0 errors, 1 warning)

安装

因为ESlint被实现为一个npm包,我们可以选择局部或全局方式进行安装。

安装之后,可以执行eslint --init来生成一个默认的配置文件.eslintrc

注意:如果ESlint使用到了相关插件和共享配置文件,也必须安装在本地。

文件配置

包括之前提到的.eslintrc文件,ESlint共支持6种格式的配置文件,其使用的优先级和说明如下:

  1. .eslintrc.js:模块定义,export的对象即为配置对象
  2. .eslintrc.yaml:yaml语法
  3. .eslintrc.yml:yaml语法
  4. .eslintrc.json:JSON语法
  5. .eslintrc:兼容yaml和JSON语法
  6. package.json: 在package.json的eslintConfig字段中定义

1.parserOptions

我们可以在这里开启对JSX语法的支持,但请注意这并不代表支持React语法,在React项目中应该使用eslint-plugin-react插件。

代码语言:javascript复制
"parserOptions": {
    "ecmaVersion": 6, // ES6,等同于2015
    "sourceType": "module", // 使用ES的模块机制,而不是nodejs的
    "ecmaFeatures": { // 拓展语言特性
        "jsx": true //支持JSX语法
    }
}

2.parser

常用的解析器有espree、Babel-ESLint、esprima。

3.env

支持25种运行环境,每一个环境都定义了一套预置全局对象,不同的环境可以组合使用。

3.globals

定义一组全局对象,可以制定其是否可写(默认true),注意需要开启no-global-assign规则来使false值生效。

4.plugins

每一个ESlint插件都是一个npm包,命名以“eslint-plugin-”开头,如eslint-plugin-react@jquery/eslint-plugin-jquery,插件中可以定义Rules、Env、Configs和Testing等。如果要创建一个plugin,推荐使用Yeoman的generator-eslint

5.extends

扩展的使用方式主要有如下几种:

  • "eslint:recommended":开启推荐rule
  • "eslint:all":开启全部rule
  • "plugin:react/recommended":使用react插件中recommended配置的rule
  • "./node_modules/coding-standard/.eslintrc-jsx":使用自定义的配置文件

6.rules

对每条rule的错误处理,分为三种off/0warn/1error/2

ESLint将Rule分为以下几类:

  • Possible Errors
  • Best Practices
  • Strict Mode
  • Variables
  • Node.js and CommonJS
  • Stylistic Issues
  • ECMAScript 6
  • Deprecated
  • Removed

配置文件中rules的写法是<规则名称>:<处理级别>,<传入参数>,举个栗子:

代码语言:javascript复制
"rules": {
    // enable additional rules
    "indent": ["error", 4],
    "linebreak-style": ["error", "unix"],
    "quotes": ["error", "double"],
    "semi": ["error", "always"],

    // override default options for rules from base configurations
    "comma-dangle": ["error", "always"],
    "no-cond-assign": ["error", "always"],

    // disable rules from base configurations
    "no-console": "off",
}

具体可参考规则文档

7.settings

考虑到不同的rule可能会存在一些公共部分,我们可以在这里进行集中定义,便于后期维护,举个栗子:

代码语言:javascript复制
"settings": {
    "sharedData": "Hello"
}

8.overrides

在这里,我们可以使用glob规则来定义哪些文件(不)需要使用eslint来进行静态代码分析,另外几乎所有的配置项都可以在这里定义,并且拥有最高优先级。

代码语言:javascript复制
"overrides": [
    {
      "files": [ "bin/*.js", "lib/*.js" ],
      "excludedFiles": "*.test.js",
      "rules": {
        "quotes": [ 2, "single" ]
      }
    }
  ]

9.root

定义配置文件所在目录是否为根目录,Boolean类型,如果为true,则不再使用上层中的ESLint配置文件,举个栗子:

代码语言:javascript复制
home
└── user
    ├── .eslintrc <- Always skipped if other configs present
    └── projectA
        ├── .eslintrc  <- Not used
        └── lib
            ├── .eslintrc  <- { "root": true }
            └── main.js

.eslintignore

放置位置同.eslintrc文件,定义了哪些文件需要忽略,取消忽略某个文件在前面添加!另外也可以直接在package.json中的eslintIgnore属性中进行配置。

注释配置

除了可以在配置文件中定义规则,还可以在代码中添加注释的方式进行灵活的规则变更,直接看栗子吧:

代码语言:javascript复制
/* eslint-env node, mocha */
/* global var1:false, var2:false */
/* eslint quotes: ["error", "double"], plugin1/rule1: 2 */

/* eslint-disable */
alert('foo');
/* eslint-enable */

/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');
/* eslint-enable no-alert, no-console */

alert('foo'); // eslint-disable-line
// eslint-disable-next-line
alert('foo');

alert('foo'); // eslint-disable-line no-alert, quotes, plugin1/rule1
// eslint-disable-next-line no-alert, quotes, plugin1/rule1
alert('foo');

命令行

命令行参数说明

常用的命令行如下:

代码语言:javascript复制
// 指定配置文件
eslint --config ~/my-eslint.json file.js
// 关闭配置文件
eslint --no-eslintrc file.js
// 指定运行环境
eslint --env browser,node file.js
// 指定需要进行代码检查的文件后缀
eslint . --ext .js --ext .JSX
// 定义全局变量
eslint --global require,exports:true file.js
// 将stdin作为代码源,指定解析器
echo '3 ** 4' | eslint --stdin --parser-options=ecmaVersion:7
// 使用缓存,指定缓存文件位置
eslint "src/**/*.js" --cache --cache-location "/Users/user/.eslintcache/"
// 指定插件
eslint --plugin eslint-plugin-mocha file.js
// 关闭warning输出
eslint --quiet file.js
// 指定报告输出文件
eslint --output-file ./test/test.html
//修复部分问题
eslint --fix

规则优先级

优先级:注释配置 > 命令行配置 > 文件配置

工具集成

  • 编辑器:Sublime Text 3、Atom、Visual Studio Code...
  • 构建工具:Webpack、Gulp、Browserify...
  • 测试工具:Mocha..
  • 源代码控制:Git Hook..
  • 规则扩展:AngularJS、React、BackboneJS...

SassLint

sass声称是世界上最成熟、稳定和强大的专业级CSS扩展语言,随着其语法规则的丰富,书写sass出错的概率也会随之增大,下面针对sass的代码检查工具——SassLint进行介绍。

安装

SassLint同样被实现为一个npm包,我们可以选择局部或全局方式进行安装。

文件配置

  • 使用配置文件.sass-lint.yml
  • 使用package.json的"sasslintConfig"字段

1.Options

  • cache-config: 用于性能提升
  • config-file: 指定加载另一个配置文件
  • formatter:定义warnings/errors的格式
  • merge-default-rules:自定义规则
  • output-file:制定结果输出文件路径

2.Files

使用glob规则定义哪些文件需要进行代码检查,举个栗子:

代码语言:javascript复制
files:
  include: 'sass/**/*.s (a|c)ss'
  ignore:
    - 'sass/vendor/**/*.scss'
    - 'sass/tests/**/*.scss

3.Rules 对每条rule的错误处理,同样分为三种off/0warn/1error/2 ,格式如下:

代码语言:javascript复制
rules:
  indentation:
    - 2
    -
      size: 2

规则文档

注释配置

和ESLint差不多,直接看栗子吧:

代码语言:javascript复制
// sass-lint:disable border-zero
p {
  // sass-lint:disable-block border-zero
  border: none;
  content: "hello"; // sass-lint:disable-line quotes
}
// sass-lint:enable border-zero

// sass-lint:disable-all
a {
  border: none; // Failing result reported
}
// sass-lint:enable-all

命令行

命令行参数说明

这里唯一需要特别注意的两个地方是:

  • 默认不显示warning错误,需要用—verbose参数来修改;
  • 遇到error时默认直接退出,无法看到所有的error错误,需要用--no-exit进行修改。
代码语言:javascript复制
sass-lint --config app/config/.sass-lint.yml '**/*.scss' --verbose --no-exit --ignore 'tests/**/*.scss, dist/other.scss'

工具集成

  • 编辑器:Sublime Text、Atom、Visual Studio Code...
  • 构建工具:Gulp、Grunt...

一点心得

1.如何在一个项目中引入一套ESLint或SassLint?

首先可以多了解一些被共享出来的成熟ESLint或SassLint标准、插件包等,根据团队或着自己的需要进行一定的修改,如果规则或应用场景比较复杂,可以考虑另外开发插件包。

2.如何平衡文件配置和注释配置?

文件配置往往是团队共同商讨制定出来的,凝聚了大多数人的智慧,所以原则上应该遵守这些规则,尽量不要在代码中添加注释配置。当这些规则无法满足当前的代码需要时,可以使用注释配置进行局部修改,但禁止对整个文件进行忽略。在问题积累得比较多的时候,可以在团队中提出来,集中修改插件或配置文件。

3.如何保证提交到版本库中的代码都通过了静态代码分析?

如果使用Git,那么Git Hook会是一个非常好的选择,可以定义在执行commit、push等操作的时候执行一些lint检查,如果存在error则禁止代码提交或上传。(不过个人仍然可以显示地用--no-verify来跳过检查)

0 人点赞