Skip to main content

[note] ESLint

keywords: CLI#

Command Line Interface#

# 安裝 eslint cli
$ npm i eslint
# 初始化 eslint 專案
$ npx eslint --init # To check syntax, find problems, and enforce code style
# 執行 eslint
$ eslint [options] [file|dir|glob]*

使用範例#

# eslint [options] file.js [file.js] [dir]
$ eslint 'src/**/*.ts' # 檢驗所有 src 中的 .ts 檔
$ eslint file1.js file2.js
$ eslint lib/**

修復問題#

# Fixing problems:
# --fix 自動修復問題
# --fix-dry-run 自動修復問題,但不儲存檔案
$ eslint 'src/**/*.ts' --fix

透過 npm 執行#

// package.json
"scripts": {
"lint": "eslint src/**/*.ts"
}

執行:

$ npm run lint -- --fix

設定 ESLint#

ESLint Configuration @ ESLint

設定方式#

ESLint 有兩種最主要的設定方式:

  1. 註解:在檔案中直接透過 JavaScript 的註解來進行設定
  2. 設定檔:為整個專案進行設定,一樣有兩種設定方式
    • 使用 JavaScript、JSON 或 YAML 檔案來,它可以是 .eslintrc.* 的檔案
    • 或在 package.json 中使用 eslintConfig 這個欄位來進行設定

透過 ESLint CLI 可以快速建立設定檔。

定義規則(rules)#

這裡的 semiquotes 是 ESLint 中可以套用的規則(rules),陣列中的:

  • 第一個值是「錯誤層級(error level)」
    • off0 - 關閉規則
    • warn1- 將該規則顯示為警告,但仍可執行
    • error2 - 將規則顯示為錯誤,會跳出錯誤後不執行,無法成功編譯
  • 第二個值則是針對該規則的「設定」,例如在 semi 規則中的 always 表示總是要有分號;quotes 規則中的 double 則表示要使用雙引號。
// .eslintrc.*
{
"rules": {
"semi": ["error", "always"], // "semi": "error",
"quotes": ["error", "double"],
"no-console": "off"
}
}

如果是針對第三方 plugins 要設定規則的話,最前面會戴上該 plugin 的名稱,例如:

// 針對 jest 這個 plugin 套用規則(要留意 jest 這個 plugin 需要在 "plugins" 或 "extends" 欄位中被啟用(activate)過。
{
"rules": {
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
}
}
### 定義解析選項(parser options)
##### keywords: `parserOptions`
設定 parser options 可以幫助 ESLint 決定什麼是解析錯誤,所有語言預設的選項都是 `false`。
預設的 ESLint 並沒有支援所有最新的 ES6 語法,因此若有需要可以加上 `{ "parserOptions": { "ecmaVersion": 6 } }` 的設定。
相關的設定如下:
- `ecmaVersion` - 設成 3, 5 (default), 6, 7, 8, 9, 10 or 11 來指定要使用哪一版本的 ECMAScript 語法,也可以用年份寫 `2015` 等同於 6,`2016` 等同於 7,以此類推。
- `sourceType` - 設成 `script` (default) 或 `module`(如果你使用的是 ECMAScript modules)。
- `ecmaFeatures` - 用來定義希望使用語言中哪些額外的功能
- `globalReturn` - 可以在 global scope 下使用 `return`
- `impliedStrict` - 可以在全域使用 Strict Mode
- `jsx` - 可以使用 JSX
​```json
// .eslintrc.json
{
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true,
"settings": {
// 這裡可以設定 react 的版本
"react": {
"version": "16.13.1"
}
}
}
}
}

定義環境(environments)#

keywords: env#

Specifying Environments @ ESLint

透過定義環境可以讓 ESLint 中知道有哪些可用的環境變數或全域變數(global variable),例如,console.log, alert 等等。其中常見的選項包含 browser, node, commonjs,設定方式如下:

// .eslintrc.json
{
"env": {
"browser": true,
"node": true,
"es2021": true,
"jest": true
}
}

或者在 package.json 設定也可以:

// package.json
{
"name": "my-package",
"version": "0.0.1",
"eslintConfig": {
"env": {
"browser": true,
"node": true
}
}
}

設定全域變數(global environments)#

透過 globals 欄位可以哪些變數是可以直接在檔案中使用的全域變數,設定方式如下:

// eslintrc.json
/**
* 設定 var1 和 var2 為全域變數
* writable 表示該變數可以被重新定義該變數
* readonly 則不能重新定義該變數
**/
{
"globals": {
"var1": "writable",
"var2": "readonly"
}
}

設定外掛(plugins)#

在 ESLint 中可以使用第三方的套件,其中在使用這些套件前需要先透過 npm 進行安裝。在設定時,每個套件名稱前面的 eslint-plugin- 可以省略不寫:

// eslintrc.json
{
"plugins": ["plugin1", "eslint-plugin-plugin2"]
}

延伸設定檔(Extending Configuration Files)#

Extending Configuration Files @ ESLint Configuration

extends 延伸後的規則,可以在 rules 欄位中進行修改或覆蓋。

extends 的欄位可以是:

  • 透過字串來定義設定檔
  • 透過字串陣列(array of strings)來定義,每一個設定都會延伸自前一個設定檔

extends 的設定檔可以是「設定檔的路徑」或「共用的設定檔(shareable config)」,例如 eslint:recommended, eslint:all),同樣的套件名稱前面的 eslint-config- 可以省略。

// .eslintrc.js
// 透過 extends 擴增的規則可以再透過 rules 進行修改或覆蓋
module.exports = {
extends: 'eslint:recommended',
rules: {
// enable additional rules
indent: ['error', 4],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'double'],
semi: ['error', 'always'],
// override default options for rules from base configurations
'comma-dangle': ['error', 'always'],
'no-cond-assign': ['error', 'always'],
// disable rules from base configurations
'no-console': 'off',
},
};

overrides#

How does overrides work @ ESLint

overrides 則可以把規則套用在特定的檔案上。例如,下面的設定檔為例,會把規則套用在所有符合 .ts.tsx 的檔案:

// .eslintrc.js
module.exports = {
overrides: [
{
files: ['**/*.ts', '**/*.tsx'],
// 各種規則...
},
],
};

建立自己的 config#

How to Create Your Own ESLint Config Package @ freecodecamp

程式碼中備註#

整支檔案隱藏警告#

keywords: eslint-disable, eslint {rule}: 0#

忽略所有規則#

放在檔案開頭:

/* eslint-disable */ // 在該檔案關閉 ESLint

忽略特定規則#

off or 0 - 關閉規則 warn or 1 - turn the rule on as a warning (doesn’t affect exit code) error or 2 - turn the rule on as an error (exit code is 1 when triggered)

/* eslint no-unused-vars: 0 */
/* eslint no-unused-vars: "error" */
/* global myVar1, myVar2 */ // 忽略未定義的全域變數

於 package.json 中設定#

忽略特定的全域變數也可以在 package.json 中加上:

{
"standard": {
"globals": ["myVar1", "myVar2"]
}
}

特定行數隱藏警告#

keywords: eslint-disable-line, eslint-disable-next-line, eslint-disable-line {rule}, eslint-disable-next-line {rule}#

忽略單行#

忽略所有規則#
file = 'I know what I am doing'; // eslint-disable-line
// eslint-disable-next-line
alert('foo');
忽略特定規則#
alert('foo'); // eslint-disable-line no-alert, quotes, semi
// eslint-disable-next-line no-alert
alert('foo');

忽略多行#

keywords: eslint-disable, eslint-enable#
忽略所有規則#
/* eslint-disable */
alert('foo');
/* eslint-enable */
忽略特定規則#
/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');
/* eslint-enable no-alert, no-console */

常見問題#

xxx should be listed in the project's dependencies#

throws spurious error on test files: @testing-library/react' should be listed in the project's dependencies, not devDependencies @ airbnb GitHub

問題說明:會出現這個問題是因為它認為在專案中有 import 到這個套件,但這個套件卻沒有被列在 package.json 中。

解決方式:針對 test files, configuration files#

如果是測試的檔案(.test.js)出現這個錯誤,可以在 rules 的地方針對 'import/no-extraneous-dependencies' 的地方,使用 devDependencies 進行說明,讓它不會對測試檔案檢查此規則:

module.exports = {
rules: {
'import/no-extraneous-dependencies': [
'warn',
{
devDependencies: [
'test/**/*',
'tests/**/*',
'**/__tests__/**',
'**/*.test.{js,jsx}',
'**/*.test.jsx',
/* 需要的時候也可以加上其他的檔案 */
'**/*.stories.js',
'**/*.stories.jsx',
'**/.eslintrc.js', // eslint config
'**/webpack.config.js', // webpack config
'**/webpack.config.*.js', // webpack config
'**/rollup.config.js', // rollup config
'**/rollup.config.*.js', // rollup config
'**/jest.config.js', // jest config
'**/jest.setup.js', // jest setup
],
},
],
},
};

解決方式:針對 monorepos#

如果是 monorepos 的話,因為並非所有的套件都會安裝在該 subpackages 內,則可以在 rules 中搭配 packageDir 使用:

// 列出所有 subpackages(有放 package.json 的 folder)
const packageDir = [
path.join(__dirname, '.'),
path.join(__dirname, 'packages/hooks'),
path.join(__dirname, 'packages/core'),
path.join(__dirname, 'packages/utils'),
];
module.exports = {
rules: {
'import/no-extraneous-dependencies': [
'warn',
{
packageDir,
},
],
},
};

避免專案不認得 module.exports 等 node 語法#

env 中加入 node:

module.exports = {
env: {
node: true,
},
};

解決 Missing file extension "ts", "tsx" for#

Typescript eslint - Missing file extension “ts” import/extensions @ stack overflow

會有這個問題時因為使用 TS 且搭配了 eslint-config-airbnb 的設定,需要修改 .eslintrc.js 中的 rulessettings

const allExtensions = ['.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json'];
module.exports = {
rules: {
// 解決 Missing file extension "ts" for ... (STEP 1)
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
mjs: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
},
settings: {
// 解決 Missing file extension "ts" for ... (STEP 2)
'import/extensions': allExtensions,
},
};

解決 Parse errors in imported module#

在 eslintrc 的 settings 中加上:

module.exports = {
settings: {
// 解決 Parse errors in imported module
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx', '.d.ts'],
},
},
};

解決 Unable to resolve path to module#

Using eslint with typescript - Unable to resolve path to module @ stack overflow

當試著從 .js 中去 import .ts.tsx 的檔案時,可能會出現這個錯誤。解決方式是在 settings 中增加以下設定:

const allExtensions = ['.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json'];
module.exports = {
settings: {
// 解決 Unable to resolve path to module
'import/resolver': {
node: {
extensions: allExtensions,
},
},
},
};

如果專案中有使用 import alias 的話,則可以不使用 node 而是使用 eslint-import-resolver-babel-module

const allExtensions = ['.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json'];
module.exports = {
settings: {
// 如果需要搭配 import alias 可以用 eslint-import-resolver-babel-module
'babel-module': {
alias: {
'@': './',
},
extensions: allExtensions,
},
},
};

extends 和 plugin 的差別#

plugin 會寫好了一系列的規則(通常稱作 presets)但沒有啟用,你可以根據需要,在設定檔的 rules 欄位中選擇要使用哪些規則。也就是說,使用 plugin 並不會強制套用任何規則,你需要透過 rules 欄位,自行選擇要套用哪個規則

當把套件放入 plugins 時,意思只是「啟用該套件」。

但 plugin 也可能會提供設定檔供你使用,如果有的話,你將可以直接把它的設定檔放入 extends 欄位中,而不需要在 plugins 中載入。

extends 則是把規則設定好,讓你可以直接套用一系列的規則。

舉例來說:

  • 因為 extends 中的 react/recommended 已經使用了 plugins: ["react"],因此 react 這個 plugin 已將被啟用,我們就不需要自己在 plugins 欄位中啟用它:
"plugins": [],
"extends": [
"eslint:recommended",
"plugin:react/recommended"
]
note

具體來說,plugins 提供你許多的規則,你可以自行選用,而 plugin 的作者也可能一併提供了他認為合理的設定檔讓你放在 extends 中使用,但這並不是強制的。

再以 eslint-plugin-prettier 為例,它有兩種不同的設定方式:

方式一:可以把 prettier 掛在 plugins 中再進行這定規則#

{
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}

方式二:也可以不掛入 plugins 中,直接套用 eslint-plugin-prettier 寫好的 config#

{
"extends": ["plugin:prettier/recommended"]
}
tip

之所以可以不用在 plugins 欄位套用 prettier 的原因在於,在 eslint-config-prettier 的設定檔中,就已經使用了 plugins:["prettier"] 來把 eslint-plugin-prettier 載入了。反之,若該 config 沒有直接在套件的 plugins 中載入(可以檢視該 config package 撰寫的 eslintrc 檔),則開發者就需要自己把它放到 plugins 中才會啟用。

TypeScript#

在 JS 的專案中使用 TS#

當專案中 JS 檔和 TS 檔並存時,可以使用 ESLint 提供的 overrides 方法,保持原本對 JS lint 的規則,針對 TS 檔再套用其他規則:

module.exports = {
/* 原本針對 JS 寫的 eslint 設定... */
// overrides 中填寫針對 TS 的 ESLint 設定
overrides: [
{
files: ['./**/*.ts', './**/*.tsx'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'simple-import-sort'],
extends: [
/* ... */
],
rules: {
/* ... */
},
},
],
};

@typescript-eslint#

必看:

TL;DR#

  • TypeScript 是使用 tsc 來編譯 TypeScript 檔案,會吃到的設定檔是 tsconfig.json。當在 VSCode 中看到 ts 的錯誤時,就是由 tsc 產生。
  • tsconfig.eslint.json 是給 @typescript-eslint 吃的 tsconfig 檔,它會繼承 tsconfig.json。當在 VSCode 中出現 @typescript-eslint 的錯誤就是由它產生的。
  • 出現 Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser. 的錯誤時,表示 ESLint 想要解析的檔案並沒有被列在給 @typescript-eslint 所涵括到的檔案中。

所有規則#

  • rules @ typescript-eslint-plugin

Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser#

錯誤描述:

error Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: .eslintrc.js.
The file must be included in at least one of the projects provided

Screen Shot 2021-05-16 at 11.51.51 PM

問題原因:

tsconfig 會編譯到的檔案與 .eslintrc.js 中會處理到的檔案不同,例如 tsconfig 只會處理 /src 內的檔案,但 .eslintrc.js 則是會處理所有專案中的 js

解決方式:

  • 如果你不想要 lint 這個檔案,則使用 .eslintignore 或 ESLint 中的 ignorePatterns 來忽略掉這隻檔案
  • 如果你想要 lint 這個檔案:
    • 確定這個檔案有被列在 tsconfig 中的 include
    • 如果這個檔案想要被 lint 但並不歸在 tsconfig 要處理的範疇中(例如,tests/, 或 .eslintrc.js 等等),則建立另一個 tsconfig.eslint.json 的檔案,將這個檔案放在 include 中,參考這個 tsconfig.eslint.json.eslintrc.js。(之所以這樣能解決,是因為 tsc 預設會吃 tsconfig.json,在沒有填 include 規則的情況下,預設會是 ["**/*"] 也就是專案中的所有檔案,因此就不會有想要 lint 但卻沒有被 tsc 包含到的情況。但實際上,我們並不是真的要 lint 所有檔案,這時候針對要 lint 的檔案在用 tsconfig.eslint.json 來做限制)。

I get errors telling me "The file must be included in at least one of the projects provided" @ typescript-eslint

參考資料#

[官方]

Last updated on