コードのミスやレビューの手間を減らすためにlintやformatterをちゃんと活用する

自動でできるものは任せたいのでlintやformatterを活用したいと思いつつ、**これまでできていなかったのでwebpack5にアップデートしたのを機会にlintやformatterを見直す**ことにしました。

:::note info
【こんな方にオススメ！】
・これから使いたいけどどんな設定にしようか迷っている
・導入方法がわからず困っている
:::

記事を読んで下さった方が各種設定を理解して、適切に設定できるようになることを期待して記事を書きます！

## なぜlintやformatterを活用しよう思ったのか？
**チェックの工数を減らしたかった**からです。
さまざまなバックグラウンドをもった方が開発に関わっているので自分1人のチェックでは管理が厳しくなってきていると感じているからです。

:::note alert
レビュー依頼が全て自分のところに集まるのでチェックが遅延するとその分開発スケジュールが遅れます。
:::

また、コードレビューも本来はロジックや設計をメインに確認すべきだと考えています。
ただ、lintやformatterがないと「インデントは大丈夫か」「正しい位置で改行されているか」など自動でできるものを人の目で確認している状況です。

:::note alert
本質的なレビューに辿り着くまでに多くの時間を費やしてしまうのが課題に感じていました…。
:::

## webpackを利用している環境で導入する
formatterはPrettierに構文チェックはlinterに任せる構成にしたいと思います。
webpack5ではwebpackのプラグイン`eslint-webpack-plugin`と`stylelint-webpack-plugin`の利用が推奨されているようです。

:::note alert
`eslint-webpack-plugin`の登場で、`eslint-loader`は2020年9月に非推奨になっているようなのでwebpackをバージョンアップした際は注意してください。
また、`eslint-webpack-plugin`と`stylelint-webpack-plugin`の3.0はwebpack5でしか動作しないのでwebpack4で2つのプラグインを利用するときはバージョンにご注意ください。
:::

### 設定できるOptions
`eslint-webpack-plugin`と`stylelint-webpack-plugin`は引数としてoptionsを渡せます。
指定できる引数の種類は同じですが、デフォルトの値が若干違います。

|引数|指定できるもの|JSデフォルト/CSSデフォルト|
|--|--|--|
|configFile（StyleLintのみ）|configファイルの位置を定義|undefined|
|context|ファイルのルートを示す文字列|compiler.context|
|eslintPath（ESLintのみ）|リンティングに使用されるインスタンスへのパス|eslint|
|extensions|チェックする拡張子を指定|js / ['css', 'scss', 'sass']|
|exclude|除外するファイルやディレクトリを指定|node_modules / ['node_modules', compiler.options.output.path]|
|resourceQueryExclude|除外するリソース クエリを指定|[]|
|files|ディレクトリ、ファイル、グログを指定|null|
|fix|自動修正機能|false|
|formatter|eslintメッセージの出力のフォーマットを設定|stylish / string|
|lintDirtyModulesOnly|変更されたファイルのみlintを実行|false|
|stylelintPath（StyleLintのみ）|リンティングに使用されるインスタンスへのパス|stylelint|
|threads|スレッドプール全体でlintタスクを実行|false|
|emitError|エラーを通知してくれる|true|
|emitWarning|警告を通知してくれる|true|
|failOnError|エラーがある場合ビルドを停止させる|true|
|failOnWarning|警告がある場合にbuildを停止させる|false|
|quiet|エラーを報告処理してくれる、警告は無視される|false|
|outputReport|エラーをファイルとして出力してくれる|false|

:::note info
グロブとは、ファイル名やディレクトリ名をワイルドカードでマッチングするためのパターンを定義するための用語
:::

### outputReportを生成する
古いコードはLint導入時にはどうしてもエラーが多くなってしまうと思います…。
ターミナルだけではエラーの量が多すぎて最初に出たエラーがわからなくなってしまうので`outputReport`を生成することになりました。

outputReportは下記のように設定します。

```javascript:webpack.common.js
plugins: [
  new ESLintPlugin({
    outputReport: {
       filpath: './eslint_outputReport.html',
    }
  }),
],
```

`./ファイル名`で指定するとoutput先をdist/sp/jsで指定していた場合はその配下に生成されます。

生成されたファイルは下記の用の表示となり、どのファイルの何行目にどのLintエラーが表示されたかわかります。
![スクリーンショット 2022-12-19 17.49.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146612/be782484-76e8-ff22-a0c7-0315f948f234.png)
少し見づらいのがネックです…。
フォーマットの仕方は調べてみましたが答えを見つけられませんでした…

## ESLint
インストールして、webpackでプラグインの読み込みと利用できるように追加します。

```javascript
yarn add -D eslint eslint-webpack-plugin
```

```json:package.json
"devDependencies" : {
  "eslint": "^8.29.0",
  "eslint-config-airbnb-base": "^15.0.0",
  "eslint-plugin-import": "^2.26.0",
  "eslint-webpack-plugin": "^3.2.0",
}
```

```webpack.common.js
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
  plugins: [new ESLintPlugin()],
}
```

https://webpack.js.org/plugins/eslint-webpack-plugin/

https://eslint.org/docs/latest/rules/

ESLintのルールは`.eslintrc.js`に記述します。

:::note info
eslintrcの形式はjson/jsのどちらが推奨されているわけでもなさそうだったので今回はjs形式で記述することにしました。
:::

雛形だけ用意してエラー文を見ながらルールを追加していきたいと思います。

```javascript:.eslintrc.js
module.exports = {
  rules: {
    // ここにESLintのリファレンスとエラーを見ながら必要なルールを追加
  }
};
```

:::note warn
nodeのバージョンが古いことでエラーが出ることがあります。
私は、jset-workerとnodeに互換性がないと怒られたのでnodeのバージョンを上げました…
:::

## StyleLint
ESLintと同様にインストールとwebpackで利用できるように設定します。

```javascript
yarn add -D stylelint stylelint-scss stylelint-webpack-plugin
```

```json:package.json
"devDependencies" : {
  "stylelint": "^14.16.0",
  "stylelint-config-prettier-scss": "^0.0.1",
  "stylelint-config-standard-scss": "^6.1.0",
  "stylelint-webpack-plugin": "^3.3.0",
}
```

```webpack.common.js
const StylelintPlugin = require('stylelint-webpack-plugin');
module.exports = {
  plugins: [new StylelintPlugin()],
}
```

https://webpack.js.org/plugins/stylelint-webpack-plugin/

https://stylelint.io/

StyleLintもjs形式で記述します。

```javascript:.stylelintrc.js.js
module.exports = {
  'rules' : {
    // 緩和したいルールを追加 ↓こんな感じ
    'selector-id-pattern': null,
  }
};
```

## Prettier
PrettierをESLintやStyleLintと併用する時はリンターのルールが競合します。
衝突する可能性のあるルールをオフにしてくれるのが`eslint-config-prettier`と`stylelint-config-prettier`です。

https://github.com/prettier/eslint-config-prettier

https://github.com/prettier/stylelint-config-prettier

https://github.com/prettier/prettier/blob/554b15473dd4032a036d7db91a8f579e624c9822/docs/integrating-with-linters.md

Prettierをインストールして`package.json`のscriptsにコマンドを記述します。
lintが終わったらフォーマッターが走るようにして自動で整形できるように設定しておきます。

```json:package.json
"scripts": {
  "format": "prettier --write src/",
  "lint": "npm run lint && npm run format",
}
```

:::note warn
私が開発する環境はPHPも記述されていることがあるので自動で整形されるとエラーでページが表示されなくなることがあるためvscodeのプラグインは使用していません…。
:::

## まとめ
どれほど手間が掛かってもLintは導入すべきだと考えています。
HTML・CSS・JavaScriptの記述方法が**整っていないことは開発効率を低下につながる**からです。

開発効率を低下させる原因は、
- 統一されていないとコードが読みづらくなるのでコードレビューに時間がかかる
- 書き方のルールが統一されていないと、何が正しいか判断できず問い合わせなどコミュニケーションコストがかかる

などがあげられます。

統一されていないからといって人の目で発見して、指摘するのは相当の量力と集中力が必要です。

:::note info
Lintやformatterにミスを発見・修正してもらい、レビューの目的である設計への指摘やユーザービリティの配慮、コアロジックの議論するための時間を生み出すために必要だと思っています！
:::

また、レガシーな環境に導入する時は**リントルールがデフォルトのままだとエラーたくさんが出るのでlintコマンドを走らせてから終わるまで1分以上かかる**こともあります。

:::note warn
不本意ではありますが、一時的にルールを甘くして少しずつ厳しくしていくのが現実的な方法だと考えています！
:::

一番厳しい状態にしておけるのが望ましいと考えていますが、サービスの状況によって異なるのでルールについては都度相談して決めていけると良いと考えます！

適切なルールを設定しつつ、開発工数の削減につながるヒントになることを祈っています！