ESLintとPrettier、いい加減ちゃんと使えるようになろ。

2023/01/02に公開約10,500字

まえがき

約2年間JavaScript/TypeScriptを使う開発現場で働いてきたが、
どのプロジェクトでもESLintは当たり前のように導入されており
CommitするときにLintチェックが走り、エラーがあればCommitできない仕組みになっていた。

このESLintをただ何となく使う側であったが、0から構築して導入する力も欲しいと思い、
この記事を書くことにする。

※参考になった記事
👉ESLint 最初の一歩
👉ESLint の設定ファイル (.eslintrc) の各プロパティの意味を理解する
👉ESLint - Prettier連携のやり方と仕組み
👉ESLint + Prettierを導入したTypeScript開発環境

先に総括

✅レビューの手間を減らす手段としてESLint/Prettierはめっちゃ良い手段。
  ESLint/Prettierを使いこなすことは確実に+になるのでちゃんと理解する👍

ESLint

✅ESLintとはJavaScriptのリンター(静的解析ツール)
✅デフォルトだとESLintチェック対象のRuleはゼロ。
✅AirbnbやGoogleが複数のRuleをまとめているRule一覧(共有設定)をextendsで読み込み、これをbaseとする。
✅extendsで取り込んだ共有設定に定義されている一部のRuleを上書きしたり、追加したりでその現場固有のコーディングスタイルを整えていくことになる。

Prettier

✅PrettierとはJavaScriptの自動フォーマッター。
✅Prettier単体で利用可能。
✅だが、ESLintと一緒に使うパターンがほとんど。
✅ESLintと一緒に使う場合はフォーマット系のRulesはESLintのチェック対象外にする(Prettierで自動整形する)ため、eslint-config-prettierをextendsに追加する必要がある。

ESLintとは

JavaScriptのリンター(ソースコードを分析し問題点を指摘してくれる静的解析ツール)である。
JavaScriptのリンターであるESLintは、プラグイン経由でTypeScriptにも適用可能。

✅スクリプト言語であるJavaScriptはコンパイルの過程がないため、
  実行前にエラーを検知するための仕組み(リンター)が発達している。

✅以下の理由よりリンターを理解/活用することは絶対に+になる👍
 1. 人間によるレビューの手間を減らす。
 2. HumanErrorによる見過ごしの防止。

個人的には2のメリットが大きい。👪人間ではなく🤖機械に任せられるものは任せた方がいい。

まず使ってみよう。

任意の場所でプロジェクトフォルダ作成
mkdir eslint-practice
cd eslint-practice
package.json作成
npm init
eslintインストール
npm install eslint --save-dev
package.jsonにlintコマンド追加
{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
+   "lint": "eslint ."
  },
+ "devDependencies": {
+   "eslint": "^8.30.0"
+ }
}
.設定ファイル(.eslintrc.json)作成
{
    "extends": ["eslint:recommended"],
    "plugins": [],
    "parserOptions": {},
    "env": {"browser": true},
    "globals": {},
    "rules": {}
}
test.js作成
function hello(name) {
    document.body.textContent = "Hello, " + nama + "!"
}

hello("World");
lintコマンド実行 → 2件のエラー検知
C:\Users\daisu\Desktop\workspace\eslint-practice>npm run lint

> eslint-practice@1.0.0 lint
> eslint .


C:\Users\daisu\Desktop\workspace\eslint-practice\test.js
  1:16  error  'name' is defined but never used  no-unused-vars
  2:45  error  'nama' is not defined             no-undef

✖ 2 problems (2 errors, 0 warnings)

チェック対象のRulesは、デフォルトは0個。

"extends": ["eslint:recommended"],を消すと、先ほどのエラーが消える。

C:\Users\daisu\Desktop\workspace\eslint-practice>npm run lint

> eslint-practice@1.0.0 lint
> eslint .

C:\Users\daisu\Desktop\workspace\eslint-practice>

このことから分かるのは、
チェック対象のRulesはデフォルトでは0個。
eslint:recommendedというESLintコミュニティが用意してくれたRules一覧をextendsで取り込む=それらをチェックしている。

eslint:recommendedの中身

eslint公式サイトeslint:recommendedでチェック対象のrule一覧が記載されている。沢山あるので、1つ1つまとめてみようと思ったが、内容としては結構当たり前なものが多いので、改めて確認する必要性はないと感じたのでここでは割愛する。

ruleを追加する。

先ほどのeslint:recommendedのようにextendsで追加したRules以外のRuleを追加したい場合は、↓のようにrulesに追加する。

.eslintrc.json
{
    "extends": "eslint:recommended",
    "env": {"browser": true},
    "rules": {
        // []の第1引数に【error/warn/off】のいずれかを設定する。
	// []の第2引数に、rule固有のOptionを定義する。semiだと"never"だというOptionがある。
        "semi": ["error", "never"]
    }
}

extendsで共有設定を読み込む。

extendsプロパティで読み込む対象は共有設定(Sharable configuration)と呼ぶ。
✅内部のルール設定が重複する場合は、後から指定したものが優先されるので注意

eslint-config-airbnb-baseを定義する場合
{
    "extends": "eslint-config-airbnb-base",
    // または"eslint-config-"は省略可能なので
    "extends": "airbnb-base"
    "env": {"browser": true},
    "rules": {
        "semi": ["error", "never"]
    }
}

共有設定は色々ある。JavaScript のコーディングスタイルとしてはAirbnb のスタイルが有名なので、制約がなければAirbnbのものを採用するで問題ないかと。
eslint-config-airbnb【 including ECMAScript 6+ and React.】
eslint-config-airbnb-base【 including ECMAScript 6+ ※NO React】
eslint-config-standard
eslint-config-google
eslint-config-react-app

どのeslint-config-*を利用するかというのはそのプロジェクト次第である。↓のような比較記事もあったので参考に置いておく。
Airbnb vs Standard – ESLint のスタイルは何を選ぶべきか?

(自分用)Airbnb-baseでチェック対象である&違反してたらErrorになるRuleの中で、対象外/Warning扱いにしたいやつ。

アロー関数関連

arrow-body-style

Require braces({}中括弧/波括弧) around arrow function bodies

アロー関数のボディを「{}」で囲わせるかどうか。

🔴airbnb-baseではチェック対象であり、違反してるとErrorとなる。
 チェック対象外にしたいなら↓のように定義しておく。

.eslintrc.json
{
    "extends": ["airbnb-base"],
    "rules": {
        "arrow-body-styled": "off"
    }
}

arrow-parens

Require parentheses(括弧()) around arrow function arguments

アロー関数の引数に「()括弧」をつけるかどうか。

🔴airbnb-baseではチェック対象であり、違反してるとErrorとなる。
 チェック対象外にしたいなら↓のように定義しておく。

.eslintrc.json
{
    "extends": ["airbnb-base"],
    "rules": {
        "arrow-parens": "off"
    }
}

Styling系

padded-blocks

Require or disallow padding within blocks

ブロック(波括弧{})前後に、空白行(Padding)を入れるか。

OK
if (a) {

    b();

}
NG
if (a) {
    b();
}

🔴airbnb-baseではチェック対象であり、違反してるとErrorとなる。
 チェック対象外にしたいなら↓のように定義しておく

.eslintrc.json
{
   "extends": ["airbnb-base"],
   "rules": {
       "padded-blocks": "off"
   }
}

max-len

Enforce a maximum line length

1行の最大文字数の設定

🔴airbnb-baseではチェック対象であり、最大文字数(Default:80)を超えてたらErrorとなる。

ErrorではなくWarning扱いとしたい場合
{
   "extends": ["airbnb-base"],
   "rules": {
       "max-len": "warn"
   }
}
最大文字数を150にする。
{
    "extends": ["airbnb-base"],
    "rules": {
        "max-len": [
	    "warn", 
	    {
               "code": 150,
               "ignoreComments": true,
               "ignorePatter": "^import .*"
             }
         ]
    }
}

no-plusplus

Disallow the unary operators ++ and --

Because the unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code.

便利な++,--の利用を禁止する。なぜなら↓のように++/--前後のwhitespaceの違いによって動きが変わってしまう可能性があるから。

expected
var i = 10;
var j = 20;

i ++
j
// i = 11, j = 20
unexpected
var i = 10;
var j = 20;

i
++
j
// i = 10, j = 21

🔴airbnb-baseではチェック対象であり、違反してるとErrorとなる。
 warn扱いにするなら↓のように定義しておく

.eslintrc.json
{
    "extends": ["airbnb-base"],
    "rules": {
        "no-plusplus": ["warn", { allowForLoopAfterthoughts: true }]
    }
}

no-underscore-dangle

Disallow dangling underscores in identifiers

As far as naming conventions for identifiers go, dangling underscores may be the > most polarizing in JavaScript.

Varible系

no-shadow

Disallow variable declarations from shadowing variables declared in the outer scope

Shadowing is the process by which a local variable shares the same name as a variable in its containing scope.

ローカル変数名が外部スコープの変数名と被ってしまう(Shadow)ことを、許すか許さないか。

NG
var a = 3;
function b() {
    var a = 10;
}

airbnb-baseではチェック対象であり、違反してるとErrorとなる。
🔴ただ
グローバル変数に対するShadowingの検知**はoptionでbuiltinGlobalsをtrueにしないと✅されないので、↓のように設定する必要がある。

.eslintrc.json
{
   "extends": ["airbnb-base"],
   "rules": {
       "no-plusplus": ["error", { builtinGlobals: true }]
   }
}

ECMAScript6系

prefer-destructuring

Require destructuring from arrays and/or objects

配列、オブジェクト内から1値を取り出す際にDestructuring assignmentを使わせるかどうか。
ECMAScript6から導入された書き方。
✅配列、オブジェクトから複数の値をそれぞれの変数に格納したい場合は便利なので使うべき👍

Destructuring assignmentを使わない場合
// indexを指定して要素を取得する。
var foo = array[0];

// プロパティ名を指定して取得する。
var foo = object.foo;
var foo = object['foo'];
Destructuring assignmentを使う場合
// []で要素を取り出す。
const arr = [1,2,3,4,5];
const [a,b,c] = arr;
console.log(a, b, c); // 1, 2, 3

// {}で要素を取り出す。。
const person = { name: "DAISUKE", age: 26 };
const { name, age } = person;
console.log(`I'm ${name}. ${age} years old.`) //  "I'm DAISUKE. 26 years old."

🔴airbnb-baseではチェック対象であり、違反してるとErrorとなる。
 warn扱いにするなら↓のように定義しておく

.eslintrc.json
{
    "extends": ["airbnb-base"],
    "rules": {
        "prefer-destructuring": ["warn"]
    }
}

ESLintとPrettierと併用する

ESLintで、コードチェックする。
.eslintrc.jsonに、チェック対象のRulesを定義する。

Prettierで、フォーマットする。
prettier.config.jsに、フォーマット設定を定義する。

ESLintのRulesには、フォーマット系のものが含まれている。しかしフォーマットはPrettierに一任するので、ESLintのRulesからフォーマット系のRulesは取り除く。
 ↓
取り除くためにeslint-config-prettierをextendsに追加する。

Prettierインストール

npm install prettier --save-dev

フォーマット系のRulesをESLintチェック対象外にする。

npm install eslint-config-prettier --save-dev
extendsの"最後"に追加する。
{
    "extends": ["airbnb-base", "prettier"],
}

Prettierの設定ファイル

Prettierによる自動フォーマットのRulesをここに記載する。

prettier-config.js
{
  printWidth: 150,
  tabWidth: 2,
  semi: true,
  singleQuote: true,
  trailingComma: 'all',
  endOfLine: 'lf'
}

VSCode -> ファイル保存時にPrettierで自動フォーマットさせる。

ESLint(dbaeumer.vscode-eslint)と Prettier(esbenp.prettier-vscode) の拡張機能をインストールする。

.vscode/settings.json追加
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true 
}

ここまでの設定を完了すれば、VSCodeでのファイル保存時にprettier-config.jsの設定に基づいてPrettierが自動フォーマットしてくれる👍

Discussion

ログインするとコメントできます