eslint, prettier の基本設定

## Prologue

`eslint` はこれまで誰かが作った設定で開発を行っていたのですが、新しくプロジェクトを作る場合には必須だな、と思い基本的な部分を作成してみました。
最初は自力で一から作っていたのですが、あまりに `rules` の設定が膨大すぎるため、何度かやり直しを行なっています。
そのため追加する module や library 等で抜けている部分がありましたらご連絡ください。
   
基本はDocument通りになるため、自身で設定する場合には都度公式を確認することをお勧めします。


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


## 環境

- macOS: v10.15.5
- node.js: v12.18.2
- terminal: iTerm
- エディタ: VS Code
- パッケージマネージャ: `yarn`
- Composition API: 1.0.0-beta.4

## 基本的な設定について

今回はチームで開発する場合等に、`pull` や `merge` ごとに差分が出ないようにすることを目指します。
そのため以下を統一できるようにします。

- インデント
- ダブルクォート / シングルクォート
- 改行

また、Nuxt.js × TypeScript で作成したプロジェクトに置いたため、それ前提で話を進めています。

- `Prettier` と `ESLint` の違い

Prettier: コードフォーマッター。コードを解析し、独自のルールでリプリントすることにより一貫したスタイルを提供する。
ESLint: 構文チェックができる。

参考: 
- [Nuxt > ESLint と Prettier](https://ja.nuxtjs.org/guide/development-tools/#eslint-%E3%81%A8-prettier)
- [Prettier](https://prettier.io/docs/en/comparison.html)
- [Prettier(GitHub)](https://github.com/prettier/prettier#intro)

## プロジェクトの作成

`yarn create nuxt-app sample` で作成した際に `Linting tools` で `Prettier` を選択すると、初期の `devDependencies` は以下のようになります。
既に `eslint-config-prettier`, `eslint-plugin-prettier`, `prettier` がインストールされている状態です。

``` JS
   "devDependencies": { 
     "@nuxt/typescript-build": "^1.0.3", 
     "@vue/test-utils": "^1.0.3", 
     "babel-core": "7.0.0-bridge.0", 
     "babel-jest": "^26.0.1", 
     "eslint-config-prettier": "^6.11.0", 
     "eslint-plugin-prettier": "^3.1.4", 
     "jest": "^26.0.1", 
     "node-sass": "^4.14.1", 
     "prettier": "^2.0.5", 
     "sass-loader": "^8.0.2", 
     "ts-jest": "^26.1.0", 
     "vue-jest": "^3.0.4" 
   } 
```

追加で下記もインストールします。

``` JS
yarn add -D eslint
```

## 設定ファイルの作成

1. `yarn eslint --init` を実行し、設定ファイルの初期設定と作成を行います。

参考: [https://eslint.org/docs/user-guide/getting-started](https://eslint.org/docs/user-guide/getting-started)

対話形式でインストール準備が行われます。

``` Shell
✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · vue
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ How would you like to define a style for your project? · prompt
✔ What format do you want your config file to be in? · JavaScript
✔ What style of indentation do you use? · 4
✔ What quotes do you use for strings? · single
✔ What line endings do you use? · unix
✔ Do you require semicolons? · No / Yes
```

作成された `.eslintrc.js` ファイルの内容が以下となります。

``` JS
module.exports = {
    'env': {
        'browser': true,
        'es2020': true
    },
    'extends': [
        'eslint:recommended',
        'plugin:vue/essential',
        'plugin:@typescript-eslint/recommended'
    ],
    'parserOptions': {
        'ecmaVersion': 11,
        'parser': '@typescript-eslint/parser',
        'sourceType': 'module'
    },
    'plugins': [
        'vue',
        '@typescript-eslint'
    ],
    'rules': {
        'indent': [
            'error',
            4
        ],
        'linebreak-style': [
            'error',
            'unix'
        ],
        'quotes': [
            'error',
            'single'
        ],
        'semi': [
            'error',
            'always'
        ]
    }
};
```


2\. `package.json` に script を追加します。

参考:
- [Nuxt.js > ESLint と Prettier] (https://ja.nuxtjs.org/guide/development-tools/#eslint-%E3%81%A8-prettier)
- [Nuxt TypeScript > Lint](https://typescript.nuxtjs.org/guide/lint.html#lint)

``` JS
  "scripts": {
    // 略
    "lint": "eslint --ext .ts,.js,.vue --ignore-path .gitignore .",
    "lintfix": "eslint --fix --ext .ts,.js,.vue --ignore-path .gitignore .",
    // 略
```

  - `--fix` オプション  
  エラーの修正をする。実際のファイルに対して行われ、未修正の問題のみが出力される。
  プロセッサが自動修正を許可することを選択しない限りはプロセッサを使用するコードには影響しない。

参考: [https://eslint.org/docs/user-guide/command-line-interface#fixing-problems](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems)

  - `--ignore-path` オプション  
  `.eslintignore` として使用するファイルを指定できる。デフォルトではカレントディレクトリで `.eslintignore` を探す。
  別のファイルのパスを指定することで、この動作をオーバーライドできる。

参考: [https://eslint.org/docs/user-guide/command-line-interface#ignoring-files](https://eslint.org/docs/user-guide/command-line-interface#ignoring-files)

## `yarn eslint --fix` の実行と確認

この時点で一度 `yarn lintfix` を実行するとエラーが出ました。

error 内容: 

``` Shell
error  Use the latest vue-eslint-parser. See also https://eslint.vuejs.org/user-guide/#what-is-the-use-the-latest-vue-eslint-parser-error  vue/no-duplicate-attributes
error  Use the latest vue-eslint-parser. See also https://eslint.vuejs.org/user-guide/#what-is-the-use-the-latest-vue-eslint-parser-error  vue/no-template-key

// 略

✖ 174 problems (169 errors, 5 warnings)
```

`babel-eslint` や `@typescript-eslint/parser` を使う場合には `vue-eslint-parser` が必要で、`parser` に書いても overwrite されないとのことなので、以下を `.eslintrc.js` に追加します。

参考: [https://eslint.vuejs.org/user-guide/#usage](https://eslint.vuejs.org/user-guide/#usage)

``` JS
    "parser": "vue-eslint-parser", // add
    'parserOptions': {
        'ecmaVersion': 11,
        'parser': '@typescript-eslint/parser',
        'sourceType': 'module'
    },
```

再度 `yarn lintfix` を実行します。

``` Shell
// 結果
✖ 20 problems (10 errors, 10 warnings)
```


## コマンドオプションの確認とエラーの解消

- 設定系のファイルを除外

`package.json` を以下のように修正します。
`--ignore-pattern` を使用して、 `.` で始まるファイルと `config` を含むファイルを除外するということをしてみます。

``` JS
  "lintfix": "eslint --fix --ext .ts,.js,.vue --ignore-path .gitignore --ignore-pattern '.*' --ignore-pattern '*.config.*' .",
```

参考: [https://eslint.org/docs/user-guide/command-line-interface#ignore-pattern](https://eslint.org/docs/user-guide/command-line-interface#ignore-pattern)

結果: 

```
✖ 17 problems (6 errors, 11 warnings)
```

※これは `config` 内にいくつかエラーがあったため、それを除外したことによりエラーの数が減った、と言う結果になります。

- global 変数を許可する

設定系のファイルでもフォーマットは管理したいため、先に追加した script は削除して、エラーの解消を進めます。

global 変数許可前

``` Shell
✖ 20 problems (10 errors, 10 warnings)
```

エラー内容: 

```Shell
error  'module' is not defined  no-undef
error  'process' is not defined  no-undef
// 略
```

`module` や `process` が定義されていないのに使われている、というエラーが出ています。
これは global な変数でエラーではないため、それを `.eslintrc.js` に追加します。

``` JS
   'globals': {
        'module': false
        'process': false
    }
```

global 変数許可後

```
✖ 16 problems (6 errors, 10 warnings)
```

## prettier の設定

1. `devDependencies` に `prettier`, `eslint-config-prettier`, `eslint-plugin-prettier` があるか確認し、なければ install します。

`eslint-config-prettier` と `eslint-plugin-prettier` の主な機能は以下となります。

 - `eslint-config-prettier`  
  `prettier` と競合する可能性のあるルールをOffにする
 - `eslint-plugin-prettier`  
  `prettier` を `eslint` として実行する

参考: 
- [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier#installation)
- [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier)

2\. 確認後、以下を`.eslintrc.js` に追加します。

``` JS
  extends: [
    'eslint:recommended',
    'plugin:vue/essential',
    'plugin:@typescript-eslint/recommended',
    // add
    'plugin:prettier/recommended',
    'prettier',
  ],
   plugins: [
    'vue',
    '@typescript-eslint',
    // add
    'prettier',
  ],
  // 略
  rules: {
     // add
    'prettier/prettier': ['error'],
    // 略
  },
```

- overwrite する関係で、 `extends` に `prettier` 関連を追記する場合には、 `eslint` の各記述の後(一番最後) に記載しないとならない、とのことなので、最後に追記します。
参考: [https://github.com/prettier/eslint-plugin-prettier#recommended-configuration](https://github.com/prettier/eslint-plugin-prettier#recommended-configuration)

- plugins, rules にもそれぞれ追記します。
参考: [https://github.com/prettier/eslint-plugin-prettier#installation](https://github.com/prettier/eslint-plugin-prettier#installation)

3. `yarn lintfix` コマンドを実行すると、エラーが大量に吐かれます。

```
✖ 290 problems (280 errors, 10 warnings)
  274 errors and 0 warnings potentially fixable with the `--fix` option.
```

内容を見ると末尾のセミコロンやインデントが引っかかっているようなので、 `.eslintrc.js` の `rules` に追記します。
ちなみにこれは、 `.prettierrc` に記述があった部分を移動しているだけになります。この転記が終わったら `.prettierrc` は必要なければ削除しても問題なく動作します。

エラー内容 : 

```Shell
 error  Delete `;`                                        prettier/prettier
 error  Replace `················` with `········`        prettier/prettier
```

追記: [.eslintrc.js]

``` JS
rules: {
    'prettier/prettier': ['error', { singleQuote: true, semi: true }], // add
    indent: ['error', 2], // change
    'linebreak-style': ['error', 'unix'],
    quotes: ['error', 'single'],
    semi: ['error', 'always'],
  },
```

結果:

```
✖ 16 problems (6 errors, 10 warnings)
```

残りは `'**' is defined but never used ` や ` Do not use "// @ts-ignore" because it alters compilation errors` が多いので一つ一つ確認して対応していきます。

## Epilogue

最初自力で `.eslintrc.js` を作りパラメータを設置し、と作っていましたがトライする前にエラーの連続で混乱したため、もっと楽に...という経緯ではじめました。
時間がある時に構文周りとかも抑えつつ、次は `commit` 時に `lintfix` が実行される実装を試してみたいと思います。

何か不備や不明点等ありましたらご連絡ください！