ESlint 終于把這個大麻煩解決了!
ESLint 將在 11 月 3 日發(fā)布的 v8.53.0 版本中棄用代碼風格規(guī)則,也就是那些強制執(zhí)行關于空格、分號、字符串格式等的代碼約定的規(guī)則。這樣,同時使用 ESlint 和 Prettier 時就不會出現(xiàn)沖突問題了!
ESlint 是一個代碼檢測工具,其可以進行代碼質量和代碼風格的靜態(tài)分析,捕獲潛在錯誤和不一致的編碼習慣。而 Prettier 是一個代碼格式化工具,其可以對代碼進行格式化,確保整個項目中的代碼風格保持一致。對于代碼中的一些問題,ESlint 可能無法正確格式化,這時候 Prettier 就可以很好地完成格式化的任務。因此,我們通常會組合使用 ESlint 和 Prettier,來保證代碼質量和風格統(tǒng)一( ESlint 負責檢測代碼質量,Prettier 負責格式化代碼)。
但是兩者都有格式化代碼風格的規(guī)則,ESlint 將代碼進行格式化后,會重新被 Prettier 再次格式化。因此最終的格式化效果是 Prettier 提供的。而代碼校驗使用的是 ESLint,因此可能會出現(xiàn)沖突。ESlint 棄用代碼風格規(guī)則后就可以專注于監(jiān)測代碼質量,而 Prettier 專注于監(jiān)測代碼風格。
背景
ESLint 于 2013 年發(fā)布,當時關于是否應該將源代碼格式化作為代碼規(guī)范工具的一部分是存在爭議的。JSLint 是最早出現(xiàn)的 JavaScript 代碼規(guī)范工具,將其作者的代碼格式化偏好編碼到了該工具中,這些偏好在 JSLint 的繼任者 JSHint 中有所保留。2013 年,JSHint 宣布他們將廢除與代碼風格相關的選項,并計劃在下一個主要版本中刪除它們。盡管這些選項從未被實際刪除,但 JSHint 仍然給出了此警告,提醒用戶該選項已被棄用:
Warning This option has been deprecated and will be removed in the next major release of JSHint。
// 警告:此選項已被棄用,并將在 JSHint 的下一個主要版本中刪除。
JSHint is limiting its scope to issues of code correctness. If you would like to enforce rules relating to code style, check out the JSCS project.
// JSHint 將其范圍限制在代碼正確性問題上。如果你想強制執(zhí)行與代碼風格相關的規(guī)則,請查看 JSCS 項目。
JSCS 項目的誕生就是為了滿足 JavaScript 開發(fā)人員對代碼格式設置的日益具體化的需求。與 ESLint 同時出現(xiàn)的 JSCS 在早期曾經歷了一段試驗期,人們嘗試著使用不同組合的 JSHint、JSCS 和 ESLint 來滿足他們的格式化需求。
起初,ESLint 要想與 JSHint 合理競爭,就必須確保 ESLint 具備所有 JSHint 規(guī)則的等效功能。盡管 ESLint 的優(yōu)勢在于自定義規(guī)則,但如果每個人都需要重新創(chuàng)建 JSHint 規(guī)則,ESLint 就可能無法得到廣泛采用。因此,最初的計劃是提供幾十個核心規(guī)則,將其余規(guī)則作為插件實現(xiàn)。
隨著時間的推移,ESLint 收到越來越多的請求,希望將格式和風格規(guī)則納入核心功能。許多請求都提到,他們不想使用兩個工具(ESLint 和 JSCS)來處理代碼,如果 ESLint 能夠實現(xiàn) JSCS 的所有功能,他們可以放棄 JSCS,只使用 ESLint。因此,ESLint 團隊專注于實現(xiàn)功能的平衡,以滿足這種需求。最終,取得了巨大成功,JSCS 的使用量下降,并將其合并到了 ESLint 中。
當時,ESlint 團隊并沒有意識到 JSHint 的想法(棄用代碼風格規(guī)則)是正確的,盡管 ESLint 已經成為 JavaScript 的主導代碼規(guī)范工具。
JavaScript 的爆炸式增長和維護負擔
在接下來的幾年里,尤其是在 ECMAScript 6 和 React 發(fā)展的推動下,編寫 JavaScript 的方式發(fā)生了巨大的變化。Airbnb 和 Standard 等越來越流行的風格指南鼓勵 JavaScript 開發(fā)人員更具體地了解他們的代碼是如何編寫的。因此,ESLint 收到了大量關于格式化規(guī)則的例外和選項的請求。在過去的十年中,出現(xiàn)了各種奇怪的代碼風格,并伴隨著對將它們強制應用于 ESLint 核心規(guī)則的請求。每當引入新的語法時,ESlint 團隊都會收到一系列請求,要求更新現(xiàn)有規(guī)則并實施新規(guī)則。
當 ESlint 的核心規(guī)則接近 300 條時,ESlint 團隊試圖通過凍結風格規(guī)則來減輕維護負擔,這樣就不再追蹤極端情況來支持每個人的個人偏好。這在一定程度上有所幫助,但還不夠:
- 規(guī)則沖突:用戶期望核心規(guī)則能夠很好地配合,這意味著任何兩個規(guī)則都不應標記相同的問題,任何兩個核心規(guī)則也不應該給出相互沖突的建議。雖然當核心規(guī)則少于 30 條時,這很容易實現(xiàn),但當規(guī)則超過 300 條時,實現(xiàn)這一點就變得很困難,甚至不可能。
- 不切實際的期望:有了大量的核心格式規(guī)則,用戶希望可以僅通過核心規(guī)則而不涉及插件就能實現(xiàn)所有可能的代碼風格指南。這給團隊增加了更多壓力,要求不斷添加選項,這也增加了核心的大小。
- 努力與價值不匹配:持續(xù)添加新選項和例外以支持所有人的代碼風格指南的維護負擔落在了 ESLint 團隊身上,而價值只被少數用戶獲得。
- 缺乏興趣:雖然 ESLint 受益于外部貢獻,但這些貢獻者對一些邊緣情況并不感興趣。ESLint 團隊將這些規(guī)則的優(yōu)先級設得比其他工作低得多,這經常導致問題長期未被解決。
- 一致性問題:由于 ESLint 的規(guī)則被設計為原子性規(guī)則,沒有訪問其他規(guī)則的能力,因此會遇到無法正確修復錯誤的問題,因為所需信息在另一個規(guī)則中。例如,如果自動修復需要添加一行新代碼,它需要知道文件的縮進方式才能應用正確的修復方法。然而,縮進規(guī)則控制 ESLint 的縮進,這意味著其他規(guī)則需要在沒有縮進的情況下應用修復,然后相信縮進規(guī)則會在后續(xù)的處理中修復縮進問題。
所有這些問題隨著 ESLint 的發(fā)展而不斷增加,現(xiàn)在 ESlint 終究是到了一個無法跟上這些問題的地步。
解決方案
推薦使用源代碼格式化工具而不是 ESLint 來對代碼進行格式化。源代碼格式化程序旨在理解整個文件并在整個文件中應用一致的格式。推薦以下兩個格式化工具:
- Prettier:基于 JavaScript 的格式化程序,支持格式化多種語言;
- dprint:基于 Rust 的格式化程序,支持較少的語言。
如果不想用專門的格式化工具,可以使用 @stylistic/eslint-plugin-js(針對JavaScript)或 @stylistic/eslint-plugin-ts(針對TypeScript)。這些包分別包含ESLint核心和 typescript-eslint 中的被棄用的格式化規(guī)則,這些規(guī)則會繼續(xù)維護。
已棄用的規(guī)則
以下列表包含 v8.53.0 中將棄用的所有規(guī)則:
- array-bracket-newline
- array-bracket-spacing
- array-element-newline
- arrow-parens
- arrow-spacing
- block-spacing
- brace-style
- comma-dangle
- comma-spacing
- comma-style
- computed-property-spacing
- dot-location
- eol-last
- func-call-spacing
- function-call-argument-newline
- function-paren-newline
- generator-star-spacing
- implicit-arrow-linebreak
- indent
- jsx-quotes
- key-spacing
- keyword-spacing
- linebreak-style
- lines-between-class-members
- lines-around-comment
- max-len
- max-statements-per-line
- multiline-ternary
- new-parens
- newline-per-chained-call
- no-confusing-arrow
- no-extra-parens
- no-extra-semi
- no-floating-decimal
- no-mixed-operators
- no-mixed-spaces-and-tabs
- no-multi-spaces
- no-multiple-empty-lines
- no-tabs
- no-trailing-spaces
- no-whitespace-before-property
- nonblock-statement-body-position
- object-curly-newline
- object-curly-spacing
- object-property-newline
- one-var-declaration-per-line
- operator-linebreak
- padded-blocks
- padding-line-between-statements
- quote-props
- quotes
- rest-spread-spacing
- semi
- semi-spacing
- semi-style
- space-before-blocks
- space-before-function-paren
- space-in-parens
- space-infix-ops
- space-unary-ops
- spaced-comment
- switch-colon-spacing
- template-curly-spacing
- template-tag-spacing
- wrap-iife
- wrap-regex
- yield-star-spacing
這些規(guī)則將在下一個版本中被棄用,但在至少 ESLint v10.0.0 之前不會被移除。仍然可以使用它們,但在 ESLint CLI 中可能會看到看用警告。
參考:https://eslint.org/blog/2023/10/deprecating-formatting-rules/