1. 程式人生 > >挖坑指南:ESLint + VS Code自動格式化程式碼

挖坑指南:ESLint + VS Code自動格式化程式碼

前言

最近在整理公司的之前的專案,對整個產品線進行梳理重構。由於專案的編碼人員換了好幾撥,每個人編碼又各有各的風格。現在在重新翻看,可讀性很差。考慮到後期專案的擴充套件,以及對現有專案的優化,決定對程式碼進行整理,並統一使用ESLint進行規範約束。

開始

“編碼一時爽,重構火葬場。”

 剛開始接觸vue學習的時候,也都是自然而然地關閉了ESLint。以至於沒有從頭開始養成良好的習慣,現在也是從0開始,將ESLint正式引入到工作中。

如果你才剛剛起步,我建議你先了解下ESLint以及它在前端工作流和團隊協作中的必要性。從開始上手時,就規範自己的 編碼行為,好過走到半路又回過來重新開始。

實踐

如何上手?首先還是官方文件。我覺得不論是學什麼,你得先去了解它是什麼,以及它為什麼出現,然後才是衡量是否要在工作或生活中使用它。

官方文件:https://eslint.org/

中文文件:https://cn.eslint.org/

官方的描述

官方描述

 ESLint它很靈活,所有的檢查都是基於規則的。

ESLint規則:https://cn.eslint.org/docs/rules/

使用ESLint三部曲

  1. 安裝
    npm install -g eslint
  2. 初始化
    npm init
  3. 編寫配置檔案(由於ESLint配置檔案支援多種檔案擴充套件,此處以.eslintrc.js為例)
    module.exports = {
      /**
       * 預設情況下,ESLint會在所有父級目錄裡尋找配置檔案,一直到根目錄。
       * 為了將ESLint限制在一個特定的專案,設定root: true;
       * ESLint一旦發現配置檔案中有 root: true,就會停止在父級目錄中尋找。
       */
      root: true,
      // 指定解析器
      // babel-ESLint: 一個對Babel解析器的包裝,使其能夠與ESLint相容。
      // parser: 'babel-eslint',
      // 設定解析器能幫助ESLint確定什麼是解析錯誤。
      parserOptions: {
        parser: 'babel-eslint',
        // 指定js版本。語法上的支援
        ecmaVersion: 6
      },
      // 指令碼在執行期間訪問的額外的全域性變數
      // globals: {},
      // env: 指定指令碼的執行環境
      env: {
        // 一個環境定義了一組預定義的全域性變數。
        browser: true,
        // 會自動開啟es6語法支援。
        es6: true,
        node: true
      },
      // 使用第三方外掛。全域性安裝的 ESLint 例項只能使用全域性安裝的ESLint外掛。本地同理,不支援混用。
      plugins: [
        'html',
        'vue'
      ],
      // 配置檔案從基礎配置中繼承已啟用的規則。
      /**
       * eslint:recommended  啟用核心規則,在規則頁面中被標記為 √ 的。
       */
      extends: [
        // plugin:(此處不能有空格)包名/配置名稱。解析時plugin是解析成 eslint-plugin-vue。如果有空格會解析失敗,eslint-plugin- vue。
        // plugin可以省略包名的字首 eslint-plugin-
        // 'plugin:vue/essential',
        // '@vue/standard',
        'eslint:recommended'
        // 也可以指定另一個基本配置檔案的絕對路徑或相對路徑
      ],
      
    
      /**
       * 每個規則有【3】個錯誤級別。
       * off或0: 關閉該規則;
       * warn或1: 開啟規則,使用警告級別的錯誤,不會導致程式退出;
       * error或2: 開啟規則,使用錯誤級別的錯誤,當被觸發的時候,程式會退出。
       */
      rules: {
        /**
         * 【================================================ Possible Errors ================================================】
         * 這些規則與JavaScript程式碼中可能的錯誤或邏輯錯誤有關。
         */
        // 強制"for"迴圈中更新子句的計算器朝著正確的方向移動
        'for-direction': 2,
        // 禁止function定義中出現重名引數
        'no-dupe-args': 2,
        // 禁止物件字面量中出現重複的key
        'no-dupe-keys': 2,
        // 禁止出現重複的case標籤
        'no-duplicate-case': 2,
        // 禁止對catch子句的引數重新賦值
        'no-ex-assign': 2,
        // 禁止對關係運算符的左運算元使用否定操作符
        'no-unsafe-negation': 2,
        // 禁止出現令人困惑的多行表示式
        'no-unexpected-multiline': 2,
        // 禁止在return、throw、continue、break語句之後出現不可達程式碼
        'no-unreachable': 2,
        // 禁止在finally語句塊中出現控制流語句
        'no-unsafe-finally': 2,
        // 要求使用isNaN()檢查NaN
        'use-isnan': 2,
        // 強制typeof表示式與有效的字串進行比較
        'valid-typeof': 2,
        // 還可以寫表示式,厲害了~
        'no-debugger': process.env.NODE_ENV === 'production' ? 'error': 'off',
        'no-console': process.env.NODE_ENV === 'production' ? 'error': 'off',
    
        /**
         * 【================================================ Best Practices ================================================】
         * 這些規則是關於最佳實踐的,幫助你避免一些問題。
         */
        // 強制 getter 和 setter在物件中成對出現
        'accessor-pairs': 2,
        // 強制所有控制語句使用一致的括號風格
        'curly': [2, 'multi-line'],
        // 強制在點號之前和之後一致的換行
        'dot-location': [2, 'property'],
        // 要求使用 ===和 !==
        'eqeqeq': [2, 'allow-null'],
        // 禁用arguments.caller 或 arguments.callee
        'no-caller': 2,
        // 禁止使用空解構模式
        'no-empty-pattern': 2,
        // 禁止eval()
        'no-eval': 2,
        // 禁止使用類似eval()的方法
        'no-implied-eval': 2,
        // 禁止擴充套件原生型別
        'no-extend-native': 2,
        // 禁止不必要的.bind()呼叫
        'no-extra-bind': 2,
        // 禁止case語句落空
        'no-fallthrough': 2,
        // 禁止數字字面量中使用前導和末尾小數點
        'no-floating-decimal': 2,
        // 禁用__iterator__屬性
        'no-iterator': 2,
        // 禁用標籤語句
        'no-labels': [2, {
          'allowLoop'  : false,
          'allowSwitch': false
        }],
        // 禁用不必要巢狀塊
        'no-lone-blocks': 2,
        // 禁止使用多個空格
        'no-multi-spaces': 2,
        // 禁止使用多行字串
        'no-multi-str': 2,
        // 禁止對String,Number 和 Boolean 使用new操作符
        'no-new-wrappers': 2,
        // 禁用八進位制字面量
        'no-octal': 2,
        // 禁止在字串中使用八進位制轉義序列
        'no-octal-escape': 2,
        // 禁止使用__proto__屬性
        'no-proto': 2,
        // 禁止多次宣告同一變數
        'no-redeclare': 2,
        // 禁止在return語句中使用賦值語句
        'no-return-assign': [2, 'except-parens'],
        // 禁止自我賦值
        'no-self-assign': 2,
        // 禁止自我比較
        'no-self-compare': 2,
        // 禁用逗號操作符
        'no-sequences': 2,
        // 禁止丟擲異常字面量
        'no-throw-literal': 2,
        // 禁止一成不變的迴圈條件
        'no-unmodified-loop-condition': 2,
        // 禁止不必要的.call()和.apply()
        'no-useless-call': 2,
        // 禁止不必要的轉義字元
        'no-useless-escape': 2,
        // 禁用with語句
        'no-with': 2,
        // 要求IIFE使用括號括起來
        'wrap-iife': 2,
        // 要求或禁止Yoda條件。 if("red" === color) { //字面量在前,變數在後 }
        'yoda': [2, 'never'],   //  比較絕不能是Yoda條件(需要變數在前,字面量在後)
    
        /**
         * 【================================================ ECMAScript 6 ================================================】
         * 這些規則只與ES6有關,即通常所說的ES2015。
         */
        // 強制箭頭函式前後使用一致的空格
        'arrow-spacing': [2, {
          'before': true,
          'after' : true
        }],
        // 要求在建構函式中有super()呼叫
        'constructor-super': 2,
        // 強制generator函式中*號周圍使用一致的空格
        'generator-star-spacing': [2, {
          'before': true,
          'after' : true
        }],
        // 禁止修改類宣告的變數
        'no-class-assign': 2,
        // 禁止修改const宣告的變數
        'no-const-assign': 2,
        // 禁止類成員中出現重複的名稱
        'no-dupe-class-members': 2,
        // 禁止 Symbolnew 操作符和 new 一起使用
        'no-new-symbol': 2,
        // 禁止在建構函式中,在呼叫super()之前使用 this 或 super
        'no-this-before-super': 2,
        // 禁止在物件中使用不必要的計算屬性
        'no-useless-computed-key': 2,
        // 禁止不必要的建構函式
        'no-useless-constructor': 2,
        // 禁止模板字串中嵌入表示式周圍空格的使用
        'template-curly-spacing': [2, 'never'],
        // 強制yield*表示式中的*周圍使用空格
        'yield-star-spacing': [2, 'both'],
        // 要求使用const宣告那些聲明後不再被修改的變數
        'prefer-const': 2,
    
        /**
         * 【================================================ Stylistic Issues ================================================】
         * 這些規則是關於程式碼風格的。
         */
        //  獲取當前執行環境的上下文時,強制使用一致的命名(此處強制使用 'that')。
        'consistent-this': [2, 'that'],
        // 禁止或強制在程式碼塊中開括號前和閉括號後有空格  { return 11 }
        'block-spacing': [2, 'always'],
        // 強制在程式碼塊中使用一致的大括號風格
        'brace-style': [2, '1tbs', {
          'allowSingleLine': true
        }],
        // 強制使用駝峰拼寫法命名規定
        'camelcase': [0, {
          'properties': 'always'
        }],
        // 要求或禁止末尾逗號
        'comma-dangle': [2, 'never'],
        // 強制在逗號前後使用一致的空格
        'comma-spacing': [2, {
          'before': false,
          'after' : true
        }],
        // 強制在逗號前後使用一致的空格
        'comma-style': [2, 'last'],
        // 要求或禁止檔案末尾存在空行
        'eol-last': 2,
        // 強制使用一致的縮排
        'indent': [2, 2, {
          'SwitchCase': 1
        }],
        // 強制在JSX屬性中一致地使用雙引號或單引號
        'jsx-quotes': [2, 'prefer-single'],
        // 要求建構函式首字母大寫
        'new-cap': [2, {
          'newIsCap': true,
          'capIsNew': false
        }],
        // 要求構造無參建構函式時有圓括號
        'new-parens': 2,
        // 禁用Array建構函式
        'no-array-constructor': 2,
        // 禁止空格和tab的混合縮排
        'no-mixed-spaces-and-tabs': 2,
        // 禁止出現多行空行
        'no-multiple-empty-lines': [2, {
          // 最大連續空行數
          max: 2
        }],
        // 禁止在函式識別符號和其呼叫之間有空格
        'func-call-spacing': 2,
        // 禁止行尾空格
        'no-trailing-spaces': 2,
        // 禁止可以在有更簡單的可替代的表示式時使用三元操作符
        'no-unneeded-ternary': [2, {
          // 允許表示式作為預設的賦值模式
          'defaultAssignment': true
        }],
        // 禁止屬性前有空白
        'no-whitespace-before-property': 2,
        // 強制函式中的變數要麼一起宣告要麼分開宣告
        'one-var': [2, {
          'initialized': 'never'
        }],
        // 強制操作符使用一致的換行符
        'operator-linebreak': [2, 'after', {
          'overrides': {
            '?': 'before',
            ':': 'before'
          }
        }],
        // 要求或禁止塊內填充
        'padded-blocks': [2, 'never'],
        // 強烈使用一致的反勾號``、雙引號""或單引號''
        'quotes': [2, 'single', {
          // 允許字串使用單引號或者雙引號,只要字串中包含了一個其他引號,否則需要轉義
          'avoidEscape': true,
          // 允許字串使用反勾號
          'allowTemplateLiterals': true
        }],
        // 禁止使用分號代替ASI(自動分號插入)
        'semi': [2, 'never'],
        // 強制分號之前和之後使用一致的空格
        'semi-spacing': [2, {
          'before': false,
          'after' : true
        }],
        // 強制在塊之前使用一致的空格
        'space-before-blocks': [2, 'always'],
        // 強制在圓括號內使用一致的空格
        'space-in-parens': [2, 'never'],
        // 要求操作符周圍有空格
        'space-infix-ops': 2,
        // 強制在一元操作符前後使用一致的空格
        'space-unary-ops': [2, {
          'words'   : true,
          'nonwords': false
        }],
        // 強制在註釋// 或/*使用一致的空格
        'spaced-comment': [1, 'always', {
          'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
        }],
        // 強制在大括號中使用一致的空格
        'object-curly-spacing': [2, 'always', {
          'objectsInObjects': false
        }],
        // 禁止或強制在括號內使用空格
        'array-bracket-spacing': [2, 'never'],
        // 強制要求在物件字面量的屬性中鍵和值之間使用一致的間距
        'key-spacing': [2, {
          'beforeColon': false,
          'afterColon' : true
        }],
       
        /**
         * 【================================================ Node.js and CommonJS ================================================】
         * 這些規則是關於Node.js 或 在瀏覽器中使用CommonJS的。
         */
        // 要求回撥函式中有容錯處理
        'handle-callback-err': [2, '^(err|error)$'],
        // 禁止呼叫 require 時使用new操作符
        'no-new-require': 2,
        // 禁止對__dirname和__filename進行字串連線
        'no-path-concat': 1,
        // 強制在function的左括號之前使用一致的空格
        'space-before-function-paren': [2, 'never'], 
        
        /**
         * 【================================================ Possible Errors ================================================】
         * 這些規則與JavaScript程式碼中可能的錯誤或邏輯錯誤有關。
         */
        // 禁止條件表示式中出現賦值操作符
        'no-cond-assign': 2,
        // 禁止在正則表示式中使用控制字元
        'no-control-regex': 0,
        // 禁止在正則表示式中使用空字符集
        'no-empty-character-class': 2,
        // 禁止不必要的布林轉換
        'no-extra-boolean-cast': 2,
        // 禁止不必要的括號
        'no-extra-parens': [2, 'functions'],
        // 禁止對function宣告重新賦值
        'no-func-assign': 2,
        // 禁止在巢狀塊中出現變數宣告或function宣告
        'no-inner-declarations': [2, 'functions'],
        // 禁止RegExp建構函式中存在無效的正則表示式字串
        'no-invalid-regexp': 2,
        // 禁止在字串和註釋之外不規則的空白
        'no-irregular-whitespace': 2,
        // 禁止把全域性物件作為函式呼叫
        'no-obj-calls': 2,
        // 禁止正則表示式字面量中出現多個空格
        'no-regex-spaces': 2,
        // 禁用稀疏陣列
        'no-sparse-arrays': 2,
    
        /**
         * 【================================================ Variables ================================================】
         * 這些規則與變數宣告有關。
         */
        // 禁止刪除變數
        'no-delete-var': 2,
        // 不允許標籤與變數同名
        'no-label-var': 2,
        // 禁止將識別符號定義為受限的名字
        'no-shadow-restricted-names': 2,
        // 禁止未宣告的變數,除非它們在/*global */註釋中被提到
        'no-undef': 2,
        // 禁止將變數初始化為undefined
        'no-undef-init': 2,
        // 禁止出現未使用的變數
        'no-unused-vars': [2, {
          'var' : 'all',
          'args': 'none'
        }],
    
        /**
         * 【================================================ 配置定義在外掛中的規則 ================================================】
         * 格式: 外掛名/規則ID
         */
        // 
        'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }]
      }
    }
    .eslintignore:可以配置指定的目錄或檔案不進行ESLint檢查。

這個專案框架是iview-admin2.x.x的,專案本身基於vue 3.x以及webpack4.x,專案自身做了基本配置。

還要安裝我們的外掛,

npm install eslint-plugin-html --save-dev
npm install eslint-plugin-vue --save-dev

在VS Code中自動按照ESLint規則格式化程式碼

  1. 在VS Code中安裝外掛(ESLint、Vurter、Prettier)
  2. 檔案 => 首選項 => 設定開啟settings.json檔案,個人配置如下
  3. {
        // 是否允許自定義的snippet片段提示
        "editor.snippetSuggestions"      : "top",
        "editor.fontSize"                : 20,
        "editor.fontWeight"              : "400",
        "editor.formatOnType"            : true,
        "workbench.iconTheme"            : "material-icon-theme",
        "workbench.colorTheme"           : "One Dark Pro",
        "guides.enabled": false,
        "editor.tabSize": 2,
        "git.confirmSync": false,
        "window.zoomLevel": 0,
        "editor.renderWhitespace": "boundary",
        "editor.cursorBlinking": "smooth",
        "editor.minimap.enabled": true,
        "editor.minimap.renderCharacters": false,
        "window.title": "${dirty}${activeEditorMedium}${separator}${rootName}",
        "editor.codeLens": true,
        // 配置檔案關聯,以便啟用對應的提示
        "files.associations": {
          "*.vue": "vue",
          "*.wxss": "css"
        },
        // 配置emmet是否啟用tab展開縮寫
        "emmet.triggerExpansionOnTab": true,
        // 配置emmet對檔案型別的支援
        "emmet.syntaxProfiles": {
            "javascript": "jsx",
            "vue": "html",
            "vue-html": "html"
        },
        // 是否開啟eslint檢測
        "eslint.enable": true,
        // 檔案儲存時是否根據eslint進行格式化
        "eslint.autoFixOnSave": true,
        // eslint配置檔案
        "eslint.options": {
          "extensions": [
              ".js",
              ".vue"
          ]
        },
        // eslint能夠識別的檔案字尾型別
        "eslint.validate": [
            "javascript",{
                "language": "vue",
                "autoFix": true
            },"html",
            "vue"
        ],
        "search.exclude": {
            "**/node_modules": true,
            "**/bower_components": true,
            "**/dist": true
        },
        // 格式化快捷鍵(預設):Shift+Alt+F
        // prettier進行格式化時,開啟eslint支援
        // "prettier.eslintIntegration": true,
        // 是否使用單引號
        "prettier.singleQuote": true,
    }

 

總結

遇到的問題:

其實遇到的坑還是蠻多的,捋清楚了,寫文章時倒是沒什麼可寫了。還是說一下,

  • 關於外掛和依賴,可以自己多實踐一下,不安裝會有什麼影響,它的作用是什麼;
  • 儘可能地多看官網的介紹,再結合自己和團隊的編碼風格,制定統一的規範;
  • ESLint+VS Code(此前使用sublime較多)可以加快我們的工作效率,提高程式碼質量;
  • VS Code的配置,只是幫我們程式碼風格(如自動新增空格),一些JS的變數、語法上(如==和===)的東西,還是需要我們自己手動去修改的。

最後,你有什麼想法和思考可以在下方留言評論,大家一起談論技術,一起成長,感謝~或者掃描下方二維碼,與我取得聯絡~  (記得備註:CSND喔~)

後記

好的文章看過很多,對於自己的表述不是很滿意,可能常常會讓人越看越疑惑。還是繼續堅持吧,記錄下來,總會成長的...