本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
背景
之前公司几个项目都配置了Sonar扫描平台,扫出来了很多Code规范问题,发文记录下解决此类问题的心得。
Sonar是一个开源平台,用于管理源代码的质量。一般用于扫描一个项目中所有代码的质量、规范、漏洞等问题。官网:www.sonarsource.com
想扫描代码得配置Sonar环境,一般分为SonarQube
和SonarCloud
,具体怎么配置笔者没用研究过,公司用到的是打包部门已经配置好的环境,配置上对应项目的git地址等,就可以做到自动化clone git、扫描、出report等。
以一个官方的项目为例:sonarcloud.io/project/ove… ,这是一个vscode-python
项目的SonarCloud
扫描结果report,点开Main Branch -> Issues会显示当前代码中被扫出来的问题,包括文件名、哪行出错、Rule规则等,也可以根据 Type
、Severity
、Language
、Rule
来过滤。
然后项目开发这边就可以根据report来修复issues,分为以下三类:
- Bug:可能会导致bug的Code。
- Vulnerability:存在安全隐患,一般是第三方版本过低或存在漏洞等。
- Code Smell:指可疑的Issues,不规范的代码。这主要是一个和维护性相关的指标,重点的含义是保持这样的代码,会导致代码维护成本越来越高,时间长了会导致很多无法理解的代码留存在项目中,从而可能会引起一些缺陷。
前两个Bug
Vulnerability
优先级比较高,如果一个项目的Issues过多,一般选择只修复这两种优先级高的Issues。
跟前端相关的Sonar rules大概有以下这些,具体还得看对应SonarQube
或SonarCloud
项目中配置了哪些Rules:
- All:rules.sonarsource.com
- javascript: rules.sonarsource.com/javascript
- typescript: rules.sonarsource.com/typescript
- css: rules.sonarsource.com/css
点击对应Rule可以查看Type
、Level
、详细规则等。
本文主要是以开发角度,来通过一些辅助工具提前解决前端code相关Issues,有效降低后期处理Sonar issues带来的开发维护成本。
关于Sonar环境安装、部署、配置、扫描等应该是打包或者运维部门的工作,此文不涉及。也不会具体分析每个Rule怎么改,大部分规则都很简单,仔细看下都能看懂。
通过ESLint来修复Sonar issues
ESLint 是一个开源的 JavaScript 代码检查工具,用来检查你的代码是否符合指定的规范。可以配合VSCode等IDE插件自动扫描提示,方便在写code过程中发现,有些Rules也支持autofix,可以在保存文件时自动修复。
关于ESLint详细用法,会在下一篇文章里讲解,包括指令、autofix、结合git commit等等。
Sonar扫描其实也是官方列出了一些 Rules,然后个人或者公司把这些Rules配置在自己的SonarQube
或SonarCloud
项目里,其中有很多Rules是跟ESLint官方Rules是等价的,也有些可以通过Sonar官方出的eslint-plugin-sonarjs
来扫描。
下面主要介绍ESLint中哪些Rules可以用来替代sonar对应Rules,以便更好更快的修复Sonar问题。本文主要以笔者做过的相关项目为例,列举一些经常被扫出来的Rules,相关项目都是React框架、JS语言开发(没用Typescript)。
ESLint官方Rules
配置ESLint时,一般会启用推荐的规则 "extends": "eslint:recommended"
,即文档中标记✅号的Rules。里面有些Rules包含了Sonar rules,建议启用,这里就不具体查哪些Rules了。
有些不在recommended
推荐规则里的Rules,需要手动将对应Rules配置在项目.eslintrc.js
里,具体总结在下面:
-
eslint: no-unused-vars
"no-unused-vars": ["error", { "args": "none", "caughtErrors": "none", "ignoreRestSiblings": true, "vars": "all" }]
- 禁止未使用过的变量。删除未使用过的变量,暂不限制方法参数。
- sonar rule: Unused assignments should be removed
- Type:
Code Smell
Level:Major
- 开发前期有些变量可能留着还有用,可以先设置为warn,然后后期再设置为error,即强制修复。
-
eslint: array-callback-return
"array-callback-return": ["error", { "allowImplicit": false, "checkForEach": false }]
- sonar rule: Return values from functions without side effects should not be ignored
- sonar rule: Callbacks of array methods should have return statements
- Type:
Bug
Level:Major
Blocker
-
eslint: no-unused-expressions
"no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }]
- 覆盖的不是很完整,有些issue扫不出来。
- sonar rule: Non-empty statements should change control flow or have at least one side-effect
- Type:
Bug
Level:Major
-
eslint: default-param-last
"default-param-last": "error"
- 强制function默认参数为最后一个参数。
- sonar rule: Function parameters with default values should be last
- Type:
Code Smell
Level:Major
-
eslint: radix
"radix": "error"
- sonar rule: The base should be provided to "parseInt"
- Type:
Bug
Level:Minor
-
eslint: eqeqeq
"eqeqeq": ["error", "always", { "null": "ignore" }]
- sonar rule: "===" and "!==" should be used instead of "==" and "!="
- Type:
Code Smell
Level:Major
-
eslint: eol-last
"eol-last": "error"
- sonar rule: Files should contain an empty newline at the end
- Type:
Code Smell
Level:Minor
-
eslint: guard-for-in
"guard-for-in": "error"
- sonar rule: 记得有这个Rule,link找不到了
eslint-plugin-sonarjs
SonarSource
官方出的eslint plugin插件,内部封装了一些ESLint自定义Rules,文档:github.com/SonarSource…
用法很简单:
npm install eslint-plugin-sonarjs --save-dev
.eslintrc.js
文件中添加plugin{ "plugins": ["sonarjs"] }
- 配置
"extends": ["plugin:sonarjs/recommended"]
,或者具体Rules。
推荐的recommended
中几乎包含了sonarjs plugin
中所有的rules,除了两个标记disabled
的rule。如果你想严格规范所有的Rules,可以配置recommended
;但如果只想对于其中一部分严重的Rules进行处理,建议不用recommended
,自行配置具体Rules。下面举例比较常见的、严重的Rules:
-
sonarjs: sonarjs/no-all-duplicated-branches
"sonarjs/no-all-duplicated-branches": "error"
- sonar rule: All branches in a conditional structure should not have exactly the same implementation
- Type:
Bug
Level:Major
-
sonarjs: sonarjs/no-identical-expressions
"sonarjs/no-identical-expressions": "error"
- 不应该在二元运算符的两端使用相同的表达式。
- sonar rule: Identical expressions should not be used on both sides of a binary operator
- Type:
Bug
Level:Major
-
sonarjs: sonarjs/no-extra-arguments
"sonarjs/no-extra-arguments": "error"
- 调用函数不应该传递额外的参数。
- sonar rule: Function calls should not pass extra arguments
- Type:
Bug
Level:Critical
-
sonarjs: sonarjs/no-use-of-empty-return-value
"sonarjs/no-use-of-empty-return-value": "error"
- sonar rule: The output of functions that don't return anything should not be used
- Type:
Bug
Level:Major
-
sonarjs: sonarjs/no-collapsible-if
"sonarjs/no-collapsible-if": "error"
- 合并可折叠if语句可以提高代码的可读性。
- sonar rule: Collapsible "if" statements should be merged
- Type:
Code Smell
Level:Major
-
sonarjs: sonarjs/no-duplicated-branches
"sonarjs/no-duplicated-branches": "error"
- 条件结构中的两个分支不应该具有完全相同的实现。
- sonar rule: Two branches in a conditional structure should not have exactly the same implementation
- Type:
Code Smell
Level:Major
-
sonarjs: 其它不常遇到rules:Bug Detection 🐛 中列举的所有Bug类型的Rules。
其它
eslint-config-sonar
一个封装好的eslint config extends,内部利用no-wildcard-postmessage
filenames
sonarjs
三个plugin,然后配置对应具体的Rules,来解决Sonar issues。
思路跟上面一样,但是更具体详细些,不过Star比较少,建议可以用来参考。具体Rules:github.com/penx/eslint…
SonarLint
官方提供的IDE插件,大多IDE都支持 www.sonarsource.com/products/so…
尝试用了下VSCode的插件,可以正确在Code里识别出来error(安装后反应会慢一些,稍等一会就会出来),也可以打开对应Rule详情,跟ESLint插件很像,但是没找到像ESLint那样可以通过指令扫描整个项目的功能,也不支持通过配置文件配置具体Rules,虽然可以通过extension settings
配置,但只能在global下设置,不能设置在workspace下,就不能规范整个项目团队了。可能其它IDE支持的更好,或者是我哪块没用明白,有需要的可以试试。
插件还有个功能,可以通过配置连接自己SonarQube
和SonarCloud
项目的信息,然后插件会把项目里的配置、rules和issues等同步到VSCode里,具体没试过。
总结
本文主要介绍了如何利用ESLint快速高效解决Sonar Issues,如何有效降低后期处理Sonar issues带来的开发维护成本。
一般步骤如下:
- 首先看Sonar扫描的情况,如果Issues较多,可以优先解决
Bug
Vulnerability
两种isues,Code Smell
可以根据Rule尽量减小个数。 - 然后根据扫描出来的Rules,来配置针对性的ESLint rules,然后让开发团队保证自己的Code没有ESLint error。
- 同时分析无法通过ESLint扫描的issues,可以团队内部制定相关Code规范,执行下去。
- 以上执行差不多时,再看下剩余的issues,此时个数不会太多,而且都是比较分散的,然后针对性的采取assign to的方式把task分下去依次解决。
通过笔者最近做过的项目来看,ESLint能覆盖大概90%的Sonar issues,效果还是很可观的,并且ESLint rules一旦配置好了,之后的项目开发和维护时,会很好的稳定Sonar issues数量,不会出现突然较多issues产生的情况。
另外,有些项目SonarQube
report中,集成了Dependency-Check功能,会扫出来有些第三方文件或者npm包的version漏洞问题(笔者就有,不确定是否跟Sonar有关)这个会在之后文章里讲解。
Code
最后share下项目里ESLint配置源码:
// .eslintrc.js
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 13,
"sourceType": "module"
},
"plugins": [
"react",
"sonarjs"
],
"settings": {
react: {
version: "18.x"
}
},
"globals": {
},
"rules": {
// eslint rules for sonar
"no-unused-vars": ["error", { "args": "none", "caughtErrors": "none", "ignoreRestSiblings": true, "vars": "all" }],
"array-callback-return": ["error", { "allowImplicit": false, "checkForEach": false }],
"no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }],
"default-param-last": "error",
"radix": "error",
"eqeqeq": ["error", "always", { "null": "ignore" }],
"eol-last": "error",
"guard-for-in": "error",
// sonarjs plugin 目前配置的是所有支持的Bug类型Rules:https://github.com/SonarSource/eslint-plugin-sonarjs
"sonarjs/no-all-duplicated-branches": "error",
"sonarjs/no-element-overwrite": "error",
"sonarjs/no-empty-collection": "error",
"sonarjs/no-extra-arguments": "error",
"sonarjs/no-identical-conditions": "error",
"sonarjs/no-identical-expressions": "error",
"sonarjs/no-ignored-return": "error",
"sonarjs/no-use-of-empty-return-value": "error",
"sonarjs/non-existent-operator": "error",
"sonarjs/no-collapsible-if": "error",
"sonarjs/no-duplicated-branches": "error",
// "sonarjs/no-one-iteration-loop": "error", // 加上后eslint scan就抛错了,原因未知
}
};