为了统一团队的代码规范,除了一纸规范说明之外,还需要引入工具进行限制。虽说工具并不能完全实现规范中的规则,但至少能够在一定程度上缓解代码不统一的局面。
相对于后端,前端代码规范的质量检查涉及到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规则
ESLint规则最多,参考自 eslint-config-alloy,再加入我们的自定义
// 自定义的规则 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', 10 ], // 禁止函数的循环复杂度超过 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 插件,然而对