【VSCode】ESLint（fixあり/fixなし）とPrettierを保存時に走らせる

#2021年1月12日追記
<font color="red">**本稿の方法はすでに推奨されない方法となっている箇所がございます**</font>ので何卒ご了承ください。詳細は以下をご覧ください。

---

[eslint-plugin-prettier](https://www.npmjs.com/package/eslint-plugin-prettier)は現在[Prettier公式](https://github.com/prettier/prettier/blob/554b15473dd4032a036d7db91a8f579e624c9822/docs/integrating-with-linters.md)にて
>These are generally not recommended, but can be useful in certain circumstances.
（日本語訳：これらは一般的には推奨されませんが、特定の状況で役立つ場合があります。 - [Google翻訳](https://translate.google.co.jp/)より）


と言及され、特定の状況以外では非推奨となりました。

#概要
VSCode上でESLintとPrettierを保存時に走らせます。
Node.jsとVSCodeのインストールは終了しているものとします。

[ESLint](https://eslint.org/)
[Prettier](https://prettier.io/)

# 目次
- ESLintの設定
- Prettierの設定
- ESLintとPrettierの連携
- 保存時の設定


#ESLintの設定
## ライブラリインストール
必要なライブラリをインストールします。

```
npm install -D eslint typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser
```
以下のライブラリはTypeScript用です。
[TypeScript](npmjs.com/package/typescript)
[@typescript-eslint/eslint-plugin](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin)
[@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser)

## 設定ファイル作成
ライブラリをインストールしたら設定ファイルを作成します。

```
./node_modules/.bin/eslint --init
```

各自の環境に合わせて質問に回答します。
本稿では以下の設定をおこないます。

- 構文チェックだけではなくスタイルも整える。（今回はAirbnb）
- TypeScriptを使用する。
- 設定ファイルはJSONで作成する。

```
? How would you like to use ESLint? To check syntax, find problems, and enforce code stylede style
? What type of modules does your project use? JavaScript modules (import/export)
? Which framework does your project use? None of these
? Does your project use TypeScript? Yes
? Where does your code run? Browser
? How would you like to define a style for your project? Use a popular style guidecript
? Which style guide do you want to follow? Airbnb: https://github.com/airbnb/javascript
? What format do you want your config file to be in? JSON
? Would you like to install them now with npm? Yes

（省略）

Successfully created .eslintrc.json file in [現在のパス]
```

`.eslintrc.json`が作成されました。
`.eslintrc.json`を編集し、TypeScriptの推奨ルールを設定します。

```JSON:.eslint.json
	"extends": [
        "airbnb-base",
        // 以下を追加する。
		"plugin:@typescript-eslint/eslint-recommended",
		"plugin:@typescript-eslint/recommended"
	],
```

## ターミナルから実行
ESLintをとりあえず実行できるようになったので試します。
ESLintの初期設定では`console.log()`を使用すると警告が出るので以下のファイルを作成しESLintを実行します。

```typescript:src/sample.ts
const func =()=>{
console.log("Hello world")
}
```


```
./node_modules/.bin/eslint src/sample.ts

\src\sample.ts
  1:7   warning  'func' is assigned a value but never used        @typescript-eslint/no-unused-vars
  1:12  error    Operator '=' must be spaced                      space-infix-ops
  1:13  warning  Missing return type on function                  @typescript-eslint/explicit-function-return-type
  1:14  error    Missing space before =>                          arrow-spacing
  1:17  error    Missing space after =>                           arrow-spacing
  1:18  error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  2:1   error    Expected indentation of 2 spaces but found 0     indent
  2:1   warning  Unexpected console statement                     no-console
  2:13  error    Strings must use singlequote                     quotes
  2:27  error    Missing semicolon                                semi
  2:27  error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  3:2   error    Missing semicolon                                semi
  3:2   error    Newline required at end of file but not found    eol-last

✖ 13 problems (10 errors, 3 warnings)
  10 errors and 0 warnings potentially fixable with the `--fix` option.
```
警告とエラーがたくさん出ているのでESLintの設定はひとまず終了です。

# Prettierの設定
## ライブラリインストール
ESLint同様必要なライブラリをインストールします。

```
npm install -D prettier eslint-config-prettier eslint-plugin-prettier
```

[eslint-config-prettier](https://www.npmjs.com/package/eslint-config-prettier)
[eslint-plugin-prettier](https://www.npmjs.com/package/eslint-plugin-prettier)[^1]

## 設定ファイル作成
`.eslintrc.json`と同じ階層に`.prettierrc.json`を手動で作成します。
本稿では動作していることが分かりやすいのでインデントをタブにします。

```JSON:.prettierrc.json
{
    "useTabs": true,
    "tabWidth": 4
}
```

## ターミナルから実行
作成した`src/sample.ts`をフォーマットします。

```TypeScript:src/sample.ts
const func=()=>{
console.log("Hello world")
}
```

実行します。
--writeは整形してファイルを上書き保存してくれるオプションです。

```
./node_modules/.bin/prettier src/sample.ts --write
```

ファイルを見るとタブでのインデントも末尾のセミコロンも挿入されています。

```TypeScript:src/sample.ts
const func = () => {
	console.log("Hello world");
};
```
Prettierの設定は終了です。

#ESLintとPrettierの連携
このままではESLintとPrettierの設定がバッティングする可能性があるので`.eslintrc.json`にESLintとPrettierの連携を設定します。
あわせてPrettierの推奨ルールも設定します。

```JSON:.eslintrc.json
	"extends": [
		"airbnb-base",
		"plugin:@typescript-eslint/eslint-recommended",
		"plugin:@typescript-eslint/recommended",
		// 以下を追加する。
		"plugin:prettier/recommended",
		"prettier"
	],
```
Prettierのプラグインは必ずextends内の一番下に書く必要があるらしいので則ります。

# 保存時の設定
VSCodeのプラグインをインストールします。

[ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
![eslint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684084/adad8fdb-1583-be58-3ff1-dbe0fcacf2c1.png)

[Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
![prettier.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684084/beb83e0f-707e-5d40-99e2-1c5bbf734b9d.png)

ここからは以下の2通りの方法があります。

- ESLintのfixを保存時に実行し、fixでフォーマットをおこなう場合
- ESLintのfixを保存時に実行せず、VSCodeのPrettierのプラグインでフォーマットのみおこなう場合

順に記載します。

## ESLintのfixを保存時に実行し、fixでフォーマットをおこなう場合

VSCodeの.setting.jsonを編集します。
***"editor.formatOnSave"をfalseに設定するとESLintのfixが対象でないファイルのフォーマットが行われないため、ESLintでfixを実行するファイルのみ"editor.formatOnSave"をfalseにしましょう。***

```JSON:.setting.json
{
	"editor.codeActionsOnSave": {
		"source.fixAll.eslint": true
	},
	"editor.defaultFormatter": "esbenp.prettier-vscode",
	"editor.formatOnSave": true,
	"[typescript]": {
		"editor.formatOnSave": false
	}
}
```

以下のファイルを作成し、保存します。

```TypeScript:src/sample.ts
const func =()=>{
console.log("Hello world")
}
```
![format.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684084/18982921-9a09-26e0-fedb-64d04aa8d30c.png)

フォーマットされました。


## ESLintのfixを保存時に実行せず、VSCodeのPrettierのプラグインでフォーマットのみおこなう場合

VSCodeの`.setting.json`を編集します。

```JSON:.setting.json
{
	"editor.defaultFormatter": "esbenp.prettier-vscode",
	"editor.formatOnSave": true
}
```

以下のファイルを作成し、保存します。

```TypeScript:src/sample.ts
const func =()=>{
console.log("Hello world")
}
```
![format.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684084/1a5ac2a3-bcbb-0eeb-2a81-fb92a48acd15.png)

こちらでも問題なくフォーマットされます。

### 設定のバッティングについて
`.eslintrc.json`と`prettierrc.json`で同じルールで異なる設定をしている場合は`.eslintrc.json`の設定が優先されます。
例えばESLintではシングルクオートを使用する設定を記載し、Prettierではダブルクオートを使用する設定を記載した場合はシングルクオートに置き換えられます。

---
***最低限の設定は以上です。手軽に統一されたコードを書きましょう！***

[^1]: 2021年1月12日現在非推奨。[追記](#2021年1月12日追記)参照。