Vue3におけるeslint(+prettier)の設定

Vue3でのフロントエンド開発において、開発環境構築時に調査した内容を作業メモベースで記事にしていきます。

## 動作環境
本記事では以下のバージョンを前提としている。
eslint 8.25.0
prettier 2.7.1
typescript 4.7.4
vue 3.2.41
eslint-plugin-vue 9.6.0

また、viteを利用しており、create-vueコマンドで作成したvueプロジェクトで作業している。
プロジェクト作成時の設定は以下の通り。
```
√ Add TypeScript? ... Yes  
√ Add JSX Support? ... No  
√ Add Vue Router for Single Page Application development? ... Yes  
√ Add Pinia for state management? ... Yes  
√ Add Vitest for Unit Testing? ... Yes  
√ Add Cypress for End-to-End testing? ... No  
√ Add ESLint for code quality? ... Yes  
√ Add Prettier for code formatting? ... Yes
```

## 完成形

今回修正するファイルは.eslintrc.cjs。
``` .eslintrc.cjs
require("@rushstack/eslint-patch/modern-module-resolution");

module.exports = {
  root: true,

  env: {
    node: true,
  },

  extends: [
    "plugin:vue/vue3-essential",
    "@vue/eslint-config-airbnb-with-typescript",
    "@vue/eslint-config-prettier",
  ],

  parserOptions: {
    ecmaVersion: "latest",
  },

  rules: {
    "vue/component-tags-order": [
      "error",
      {
        order: ["script", "template", "style"],
      },
    ],
    "@typescript-eslint/no-explicit-any": "error",
    "@typescript-eslint/typedef": [
      "error",
      {
        variableDeclaration: true,
        memberVariableDeclaration: true,
        propertyDeclaration: true,
        variableDeclarationIgnoreFunction: true,
        arrayDestructuring: true,
        objectDestructuring: true,
        parameter: true,
        arrowParameter: true,
      },
    ],
  },
};


```


## eslintの設定

詳細な設定方法は先人たちがたくさんの記事を残してくれているのでさらっと見ていく。




### 基本

#### extends
.eslijntrc.cjsファイルのextendsに既存のルールのテンプレートを追加することができる。  

https://eslint.org/docs/latest/user-guide/configuring/configuration-files#extending-configuration-files

extendsで指定できるeslint-config-xxxxは個々のルールの設定の組み合わせだが、plugin:xxxx/xxxxを指定することでもルールのテンプレートを読み込むことができる。extends内で重複するルールの記述は下から優先される。  

今回は@vue/eslint-config-airbnb-with-typescriptを追加する。  
これは@vue/eslint-config-airbnbを拡張してtypescript向けに個別のルール設定を加えたもの。

https://github.com/vuejs/eslint-config-airbnb/tree/main/packages/eslint-config-airbnb-with-typescript

plugin:vue/vue3-essentialはviteを利用したvue3プロジェクト作成コマンド、create-vueコマンドで標準でインストールされるもの。一番最後には後述の@vue/eslint-config-prettierがデフォルトで追加されていたため、今回追加したのは@vue/eslint-config-airbnb-with-typescriptのみ。
```
extends: [
    "plugin:vue/vue3-essential",
    "@vue/eslint-config-airbnb-with-typescript",
    "@vue/eslint-config-prettier",
  ],
```

#### parser
解析する言語を指定できる。今回はextendsしているconfigにvue-eslint-parserの設定があるためparserの設定は特にしない。

https://eslint.org/docs/latest/user-guide/configuring/configuration-files#:~:text=Here%E2%80%99s%20an%20example%20JSON%20configuration%20file%20that%20uses%20the%20typescript%2Deslint%20parser%20to%20support%20TypeScript%20syntax%3A

#### parserOptions
サポートするJavaScript言語オプションを指定できる。   
typescriptを使用する場合tsconfig.jsonの設定が必要だが、今回はextendsしているconfig内で設定されているため、特に変更しない。

https://eslint.org/docs/latest/user-guide/configuring/language-options#specifying-parser-options 

#### rules
個々の設定。extendsで設定したルールの組み合わせをさらに一部変更したい場合に指定する。  

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

https://eslint.org/docs/latest/user-guide/configuring/rules

#### env
実行環境を設定し使えるグローバル変数を設定する。  

https://eslint.org/docs/latest/user-guide/configuring/language-options

### 追加で設定したeslintルールたち

@vue/eslint-config-airbnb-with-typescriptで整形しているが、一部気になったところは個別でルール設定しているので紹介。

#### vue/component-tags-order
scriptタグを一番上に来るようにするルール。vue3ではこれが標準らしいので合わせる。
```
"vue/component-tags-order": [
      "error",
      {
        order: ["script", "template", "style"],
      },
    ],
```


#### @typescript-eslint/typedef
変数やメソッド、パラメータの定義時に型定義が必須になる。ライブラリからimportしたメソッドなど、返り値が複雑な型になるケースは注意が必要。

```
"@typescript-eslint/typedef": [
      "error",
      {
        variableDeclaration: true,
        memberVariableDeclaration: true,
        propertyDeclaration: true,
        variableDeclarationIgnoreFunction: true,
        arrayDestructuring: true,
        objectDestructuring: true,
        parameter: true,
        arrowParameter: true,
      },
    ],
```


#### @typescript-eslint/no-explicit-any

どんな場合にもanyに対してerrorを出してくれる。

```
"@typescript-eslint/no-explicit-any": "error",
```




## eslintとprettierの共存設定について
### 導入の背景

#### eslintとprettierは競合が起きる
フォーマッタとしてeslintに加えprettierを導入することを考えたが、eslintと併用するとうまく動かないということがあるらしい。
eslintはリンタとしてのイメージがあるがフォーマッタとしての性質が強いルールが多くある。これらとprettier側で設定したルールが矛盾したとき、後から実行したほうでエラーが起きるということのようだ。
eslintとprettierのうち、後に実行する方を上書きモードで実行することでエラーを回避する、といった方法が古くはとられていたらしい。

#### 旧来の回避方法
これらの状況に対し、eslint公式が打ち出した回避方法は以下のようなものだった。
* eslint-config-prettierでeslintのフォーマッタ機能をオフにする
* eslint-plugin-prettierでeslintによってPrettierを実行する

これらの設定により、eslintからprettierを実行することでフォーマットのエラーもすべてeslintのエラーとして報告されるようになる。実行順序やフォーマッタの個々の設定に悩まなくてよいというメリットがあった。

また、他の方法としてprettier-eslintというプラグインもあり、これはprettierで整形したあとeslint --fixによる上書きモード実行にするというもので、「後に実行する方を上書きモードで実行することでエラーを回避する」という根幹は変わっていないものの、自動化できるというメリットがあった。

#### eslint-plugin-prettierのデメリット
ところが、eslint-plugin-prettierの利用にはいくつかの[問題点](https://github.com/prettier/prettier/blob/554b15473dd4032a036d7db91a8f579e624c9822/docs/integrating-with-linters.md)があった。

>1. エディタにフォーマットの警告がたくさん出てくる
>2. 直接prettierを実行するより遅い
>3. 不整合が起きる可能性がある

また、最近はエディタから直接prettierを実行できるプラグインが増えたため、eslintから実行することで自動化できる、というメリットが薄くなった。

これらの背景から、現在では**eslint-config-prettierのみを利用することが推奨されている**。

### 設定方法
#### eslint-config-prettierの導入
eslintrc.cjsのextendsの最後にprettierを追加する。

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

create-vueコマンドで作成したプロジェクトの場合、作成時にeslintもprettierも利用する設定にすると、extendsにはデフォルトで@vue/eslint-config-prettierが記述されている。

[公式](https://github.com/vuejs/eslint-config-prettier)より引用すると
>この構成は、@vue/cli & create-vueセットアップで使用するように特別に設計されており、

ということなので、どうやら初めからeslint-config-prettierが導入されているようだ。creata-vueコマンド便利。

#### @rushstack/eslint-patch/modern-module-resolutionとは何か
eslintでは特定のプラグインに依存したプラグインを利用する際にすべての依存関係を手動でインストールする必要があったが、それを自動で補ってくれるプラグインである。
プラグインBに依存するプラグインAを利用したい場合、
>npm install --dev B A

を実行する必要があったが、@rushstack/eslint-patchがあるとAのインストールが不要になる。
以前からeslintのconfigについて[こういった問題があった](https://github.com/eslint/eslint/issues/3458)ようだが、

これらの問題を回避するプラグインである@rushstack/eslint-patchが現在は広く使われている。

https://github.com/microsoft/rushstack/tree/main/eslint/eslint-patch
### eslintとprettierの実行方法
#### スクリプト経由で実行する
package.jsonのscriptで設定する方法。
eslintは"npm run lint"コマンドで実行できる。
prettierは"format": "prettier --write src/*.{ts,vue} && prettier --write src/**/*.{ts,vue}"を追加することで実行できる。
lintコマンドでeslint実行後にprettierコマンドを実行するよう記述を変えてもよい。

create-vueコマンドで自動生成されるlintコマンドはそのままでformatコマンドを追加する。

```package.json
  "scripts": {
    "dev": "vite",
    ...
    (略)
    ...
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
    "format": "prettier --write src/*.{ts,vue} && prettier --write src/**/*.{ts,vue}"
  },
```

要はそれぞれを実行するコマンドをscriptに書けばいいので、割とお任せでよい。

#### ファイル保存時に実行する
ルートディレクトリ直下に.vscodeフォルダを作成し、以下を記載したsettings.jsonを配置する。
上二行はprettierを、下3行はeslintを保存時に実行する設定。
```.vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
```

.vscodeフォルダ直下のsettigs.jsonもgitで管理するようにすると、作業者個人のvscodeの設定に寄らずチーム全員がこれらの設定を適用させられるので便利ですね。

## prettierのルールの変更方法
.prettierrc.jsonファイルで各種設定を変更できる。  

https://prettier.io/docs/en/configuration.html  

#### plugin
特定の言語の整形ルールを追加する場合、以下の方法でpluginを追加できる。  
https://prettier.io/docs/en/plugins.html  
ただし、prettier自体がJavaScript系の言語向けに作られているため、今回は変更しない。

#### ルールの個別設定
個別のルール設定方法は以下参照。  
prettierrc.jsonで特にルール指定をしない場合、デフォルト設定が適用される。  
今回はなるべく標準的なルールにしたかったため、デフォルトから変更していません。

https://prettier.io/docs/en/options.html

ファイルの拡張子によって整形ルールを変更したい場合はprettierrc.jsonでoverride設定を使う。  

https://prettier.io/docs/en/configuration.html#configuration-overrides

特定のファイルを整形の対象にしない場合は、.prettierignoreファイルを作成する。  

https://prettier.io/docs/en/ignore.html