前端代碼亂糟糟?是時候引入代碼質量檢查工具了


為了統一團隊的代碼規范,除了一紙規范說明之外,還需要引入工具進行限制。雖說工具並不能完全實現規范中的規則,但至少能夠在一定程度上緩解代碼不統一的局面。

相對於后端,前端代碼規范的質量檢查涉及到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\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')
    }));
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM