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.
代码检查很重要,原因有三:
- 避免低级bug:一些常见代码问题,如果在编译或运行前不能及时发现,代码中的语法问题会直接导致编译或运行时错误,影响开发效率和代码质量;
- 统一代码习惯:每一个团队或个人都会有一些代码规范或者代码习惯,为了便于后期维护和阅读,我们编写的代码也需要符合一定的格式规范;
- 保证线上代码质量:在版本管理中,我们需要在提交或发布之前自动执行一些代码检查工作,确保我们的代码符合最终版本要求。
通常,代码编辑器(或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种格式的配置文件,其使用的优先级和说明如下:
- .eslintrc.js:模块定义,export的对象即为配置对象
- .eslintrc.yaml:yaml语法
- .eslintrc.yml:yaml语法
- .eslintrc.json:JSON语法
- .eslintrc:兼容yaml和JSON语法
- 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/0
、warn/1
、error/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/0
、warn/1
、error/2
,格式如下:
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进行修改。
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来跳过检查)