VSCode-Prettier和ESLint如何和睦共處?

孤舟蓑翁發表於2021-02-03

1 在VSCode中單獨使用Prettier儲存程式碼自動格式化的配置方法

1.1 為什麼要使用Prettier?

手動調整程式碼格式,不僅低效,而且在團隊協作開發中,無法保證程式碼風格統一,所以需要引入自動格式化程式碼工具。Prettier不僅可以格式化js, jsx, vue,angular,ts,flow,還適用於HTML, CSS/Less,/Sass,Markdown, YAML,  GraphQL程式碼的格式化,

1.2 Prettier程式碼格式化規則有哪些?

{
  printWidth: 80, // 超過最大值換行
  tabWidth: 2, // 縮排位元組數
  useTabs: false, // 縮排不使用tab,使用空格
  semi: true, // 句尾新增分號
  singleQuote: false, // 使用單引號代替雙引號
  quoteProps: 'as-needed', // 物件的key是否用引號括起來,有三種選項 "as-needed"|"consistent"|"preserve"
  jsxSingleQuote: false, // 在jsx中使用單引號代替雙引號
  trailingComma: 'es5', // 選項:none|es5|all, 在物件或陣列最後一個元素後面是否加逗號(在ES5中加尾逗號)
  bracketSpacing: true, // 是否在物件的{}內部兩側加空格 true - { foo: bar } false - {foo: bar}.
  jsxBracketSameLine: false, // 在jsx中把'>' 是否單獨放一行
  arrowParens: 'avoid', // (x) => {} 箭頭函式引數只有一個時是否要有小括號。avoid:省略括號 'bracketSpacing': true, // 在物件,陣列括號與文字之間加空格 "{ foo: bar }"
  rangeStart: 0, // 僅格式化選中文字 選中文字格式化的起始位置
  rangeEnd: Infinity, // 選中文字格式化的結束位置
  parser: 'babylon', // 格式化的解析器,預設是babylon,會自動根據輸入檔案推斷,不用更改設定
  requirePragma: false, // 若為true,檔案頂部加了 /*** @prettier */或/*** @format */的檔案才會被格式化
  insertPragma: false, // 當requirePragma引數為true時,此引數為true將向@format標記後面新增一個換行符
  proseWrap: 'preserve', // 有效選項[always|never|preserve]。當Markdown文字超過printWidth時,是否換行,always-換行 never-不換行 preserve保持原樣
  endOfLine: 'lf', // 結尾是 lf-\n cr-\r lfcr-\n\r  auto-保持現有的行尾設定
  htmlWhitespaceSensitivity: 'css', // 是否顯示HTML檔案中的空格。 有效選項: 'css' - 尊重CSS display屬性的設定。 'strict' - 空格被認為是敏感的。 'ignore' - 空格被認為是不敏感的
  vueIndentScriptAndStyle: false, // 是否給vue中的 <script> and <style>標籤加縮排
  embeddedLanguageFormatting: 'auto', // 是否格式化嵌入到JS中的html標記的程式碼段或者Markdown語法 auto-格式化 off-不格式化
}

1.3 如何開啟儲存時程式碼自動格式化?

1.3.1 下載Prettier外掛

在vscode的配置檔案中,設定儲存程式碼時使用prettier自動進行程式碼格式化

{
  "javascript.format.enable": false, // 禁用vscode預設的js格式化外掛
  "editor.formatOnSave": true, // 儲存程式碼的時候格式化
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode" // js檔案採用prettier進行格式化
  },
}

 配置完之後,儲存程式碼時,就有自動格式化的效果。

2.ESLint程式碼校驗配置

2.1 有了Prettier之後,為什麼還需要ESLint?

prettier只關心程式碼格式,這顯然是不夠的,我們追求的目標不僅僅是程式碼風格統一,還要在書寫的時候,避免一些常見的低階的錯誤。所以,就要引入ESlint。ESLint也有許多與程式碼規則有關的配置項,那你可能要問,我只用eslint就好了,既能規範編碼風格,也能提升程式碼質量。何必兩個都用,用了還容易起衝突,這是因為eslint的程式碼格式化有盲區,只針對js,jsx,ts,tsx,不能格式化HTML, CSS/Less,/Sass,Markdown, YAML,  GraphQL,以及vue中的html和css。

2.2 Prettier和ESLint為什麼會衝突?

Prettier的功能比較專一,是專門用來格式化程式碼的,格式化程式碼的範圍比ESLint廣泛。

ESLint的功能相對綜合,大體可以分為類,一類是規範程式碼風格(見下圖),一類是規範程式碼質量。

它們之所以會衝突,就是因為井水犯了河水,功能有交叉,而且規則不同,比如Prettier格式化程式碼,預設每行後面加分號,而ESLint的規則是不加,再比如Prettier格式化程式碼時,字串會用雙引號包起來,而ESLint的規則是單引號,由此就產生的衝突。

2.3 如何解決兩者的衝突?

要麼修改Prettier的規則,使之與ESLint保持一致,要麼修改ESLint的校驗規則,使之與Prettier的程式碼格式化風格一致,究竟要改哪一個,都可以。個人傾向於改ESlint的規則,因為Prettier的程式碼格式化規則是普適的,而ESLint的程式碼校驗規則是針對特定語言的,特定的遵從普適的原則上好一些。

 ESLint有關程式碼風格的設定,有些是於Prettier衝突的,安裝eslint-config-prettier npm工具包,就可以關閉eslint程式碼風格部分與prettier衝突的設定。

yarn add  -D eslint-config-prettier

在.eslintrc.js中新增

{
  "extends": [
    "some-other-config-you-use",
    "prettier"
  ]
}

2.3 vscode 儲存時自動修復eslint報錯的配置

2.3.1 安裝ESLint外掛

2.3.2 在.vscode中setting.json中開啟程式碼儲存自動修復eslint告警功能
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
 2.3.3 在專案下新增.eslintrc.js檔案,內容如下:
module.exports = {
  parser: 'babel-eslint',
  parserOptions: {
    // 想使用的額外的語言特性
    ecmaFeatures: {
      legacyDecorators: true, // 裝飾器
    },
  },
  // 新增共享設定
  settings: {
    polyfills: ['fetch', 'promises', 'url', 'object-assign'],
  },
  // extends 屬性值可以省略包名的字首 eslint-config-
  // 你可能想要將你的配置資訊分享給其他專案或人。可分享的配置允許你在 npm 釋出你的配置設定並且其他人可以在他的 ESLint 專案中下載使用這些配置。
  // 可共享的配置 是一個 npm 包,它輸出一個配置物件。
  extends: ['airbnb', 'prettier', 'plugin:compat/recommended'],
  // 外掛一般是輸出規則,一些外掛也可以輸出一個或多個命名的 配置
  plugins: ['react'],
  // 指定指令碼的執行環境。每種環境都有一組特定的預定義全域性變數。
  env: {
    browser: true,
    node: true,
    es6: true,
    mocha: true,
    jest: true,
    jasmine: true,
  },
  globals: {
    localStorage: true,
    sessionStorage: true,
    WeixinJSBridge: true,
    screen: true,
    wx: true,
    qq: true,
    alert: true,
    Image: true,
    File: true,
    FormData: true,
    IntersectionObserver: true,
    fiboSDK: true,
  },
  rules: {  // 規則集,會覆蓋extends中的規則
    'react/jsx-filename-extension': [1, { extensions: ['.js'] }],
    'react/jsx-wrap-multilines': 0,
    'react/prop-types': 0,
    'react/forbid-prop-types': 0,
    'react/jsx-one-expression-per-line': 0,
    'import/no-unresolved': [2, { ignore: ['^@/', '^umi/'] }],
    'import/no-extraneous-dependencies': [0],
    'jsx-a11y/no-noninteractive-element-interactions': 0,
    'jsx-a11y/click-events-have-key-events': 0,
    'jsx-a11y/no-static-element-interactions': 0,
    'jsx-a11y/anchor-is-valid': 0,
    'linebreak-style': 0,
    'no-console': 0,
    'import/prefer-default-export': 0,
    'react/destructuring-assignment': 0,
    'consistent-return': 0,
    'no-return-assign': 0,
    'no-case-declarations': 0,
    'react/no-array-index-key': 0,
    'no-plusplus': 0,
    'no-param-reassign': 0,
    'no-useless-escape': 0,
    'array-callback-return': 0,
    'no-unused-expressions': 0,
    'no-underscore-dangle': 0,
    'no-lonely-if': 0,
    'func-names': 0,
    'react/no-access-state-in-setstate': 0,
    'react/no-did-update-set-state': 0,
    'no-restricted-syntax': 0,
    'no-nested-ternary': 0,
    'no-restricted-globals': 0,
    'react/jsx-props-no-spreading': 0,
    'class-methods-use-this': 0,
    'global-require': 0,
    'react/state-in-constructor': 0,
    'import/no-dynamic-require': 0,
    'react/no-danger': 0,
    'react/sort-comp': 0,
    'no-shadow': 0,
    camelcase: 0,
    //  不檢驗函式入參是否被使用
    'no-unused-vars': ['warn', { args: 'none' }],
  },
};

參考文獻

 

相關文章