zoukankan      html  css  js  c++  java
  • 前端代码乱糟糟?是时候引入代码质量检查工具了

    为了统一团队的代码规范,除了一纸规范说明之外,还需要引入工具进行限制。虽说工具并不能完全实现规范中的规则,但至少能够在一定程度上缓解代码不统一的局面。

    相对于后端,前端代码规范的质量检查涉及到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 插件,然而对<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-stylelintSublimeLinter-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检查

    本地安装 HTMLHint插件下载地址,注意 此插件仅可支持检查HTML后缀文件,不支持tpl,有兴趣的可以给作者提PR

    安装之后,可能需要重启,在列表中可以看到插件配置入口

     

    因此插件比较特殊,在windows下,bin中请使用 node执行程序的绝对路径 全局 htmlhint的绝对路径

    其他环境下就慢慢试吧..

    bin:  D:Program Files
    odejs
    ode.exe C:Userse470AppDataRoaming
    pm
    ode_moduleshtmlhintinhtmlhint
    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')
        }));
    }
  • 相关阅读:
    Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column is set to 0.
    旋转二维数组
    replace empty char with new string,unsafe method和native implementation的性能比较
    判断一字符串是否可以另一字符串重新排列而成
    移除重复字符的几个算法简单比较
    也来纠结一下字符串翻转
    判断重复字符存在:更有意义一点
    程序员常去网站汇总
    sublime
    针对程序集 'SqlServerTime' 的 ALTER ASSEMBLY 失败,因为程序集 'SqlServerTime' 未获授权(PERMISSION_SET = EXTERNAL_ACCESS)
  • 原文地址:https://www.cnblogs.com/imwtr/p/9189414.html
Copyright © 2011-2022 走看看