前端代码乱糟糟?是时候引入代码质量检查工具了
Posted 前端儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端代码乱糟糟?是时候引入代码质量检查工具了相关的知识,希望对你有一定的参考价值。
为了统一团队的代码规范,除了一纸规范说明之外,还需要引入工具进行限制。虽说工具并不能完全实现规范中的规则,但至少能够在一定程度上缓解代码不统一的局面。
相对于后端,前端代码规范的质量检查涉及到html, CSS,javascript ,如今还涉及到SCSS,ES5,JSX, React,Vue,Angular等,更是复杂。
本文提供了在检查工具方面的规则制定,在编辑器IDE中进行配置,在webpack中进行打包。让开发小伙伴有所参考
相关规则可以在 webpack4项目demo 中看到,里头放了相关的规则链接注释,欢迎围观~
1. 工具选取
笔者对常见的代码检查工具做了一番调研,结合规则支持度,配置方式,在编辑器Sublime于Webstrom这只IDE上的支持度,在webpack打包的支持,最终确立了使用如下方案
HTML / tpl: HTMLHint
CSS / SCSS: StyleLint
JS / JSX: ESLint
对比参考: JavaScript 代码静态质量检查 CSS 代码静态质量检查 HTML代码风格检查工具对比
尽管如此,这三个插件也并不完美,有太多太多的坑踩遍了,如果你有更合适的套件,欢迎建议~
2. 规则制定
选取了工具之后,就需要确立相应的规则。
规则非常多,对我们这种没经验的小白是不可能一条一条自主去选取的,所以需要依据某些参考。但也只能是参考,我们需要把这些通用的设置,结合到我们实际项目中,并一条条去了解规则,最终选出并摘录进我们的规则集中。
ESLint规则
// 自定义的规则
rules: {
// 必须使用 === 或 !==,禁止使用 == 或 !=,与 null 比较时除外
// @warn 在异步接口返回时不确定参数是数值还是字符串,有时可利用这个类型转换
'eqeqeq': 'warn',
// 禁止在 if 代码块内出现函数声明
// @off 在for循环中会经常使用定义var for(var i = 0; i < 10; ++i)
'no-inner-declarations': 'off',
// switch 的 case 内有变量定义的时候,必须使用大括号将 case 内变成一个代码块
// @off 太严格
'no-case-declarations': 'off',
// 禁止使用 !! ~ 等难以理解的运算符
// @off 有些时候会用到 if (!!abc) '' + 100 +new Date() 等
'no-implicit-coercion': 'off',
// 禁止在全局作用域下定义变量或申明函数
// @off 太严格
'no-implicit-globals': 'off',
// 禁止使用没必要的 {} 作为代码块
// @off 有时候需要用代码块做逻辑区分
'no-lone-blocks': 'off',
// 禁止出现 location.href = 'javascript:void(0)';
// @off 有时候需要用便捷的 javascript:;
'no-script-url': 'off',
// 对象字面量只有一行时,大括号内的首尾必须有空格
// @off 没有必要限制
'object-curly-spacing': 'off',
// 禁止对函数的参数重新赋值
// @warn 警示即可
'no-param-reassign': 'warn',
// 文件最后一行必须有一个空行
// @error 应该在文件末尾保持一个换行
'eol-last': 'error',
// 代码块嵌套的深度禁止超过 10 层
// @warn 有些特殊情况会出现 警示即可
'max-depth': [
'warn',
],
// 禁止函数的循环复杂度超过 100
// @error 最大值可以宽松点
'complexity': [
'error',
{
max: 100
}
],
// 定义过的变量必须使用
// @warn 多文件互相引用时 偶尔会出现无引用的情况
'no-unused-vars': [
'warn',
{
vars: 'all',
args: 'none',
caughtErrors: 'none',
ignoreRestSiblings: true
}
],
// 在ES5中需使用var
// @off 没有必要限制
'no-var': 'off',
// 禁止使用未定义的变量 建议将相关变量在上方 globals 配置项中配置
// @warn 警示即可
'no-undef': 'warn',
// 函数的参数禁止超过10个
// @warn 警示即可
'max-params': ['warn', 10],
// 回调函数嵌套禁止超过 5 层
// @warn 警示即可
'max-nested-callbacks': ['warn', 5],
// 循环内的函数中不能出现循环体条件语句中定义的变量
// @warn 警示即可
'no-loop-func': 'warn',
// Promise 的 reject 中必须传入 Error 对象
// @off 不需要限制
'prefer-promise-reject-errors': 'off',
// 变量声明时尽量使用一个var声明连续的多个
// @warn 警示即可
'one-var': [
'error',
'consecutive'
],
// 变量申明必须每行一个
// @error 赋值时保证处于一行即可
'one-var-declaration-per-line': [
'error',
'initializations'
],
// 禁止使用已废弃的 api
// @off 不需要限制
'react/no-deprecated': 'off',
// 禁止使用字符串 ref
// @warn 警告即可
'react/no-string-refs': 'warn',
// 必须使用 Class 的形式创建组件
// @warn 警告即可
'react/prefer-es6-class': [
'warn',
'always'
],
// 禁止在 componentDidUpdate 里面使用 setState
// @warn 警告即可
'react/no-did-update-set-state': 'warn',
// 组件内方法必须按照一定规则排序
// @off 不需要限制
'react/sort-comp': 'off',
// jsx 的 props 缩进必须为四个空格
// @off 不需要限制
// 'react/jsx-indent-props': 'off',
}
StyleLint规则
ESLint规则也很多,以 stylelint-config-standard 为基础,加入自定义
rules: {
// 颜色值避免直接使用颜色名
'color-named': [
'never', {
ignore: ['inside-function']
}
],
// 使用数字或命名的 (可能的情况下) font-weight 值
'font-weight-notation': 'numeric',
// 在函数的逗号之后要求有一个换行符或禁止有空白
'function-comma-newline-after': null,
// 在函数的括号内要求有一个换行符或禁止有空白
'function-parentheses-newline-inside': null,
// url使用引号
'function-url-quotes': 'always',
// 禁止小于 1 的小数的前导 0
'number-leading-zero': 'never',
// 字符串使用双引号
'string-quotes': 'double',
// 要求选择器列表的逗号之前有一个换行符
'selector-list-comma-newline-before': 'never-multi-line',
// 在媒体查询的逗号之前禁止有一换行
'media-query-list-comma-newline-before': 'never-multi-line',
// 缩进
'indentation': 4,
// 禁止低优先级的选择器出现在高优先级的选择器之后
'no-descending-specificity': null,
// 禁止空源
'no-empty-source': null,
// 禁止缺少文件末尾的换行符
'no-missing-end-of-source-newline': null
}
HtmlHint规则
HtmlHint的规则比较少,可以直接自定义
要注意的是它并不支持JS语法,需要使用JSON格式(在webpack中会强制按这个语法parse)
{
"_comment": [
"自定义的HTMLHint配置项",
"规则中文 @see https://segmentfault.com/a/1190000013276858",
"规则英文 @see https://github.com/yaniswang/HTMLHint/wiki/Rules",
"使用注释自定义规则 @see https://github.com/yaniswang/HTMLHint/wiki/Usage#cli"
],
"_comment": "标签名必须小写",
"tagname-lowercase": true,
"_comment": "属性名必须小写",
"attr-lowercase": false,
"_comment": "属性值必须放在双引号中",
"attr-value-double-quotes": true,
"_comment": "属性值一定不可为空",
"attr-value-not-empty": false,
"_comment": "属性值一定不可重复",
"attr-no-duplication": true,
"_comment": "Doctype必须是 HTML 文档的第一行",
"doctype-first": false,
"_comment": "标签必须成对",
"tag-pair": true,
"_comment": "标签必须自封闭",
"tag-self-close": false,
"_comment": "特殊字符必须转义",
"spec-char-escape": false,
"_comment": "ID 属性必须唯一",
"id-unique": true,
"_comment": "src 属性一定不可为空",
"src-not-empty": true,
"_comment": "title 属性必须出现在标签中",
"title-require": false,
"_comment": "img 标签必须包含 alt 属性",
"alt-require": true,
"_comment": "Doctype 必须是 HTML5",
"doctype-html5": true,
"_comment": "ID 和 Class 的命名规则必须统一",
"id-class-value": false,
"_comment": "不该使用样式标签",
"style-disabled": false,
"_comment": "不该使用行内样式",
"inline-style-disabled": false,
"_comment": "不该使用行内脚本",
"inline-script-disabled": false,
"_comment": "空格和制表符一定不可混合在行前",
"space-tab-mixed-disabled": "space4",
"_comment": "ID 和 Class 一定不可使用广告关键词",
"id-class-ad-disabled": false,
"_comment": "href 必须是绝对路径或者相对路径",
"href-abs-or-rel": false,
"_comment": "属性值一定不可使用不安全字符",
"attr-unsafe-chars": true,
"_comment": "script 标签不该使用在头部",
"head-script-disabled": false
}
对于页面中嵌入的CSS与JS,也需要进行检查。
在ESlint中提供了 eslint-plugin-html 插件,然而对<style> 与 <script> 造成的缩进处理不当(配置失效的样子),这个是比较难搞的
// 检查html文件(或tpl文件)中的JS
plugins: [
'html'
],
settings: {
'html/html-extensions': ['.html', '.tpl'],
// 'html/indent': '+4'
},
在StyleLint中提供了 stylelint-processor-arbitrary-tags 插件,不过新版似乎内置了支持。然而也并算完美,至少能用就行
在Sublime,Webstorm或其他编辑器IDE中使用这些工具的前提:
安装NodeJS,然后使用NPM在全局安装以下依赖包
npm i -g eslint babel-eslint eslint-config-alloy eslint-plugin-html eslint-plugin-react stylelint stylelint-config-standard htmlhint
在项目根目录下添加三个工具对应的文件 (这三个文件即为对应的检查规则集),以便代码编辑器在任何地方都能找到配置文件,如
ESLint 和 StyleLint 工具提供了自动修复功能,可以修复简单的错误如少了分号,多了空格,缩进不正确等
但要注意的是,自动修复某些时候可能会使代码发生逻辑或语法错误,需谨慎使用(自动修复后一定一定一定记得比对代码,确保无误)
3. 在Sublime中的配置
sublime安装对应的linter工具,以SublimeLinter工具为基础进行配置
Ctrl+Shift+P 调出安装插件层,输入关键字 sublimelinter 进行搜索安装
再安装相应的工具插件,SublimeLinter-eslint , SublimeLinter-stylelint, SublimeLinter-contrib-htmlhint
安装 ESLint-Formatter 以支持自动修复检查的错误
新增一个构建任务,可命名为,StyleLint-Fix.sublime-build 以支持自动修复检查的错误
在其中填入以下内容,保存在相应的位置即可
{
"shell_cmd": "stylelint $folder/node_modules/.bin/eslint --fix $file"
}
接下来就是配置 SublimeLinter
打开插件配置,在User部分填入以下内容并保存即可
stylelint配置中的executable全局路径需要设置好
// SublimeLinter Settings - User
{
"debug": true,
// "delay": 0.2,
"lint_mode": "manual",
// "syntax_map": {
// "html (django)": "html",
// "html (rails)": "html",
// "html 5": "html",
// "css": "css",
// "javascript (babel)": "javascript",
// "magicpython": "python",
// "php": "html",
// "python django": "python",
// "pythonimproved": "python"
// },
"styles": [
{
"scope": "region.yellowish markup.warning.sublime_linter",
"types": ["warning"]
},
{
"scope": "region.redish markup.error.sublime_linter",
"types": ["error"]
},
{
"priority": 1,
"icon": "dot",
"mark_style": "outline"
}
],
"linters": {
"eslint": {
// 让eslint能够识别html页面中嵌入的JS
"selector": "source.js | text.html.basic"
},
// 下面三个sublimelinter默认都支持,为防止检查干扰,需要禁用它们
"scsslint": {
"disable": true
},
"csslint": {
// "disable": true
},
"htmllint": {
"disable": true
},
"stylelint": {
// 似乎Sublime的stylelint需要手动设置到全局路径
// "executable": "C:\\Users\\e470\\AppData\\Roaming\\npm\\stylelint.cmd"
"executable": "/usr/local/bin/stylelint"
}
}
}
可以看到,在sublimelinter的配置中是以手动(manual)模式进行调用检查的,可以防止某些文件代码量太大,频繁检查消耗性能
需要检查的时候,在当前文件打开命令即可,或者使用对应快捷键(如果看不到命令,就采用重启大法吧)
以下命令关键字都是在以 Ctrl+Shift+P打开命令层的前提下进行的
Lint This View ,执行检查
SublimeLinter还支持检查HTML或tpl文件里嵌入的JS和CSS, 但Webstorm不行唷~~
Show All Errors,在底部显示错误列表
使用 ESlint-formatter进行自动修复JS
使用 StyleLint-Fix 进行自动修复CSS
这个需要调出构建任务列表层,或者使用快捷键 Ctrl+Shift+B,选择我们的fix任务执行即可
HTMLHint的不提供自动修复功能
4. 在WebStorm中的配置
打开设置
启用内置的ESLint检查
启用内置的StyleLint检查
安装之后,可能需要重启,在列表中可以看到插件配置入口
因此插件比较特殊,在windows下,bin中请使用 node执行程序的绝对路径 全局 htmlhint的绝对路径
其他环境下就慢慢试吧..
bin: D:\Program Files\nodejs\node.exe C:\Users\e470\AppData\Roaming\npm\node_modules\htmlhint\bin\htmlhint
path: .htmlhintrc
内置的ESLint与StyleLint不支持自动修复功能,所以我们需要手动创建 File Watcher
配置成手动执行可能会更好些
需要执行的时候,执行即可
5. 在webpack中的配置
参考我的webpack项目配置DEMO, 在 webpack.config.js 中传入相应的参数
正式使用时autoFix会按需设置,建议修复。如果选择修复,webpack将按模块的设置进行批量修复,可能会有大量文件被修改,所以需要做好代码比对工作
另外,开启自动修复可能会导致webpack编译无限循环的问题,对于这个我们可以引入一个新的插件 time-fix-plugin ,直接调用即可
new TimeFixPlugin()
在使用 htmlhint-loader的时候,webpack默认无法识别html资源,在以往我们可以直接使用 htmlWebpackPlugin来识别,因为它内置支持了ejs-loader
但现在这个代码检查插入之后,我们就需要手动设置好html语法的loader。
不能使用 html-loader ,使用之后会导致无法识别我们的ejs语法,导致htmlWebpackPlugin的资源插入失效
解决办法也很简单,使用 ejs-loader 即可,见下方配置
另外,在生产模式 npm run build:prod的时候,提供了将检查结果输出到文件的功能(css的不支持),见 lint目录
虽然有点错乱,也够搜索存档用了
而具体在webpack的核心配置文件里面,配置也是挺简单的,虽然也有蛮多不如意
首先相关的npm包需要安装好,使用 htmlhint-loader eslint-loader stylelint-webpack-plugin
配置核心部分
new HappyPack({
id: 'js',
use: configs.lint.js.open ? [{
loader: 'babel-loader',
options: {
// cacheDirectory: true
}
}, {
enforce: 'pre',
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
fix: configs.lint.js.autoFix,
cache: true,
emitWarning: !configs.lint.js.emitAsError,
failOnError: configs.lint.js.failOnError,
formatter: require('eslint-friendly-formatter'),
outputReport: {
filePath: cwdRalativeOutputPath + '/lint/js/[name].xml',
formatter: require('eslint-friendly-formatter')
}
}
}] : [{
loader: 'babel-loader',
options: {
// cacheDirectory: true
}
}]
}),
new HappyPack({
id: 'html',
use: configs.lint.html.open ? [{
loader: 'ejs-loader',
options: {
}
}, {
loader: 'htmlhint-loader',
enforce: 'pre',
exclude: /node_modules/,
options: {
configFile: configs.lint.html.configFile,
failOnError: configs.lint.html.failOnError,
outputReport: {
filePath: cwdRalativeOutputPath + '/lint/html/[name].xml'
}
}
}] : [{
loader: 'ejs-loader',
options: {
}
}]
}),
// stylelint检查
if (configs.lint.css.open) {
commonConfig.plugins.push(new StyleLintPlugin({
fix: configs.lint.css.autoFix,
emitErrors: configs.lint.css.emitAsError,
failOnError: configs.lint.css.failOnError,
formatter: require('stylelint-formatter-pretty')
}));
}
以上是关于前端代码乱糟糟?是时候引入代码质量检查工具了的主要内容,如果未能解决你的问题,请参考以下文章