もうprettierで消耗したくない人へのvueでのeslint設定

タイトル通り。vscodeとvuejsを使ってのlintの設定を**prettierなし**でやってみた。

## tl;dr

対象ファイルとpackage.jsonと.eslintrc.jsの対応表👇

|構文チェック・自動フォーマット対象ファイル | npmライブラリ(package.json) | .eslintrc.jsでのextends|
|:--|:--|:--|
|`.vue(<template>)`|`eslint-plugin-vue`|`plugin:vue/recommended`|
|`.vue(<script>)`|`eslint`|`eslint:recommended`|
|`. js`|`eslint`|`eslint:recommended`|

```sh
yarn add -D eslint eslint-plugin-vue
```

```javascript:.eslintrc.js
module.exports = {
  plugins: [
    "vue"
  ],
  extends: [
    'eslint:recommended',
    'plugin:vue/recommended'
  ],
  rules: {
    // タグの最後で改行しないで
    "vue/html-closing-bracket-newline": [2, {"multiline": "never"}],
    // 不要なカッコは消す
    "no-extra-parens": 1,
    // 無駄なスペースは削除
    "no-multi-spaces": 2,
    // 不要な空白行は削除。2行開けてたらエラー
    "no-multiple-empty-lines": [2, {"max": 1}],
    // 関数とカッコはあけない(function hoge() {/** */})
    "func-call-spacing": [2, "never"],
    // true/falseを無駄に使うな
    "no-unneeded-ternary": 2,
    // セミコロンは禁止
    "semi": [2, "never"],
    // 文字列はシングルクオートのみ
    "quotes": [2, "single"],
    // varは禁止
    "no-var": 2,
    // jsのインデントは２
    "indent": [2, 2],
    // かっこの中はスペースなし！違和感
    "space-in-parens": [2, "never"],
    // コンソールは許可
    "no-console": 0,
    // カンマの前後にスペース入れる？
    "comma-spacing": 2,
    // 配列のindexには空白入れるな(hogehoge[ x ])
    "computed-property-spacing": 2,
    // キー
    "key-spacing": 2,
    // キーワードの前後には適切なスペースを
    "keyword-spacing": 2,
  }
}
```

```json:settings.json
{
	"eslint.validate": [
        "javascript",
        "javascriptreact",
        {
          "language": "vue",
          "autoFix": true,
        },
	  ],
    "eslint.autoFixOnSave": true,
}
```



## 環境

とあるプロジェクトでnuxt+vuejsを使って実装をしていた時の話。開発初期段階だったのもありnuxtが2.4をリリースしたというのでアップデートしてみた。しかし急にeslintとprettierの構文チェック・自動フォーマットが効かなくなった。。。。

開発環境はvscode。

package.jsonのパッケージはだいたいこんな感じ。

- vue@2.6.6
- nuxt@2.4.3
- babel-eslint@7.2.3
- eslint@4.19.1
- eslint-config-standard@10.2.1
- eslint-loader@1.9.0
- eslint-plugin-html@3.1.1
- eslint-plugin-import@2.7.0,
- eslint-plugin-node@5.1.1,
- eslint-plugin-promise@3.5.0,
- eslint-plugin-standard@3.0.1,
- eslint-plugin-vue@5.2.2
- eslint-config-prettier@4.0.0
- eslint-plugin-prettier@3.0.1

そこで、再び構文チェック・自動フォーマットが効くように半日頑張ったが無理だった。半日溶けた。

## 問題点

1. `eslint`系が12種と多い、多すぎる😇😇😇😇😇、どれが何の役割を果たしているかわからない
2. prettier・veturも絡んでいる
3. 依存関係がわからない(vscodeのconfig.json、`.eslintrc.js`にもprettierがある。)
4. 元々の設定もどこかしらのドキュメントを参考につぎはぎしていたので何の設定をどこで制御できるのかわからない


👉カオス味を減らしたい

👉👉prettierはもういらないのでは？？

👉👉👉**prettierをなくして最低限のeslintによる構文チェック・自動フォーマットを設定する**

## 手順

僕の`.eslintrc.js`がいつまでも正しいかどうかわからないので記録を残しておく。苦しんで覚えたい人は再現してほしい。おれのしかばねをこえてゆけ💀💀💀


### .vueの構文チェックその１

まずは自動フォーマットはひとまず無視して、構文チェックができるようにする。

[eslint公式](https://eslint.org/)にはvuejsに関する記述はなかったが、 [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue)には　`Official ESLint plugin for Vue.js`という記載があったのでこれを信じる。



これだけでいいみたい。

- eslint
- eslint-plugin-vue

> https://vuejs.github.io/eslint-plugin-vue/user-guide/#installation

以下は不要なもの。多すぎ。使っている人はいますぐpackage.jsonから消し去ろう

- eslint-config-standard@10.2.1
- eslint-loader@1.9.0
- eslint-plugin-html@3.1.1
- eslint-plugin-import@2.7.0,
- eslint-plugin-node@5.1.1,
- eslint-plugin-promise@3.5.0,
- eslint-plugin-standard@3.0.1,
- eslint-config-prettier@4.0.0
- eslint-plugin-prettier@3.0.1



あとは `.eslintrc.js`の設定だけ。これでOK

```javascript:.eslintrc.js
module.exports = {
  plugins: [
    "vue"
  ],
  extends: [
    // 'eslint:recommended',
    'plugin:vue/recommended'
  ],
  rules: {
  }
}
```

> https://vuejs.github.io/eslint-plugin-vue/user-guide/#configuration



この段階ではまだvscodeでの自動フォーマットは効いていないはず。落ち着いてまずは構文チェックができるかを確認

```sh
# srcフォルダにvueファイルがある前提

$ eslint --ext .js,.vue src
# または
$ eslint "src/**/*.{js,vue}"
```



構文チェックがうまく走るとおそらくこんな表示になる。

```sh
$ yarn run eslint "pages/**/*.{js,vue}"
....
....
✖ 70 problems (21 errors, 49 warnings)
  13 errors and 49 warnings potentially fixable with the `--fix` option.


```

出力からわかると思うが、`--fix`をつけることでフォーマットすることができる。

このことから**eslintを用いることで、vueファイルの構文チェック・自動フォーマットができること**が確認できた。



### vscode上での自動フォーマット

こんどは`Cmd + Sft + P`で`setting`と打ち、`Open Settings(JSON)`を選択。

ここで、vscode上で**eslint**の**構文チェック・自動フォーマット**ができるように以下を設定

```json:settings.json
{
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    {
      "language": "vue",
      "autoFix": true,
    },
  ],
  "eslint.autoFixOnSave": true,
}
```

このことから**validate=構文チェック**かつ**autoFixOnSave=自動フォーマット**なのがわかる

試しに、`.vue`ファイルのtemplate内のインデントをぐちゃぐちゃにするとエラーが出て、`Cmd + S`を何回か押すと自動フォーマットができることが確認できる。

しかしまだ不完全のようである。`.vue`の`<script>`タグの中が全くフォーマットされていない

### .vueの構文チェックその２

`.eslintrc.js`を振り返り、以下の行をコメントアウト

```javascript:.eslintrc.js
module.exports = {
  plugins: [
    "vue"
  ],
  extends: [
    'eslint:recommended',
    'plugin:vue/recommended'
  ],
  rules: {
  }
}
```



すると、例えば以下のvueファイルで自動フォーマットをすると`console.log("hoge");;;;;;`の`;`が自動で消えるようになる

```diff
<template>
  <div>
    <p>aaaa</p>
  </div>
</template>

<script>
export default {
  created() {
-  	console.log("hoge");;;;;;
+  	console.log("hoge");
          const    a     =     "A"
    var b = (4+(1-1))
    let c = [  1  ,  2 ,  3]


    const d = "zzzzzzzz"
  }
}
</script>
```

🎊🎊🎊おめでとう🎊🎊🎊。ここまで来ればeslintの設定はほとんど終わり。だけどscriptの中はまだまだ混沌としているので、あとでカスタマイズ。



### rulesをカスタマイズ

#### `<template>`のカスタマイズ

今までの内容を見るに、vueファイルの`<template>`の構文チェックを行なっているのは **eslint-plugin-vue**であり、`<template>`は**eslint-plugin-vue**独自のルールが適用されている。

独自のルールは[ここ](https://vuejs.github.io/eslint-plugin-vue/rules/)にまとめられている。今回の設定（以下ファイル）では、 `'plugin:vue/recommended'`として導入されているので、`Priority A: Essential (Error Prevention)`と`Priority B: Strongly Recommended (Improving Readability)`の内容も含んでおり、一通りvuejs公式が推奨するルールはだいたい入っている。

```javascript:.eslintrc.js
module.exports = {
  plugins: [
    "vue"
  ],
  extends: [
    'eslint:recommended',     // これ
    'plugin:vue/recommended'
  ],
  rules: {
  }
}
```



`'plugin:vue/recommended'`に入っていないルールであっても自分で追加することができる。

例えば筆者は以下の部分をカスタマイズした。

```javascript:.eslintrc.js
  rules: {
    // タグの最後で改行しないで
    "vue/html-closing-bracket-newline": [2, {"multiline": "never"}],
  }
```

簡単にいうと、`2`はエラー。このルールを厳しく適用する

[html-closing-bracket-newline](https://vuejs.github.io/eslint-plugin-vue/rules/html-closing-bracket-newline.html)は、 `'plugin:vue/recommended'`には含まれているがカスタマイズしないと以下の構文のpタグがOKになってしまう。

```vue:sample.vue
<template>
  <div>
    <p
      hoge="#"
      huga="%%%"
      >
      aaaa
    </p>
  </div>
</template>
```

これは個人的には気に入らないので、`"multiline": "never"`という設定にした。

```diff
<template>
  <div>
    <p
      hoge="#"
-     huga="%%%"
-     >
+     huga="%%%">
      aaaa
    </p>
  </div>
</template>
```



注意点として、自動フォーマットができないルールもいくつかある。ルールの一覧画面に🔧マークがなければ自動フォーマットができないので注意しよう、



#### `<script>`をカスタマイズ

これが思ったよりしんどい。

これも今までの内容を見るに、`<script>`の構文チェックを行なっているのは**eslint**である。eslintのルールは[こちら](https://eslint.org/docs/rules/)にある。100個以上あってなかなかしんどいが、一通り目を通すと非常に勉強になるのでみなさんにも読んでほしい。



今回は`'eslint:recommended',`として導入しており、ルール一覧画面では✔️マークがあるルールは全て含まれている。（こちらも注意点として、自動フォーマットができないルールもいくつかある。ルールの一覧画面に🔧マークがなければ自動フォーマットができない。）

ただし、recommendedでは先ほど出てきた構文でも特に何もエラー・警告を吐かない。ツッコミどころしかないのだが。。

```javascript:sample.vue
          const    a     =     "A"
    var b = (4+(1-1))
    let c = [  1  ,  2 ,  3]


    const d = "zzzzzzzz"
```



これをどう直すかは人次第なので一意見として僕のrulesをいかに貼ります。

```javascript:.eslintrc.js
  rules: {
    // 不要なカッコは消す
    "no-extra-parens": 1,
    // 無駄なスペースは削除
    "no-multi-spaces": 2,
    // 不要な空白行は削除。2行開けてたらエラー
    "no-multiple-empty-lines": [2, {"max": 1}],
    // 関数とカッコはあけない(function hoge() {/** */})
    "func-call-spacing": [2, "never"],
    // true/falseを無駄に使うな
    "no-unneeded-ternary": 2,
    // セミコロンは禁止
    "semi": [2, "never"],
    // 文字列はシングルクオートのみ
    "quotes": [2, "single"],
    // varは禁止
    "no-var": 2,
    // jsのインデントは２
    "indent": [2, 2],
    // かっこの中はスペースなし！違和感
    "space-in-parens": [2, "never"],
    // コンソールは許可
    "no-console": 0,
    // カンマの前後にスペース入れる？
    "comma-spacing": 2,
    // 配列のindexには空白入れるな(hogehoge[ x ])
    "computed-property-spacing": 2,
    // キー
    "key-spacing": 2,
    // キーワードの前後には適切なスペースを
    "keyword-spacing": 2,
  }
```

ちなみに`2`は先ほど出てきたが、`1`と`0`もここで出てきた。`1`は警告（エラーではない）、`0`は許可。



例えばこのルールで先ほどの構文を自動フォーマットするとこうなる。幸せ。

```javascript:sample.vue
    const a = 'A'
    let b = 4+(1-1)
    let c = [ 1, 2, 3]

    const d = 'zzzzzzzz'
```

## まとめ。

prettierの設定に疲れた人はやって見ると良い。

対象ファイルとpackage.jsonと.eslintrc.jsの対応表👇

|構文チェック・自動フォーマット対象ファイル | npmライブラリ(package.json) | .eslintrc.jsでのextends|
|:--|:--|:--|
|`.vue(<template>)`|`eslint-plugin-vue`|`plugin:vue/recommended`|
|`.vue(<script>)`|`eslint`|`eslint:recommended`|
|`. js`|`eslint`|`eslint:recommended`|

```sh
yarn add -D eslint eslint-plugin-vue
```

```javascript:.eslintrc.js
module.exports = {
  plugins: [
    "vue"
  ],
  extends: [
    'eslint:recommended',
    'plugin:vue/recommended'
  ],
  rules: {
    // タグの最後で改行しないで
    "vue/html-closing-bracket-newline": [2, {"multiline": "never"}],
    // 不要なカッコは消す
    "no-extra-parens": 1,
    // 無駄なスペースは削除
    "no-multi-spaces": 2,
    // 不要な空白行は削除。2行開けてたらエラー
    "no-multiple-empty-lines": [2, {"max": 1}],
    // 関数とカッコはあけない(function hoge() {/** */})
    "func-call-spacing": [2, "never"],
    // true/falseを無駄に使うな
    "no-unneeded-ternary": 2,
    // セミコロンは禁止
    "semi": [2, "never"],
    // 文字列はシングルクオートのみ
    "quotes": [2, "single"],
    // varは禁止
    "no-var": 2,
    // jsのインデントは２
    "indent": [2, 2],
    // かっこの中はスペースなし！違和感
    "space-in-parens": [2, "never"],
    // コンソールは許可
    "no-console": 0,
    // カンマの前後にスペース入れる？
    "comma-spacing": 2,
    // 配列のindexには空白入れるな(hogehoge[ x ])
    "computed-property-spacing": 2,
    // キー
    "key-spacing": 2,
    // キーワードの前後には適切なスペースを
    "keyword-spacing": 2,
  }
}

```

```json:settings.json
{
	"eslint.validate": [
        "javascript",
        "javascriptreact",
        {
          "language": "vue",
          "autoFix": true,
        },
	  ],
    "eslint.autoFixOnSave": true,
}
```

## おまけ

eslintのruleと死闘を繰り広げてるときに投げられた無慈悲なメッセージ

<img width="826" alt="スクリーンショット 2019-02-21 20.18.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/158393/dffc0ed1-7508-ddcf-21f7-e17a3dbcdf6c.png">



>ESLintを入れただけでは今までのおまえのコードは何一つ綺麗にならない。おまえはメキシコの夕日よりも赤いコードを見ることになるだろう。
>
>https://qiita.com/khsk/items/0f200fc3a4a3542efa90