Angular12にESLintとPrettierを適応

2021年2月に正式にAngular12で使用できるLinterであるESLint( [angular-eslint][2] )の対応コードが本家にマージされたため、今回はそれらを使用してAngular12アプリケーションにESLintを適応し、コードフォーマットに[Prettier][3]を使用するまでのスケルトンプロジェクトを作成します。

AngularCLIはv12以降の環境を使用しています。

# Angular12アプリケーションの新規作成
まずは、Angular12の新規アプリケーションを`ng n my-app`コマンドを実行して作成します。

```
$ ng new my-app
$ cd my-app
```

# angular-eslintを適応
Angular12からは新規プロジェクト作成ではデフォルトのLinterが含まれなくなっており、この時点で`ng lint`コマンドを実行しても下記のようにエラーが出力されます。

```
$ ng lint
Cannot find "lint" target for the specified project.

You should add a package that implements linting capabilities.

For example:
  ng add @angular-eslint/schematics
```

冒頭で記載したとおり、2021年2月以降のバージョンではangular-eslitの対応済みなのでエラー内容通りにコマンドを実行するだけでプロジェクトにESLintを組み込むことができます。

```
$ ng add @angular-eslint/schematics
```

コマンドを実行すると下記のファイルが作成、または更新されます。

- .eslintrc.json
- angular.json
- package.json

これだけでESLintが利用できる状態となっています。

```
$ ng lint
All files pass linting.
```

# VSCodeのESLint拡張機能の利用
エディタにVSCodeを使用している方も多いと思います。

VSCodeにESLint拡張機能を導入することで、コンソールから`ng lint`コマンドを実行しなくともエディタ上にLinterが検出したエラーを表示することができます。

VSCodeの拡張機能を表示し`dbaeumer.vscode-eslint`で検索するとESLint拡張機能が表れますのでインストールを実行します。

## ワーキングディレクトリの調整
ESLint拡張機能のデフォルト設定ではホームディレクトリ配下にプロジェクトが存在する設定となっており、それ以外のディレクトリで作業をしている方は「tsconfig.jsonが見つかりません」といったエラーが表示されるようになります。

ESLint拡張機能の`workingDirectories`を変更し、自動でtsconfig.jsonを探し出すよう設定を変更します。

今回はVSCodeのワークスペースでのみ設定を有効にしたいので、ワークスペースディレクトリ内の`.vscode/settings.json`ファイルを下記のように編集します(フォルダやファイルが無い場合は作成します)

```json
{
  "eslint.workingDirectories": [
    {
      "mode": "auto"
    }
  ]
}
```

# Priettierの適応
次にPriettierを適応します。

ESLintとPrettierは[併用しない方が良い][1]という情報もありますが、これはESLint自体がコーディングスタイルを修正してしまうためPrettier自体をESLintに組み込んで実行することを示しており、本来は役割を分けLinterはコード品質を担保しFormatterはコーディングスタイルを担保するという方針で、現在はそれぞれ別々に実行する方が望ましいとなっています。

angular-eslintでは実行順序を制御するなどの方法で併用しても問題ないよう対処しているようです。

## Prettierのインストール
プロジェクトにPrettierとESLintと併用するために、競合等を解消するための調整用パッケージを導入します。

```
$ npm i -D @typescript-eslint/eslint-plugin eslint-plugin-prettier prettier prettier-eslint eslint-config-prettier
```

- @typescript-eslint/eslint-plugin = ESLintへTypeScriptのルールを適応するためのプラグイン
- eslint-plugin-prettier = ESLintへPrettierのルールを適応し実行するプラグイン
- prettier = Prettier本体
- prettier-eslint = Prettier実行後のコードがESLintに渡されるようにする用にフローを調整する
- eslint-config-prettier = Prettierと競合するESLintのルールを無効化

## angular-eslintへの適応
本記事ではAngularプロジェクトでのlintの実行にはangular-eslintで行うことを想定しているため、angular-eslintが正しくPrettierを呼び出すよう設定を変更します。

`.eslintrc.json`の下記の部分を修正します。

```json
{
  "overrides":[
    {
      ...
      "extends": [
        "plugin:@angular-eslint/recommended",
        "plugin:@angular-eslint/template/process-inline-templates",
        "plugin:prettier/recommended" // これを追加
      ]
    },
    ...
    // 下記を追加
    {
      "files": [
        "*.html"
      ],
      "excludedFiles": [
        "*inline-template-*.component.html"
      ],
      "extends": [ "plugin:prettier/recommended" ],
      "rules": {
        "prettier/prettier": [
          "error",
          {
            "parser": "angular"
          }
        ]
      }
    }
  ]
}
```

AngularではHtmlファイルは拡張されたフォーマット(HTMLテンプレート)が採用されており、それらのファイルでも正しくPrettierが機能するために設定をオーバーライドします。

## Prettierのルール
適応したいPrettierのルールを`.prettierrc.json`に記述します。

```json
{
  "printWidth": 80,
  "useTabs": false,
  "singleQuote": true,
}
```

# VSCodeの既存フォーマッタへの対応
TypeScriptのファイルやJavaScriptファイルにはVSCodeで既存のフォーマッタが登録されています。このフォーマッタを使用するとせっかく設定したESLint+Prettierによるフォーマットを無視してしまうので、既存のフォーマッタを無効とします。

前述にもあるように、今回ははVSCodeのワークスペースでのみ設定を有効にしたいので、ワークスペースディレクトリ内の`.vscode/settings.json`ファイルを下記のように編集します。

```json
{
  ...
  "[typescript]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint",
    "editor.codeActionsOnSave": {
      "source.fixAll.eslint": true
    },
    "editor.formatOnSave": false
  },
  "[javascript]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint",
    "editor.codeActionsOnSave": {
      "source.fixAll.eslint": true
    },
    "editor.formatOnSave": false
  }
}
```

`defaultFormatter`を変更し既存のフォーマッタが実行されないようにしています。ただし、残念なことに`dbaeumer.vscode-eslint`はVSCodeのコードフォーマットコマンドに対応していないため、コードフォーマットコマンドを実行してもフォーマットが実行されない点に注意してください。

上記のように設定をファイル保存時にlintコードアクションを実行するよう変更し、lintの実行によりESLintによるコード品質のチェックとPrettierによるコードフォーマットが実行されます。(保存時にフォーマッタが動作しないよう`formatOnSave`も無効化します)


[1]:https://prettier.io/docs/en/integrating-with-linters.html
[2]:https://github.com/angular-eslint/angular-eslint
[3]:https://github.com/prettier/prettier