爲了統一團隊的代碼規範,除了一紙規範說明以外,還須要引入工具進行限制。雖然說工具並不能徹底實現規範中的規則,但至少可以在必定程度上緩解代碼不統一的局面。javascript
相對於後端,前端代碼規範的質量檢查涉及到HTML, CSS,Javascript ,現在還涉及到SCSS,ES5,JSX, React,Vue,Angular等,更是複雜。php
本文提供了在檢查工具方面的規則制定,在編輯器IDE中進行配置,在webpack中進行打包。讓開發小夥伴有所參考css
相關規則能夠在 webpack4項目demo 中看到,裏頭放了相關的規則連接註釋,歡迎圍觀~html
筆者對常見的代碼檢查工具作了一番調研,結合規則支持度,配置方式,在編輯器Sublime於Webstrom這隻IDE上的支持度,在webpack打包的支持,最終確立了使用以下方案前端
HTML / tpl: HTMLHinthtml5
CSS / SCSS: StyleLintjava
JS / JSX: ESLintnode
對比參考: JavaScript 代碼靜態質量檢查 CSS 代碼靜態質量檢查 HTML代碼風格檢查工具對比python
儘管如此,這三個插件也並不完美,有太多太多的坑踩遍了,若是你有更合適的套件,歡迎建議~react
選取了工具以後,就須要確立相應的規則。
規則很是多,對咱們這種沒經驗的小白是不可能一條一條自主去選取的,因此須要依據某些參考。但也只能是參考,咱們須要把這些通用的設置,結合到咱們實際項目中,並一條條去了解規則,最終選出並摘錄進咱們的規則集中。
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 工具提供了自動修復功能,能夠修復簡單的錯誤如少了分號,多了空格,縮進不正確等
但要注意的是,自動修復某些時候可能會使代碼發生邏輯或語法錯誤,需謹慎使用(自動修復後必定必定必定記得比對代碼,確保無誤)
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的不提供自動修復功能
打開設置
啓用內置的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
配置成手動執行可能會更好些
須要執行的時候,執行便可
參考個人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') })); }