AngularでESLintを適用させる（v12＆v11向け）

Angular v12ではデフォルトのコードチェックツールが無いため、ソースコードがAngularの一般的なコーディング規約に則っているかをチェックするにはESLintを適用する必要があります。

そこで今回は[Angular ESLint公式ガイド](https://github.com/angular-eslint/angular-eslint)に沿ってAngularにESLintを適用する方法をご紹介します。

また、Angular v11まではTSLintがデフォルトでインストールされているため、TSLintからESLintの移行についても合わせて記載しております。

## そもそもESLintとTSLintって何？
### [ESLint](https://eslint.org/)
* JavaScriptのコードチェックツールです。
* コーディングルールを定義することで、ソースコードがルールに則っているか確認できます。
* 例えば「コーディング規約に違反している場合はエラーとする」といった設定を定義させることができます。
  * そうすることで、チームで開発する時にコードの記述を統一させることができ、保守性・可読性の低下や思わぬエラーなどを未然に防ぐことができます。
* ESLintには様々なプラグインがあり、TypeScriptやAngular用のプラグインも提供されています。

### [TSLint](https://palantir.github.io/tslint/)
* こちらもTypeScriptのコードチェックツールですが、既に2019年に非推奨となっています。
* Angular v11まではデフォルトでインストールされているため、TSLintからESLintへの移行が必要です。

## ESLintの適用手順
### 前提
Node.jsおよびAngularは以下のバージョンを利用します。

* Node.js: v14.15.4
* Angular: v12.1.1
    * v11までの手順も掲載しています。

### ESLintのインストール
1. Angularプロジェクト直下に移動
1. ESLintのインストール
    * 以下のコマンドを実行させ、ESLintをインストールします。
  
        ```
        ng add @angular-eslint/schematics
        ```
    * 続行するか聞かれるので「Y」を入力します。
    
        ```
        ℹ Using package manager: npm
        ✔ Found compatible package version: @angular-eslint/schematics@12.2.0.
        ✔ Package information loaded.

        The package @angular-eslint/schematics@12.2.0 will be installed and executed.
        Would you like to proceed? (Y/n)Y
        ```
    * 以下のメッセージが表示されるとインストールが完了します。
   
        ```
        ✔ Package successfully installed.
        
            All @angular-eslint dependencies have been successfully installed 🎉
        
            Please see https://github.com/angular-eslint/angular-eslint for how to add ESLint configuration to your project.
        
        
            We detected that you have a single project in your workspace and no existing linter wired up, so we are configuring ESLint for you         automatically.
        
            Please see https://github.com/angular-eslint/angular-eslint for more information.
        
        CREATE .eslintrc.json (984 bytes)
        UPDATE package.json (1453 bytes)
        UPDATE angular.json (3549 bytes)
        ✔ Packages installed successfully.
        ```
    * package.jsonを見ると、下記のライブラリがインストールされていることが確認できます。
      * これらはESLintおよびAngular用のESLintプラグインとなります。詳細は[こちらのドキュメント](https://github.com/angular-eslint/angular-eslint#packages-included-in-this-project)をご覧ください。
         * @angular-eslint/builder
         * @angular-eslint/eslint-plugin
         * @angular-eslint/eslint-plugin-template
         * @angular-eslint/schematics
         * @angular-eslint/template-parser
         * @typescript-eslint/eslint-plugin
         * @typescript-eslint/parser
         * eslint
    * またESLintの設定ファイルである`.eslintrc.json`というファイルも追加されていることが確認できます。
        * Angular v11までの場合、この段階では`.eslintrc.json`の追加はされません。後述の「TSLintのアンインストール」で追加されます。

1. TSLintのアンインストール（Angular v11まで）
    * Angular v11までのバージョンではデフォルトでTSLintが含まれているので、以下の手順でアンインストールします。
      * 以下のコマンドを実行させ、TSLintのアンインストールとESLintの設定を適用します。
      
        ```
        ng g @angular-eslint/schematics:convert-tslint-to-eslint --remove-tslint-if-no-more-tslint-targets --ignore-existing-tslint-config
        ```
      * 以下のメッセージが表示されれば完了です。
      
        ```
        > ng g @angular-eslint/schematics:convert-tslint-to-eslint --remove-tslint-if-no-more-tslint-targets --ignore-existing-tslint-config
        
        INFO: We are now installing the "tslint-to-eslint-config" package into a tmp directory to aid with the conversion

        This may take a minute or two...

        DELETE tslint.json
        CREATE .eslintrc.json (1015 bytes)
        UPDATE angular.json (4132 bytes)
        UPDATE package.json (1683 bytes)
        ✔ Packages installed successfully.
        ```
      * 実行が完了すると、以下の変更が適用されます。
         * `.eslintrc.json`の追加
         * TSLintおよび[Codelyzer](https://www.npmjs.com/package/codelyzer)のアンインストール
         * TSLintの設定ファイル`tslint.json`の削除
         * Angular設定ファイル`angular.json`のLinter設定がtslintからeslint向けに移行

1. ESLintの実行
    1. 下記コマンドからESLintを実行し、コードチェックを行います。
    
        ```
        > ng lint
        ```
    1. ESLintの結果は下記の通りです。
    
        ```
        Linting "angular-example"...

        C:\Users\username\Documents\angular-example\src\app\header.component.ts
        12:3  error  Lifecycle methods should not be empty  @angular-eslint/no-empty-lifecycle-method

        ✖ 1 problems (1 errors, 0 warnings)

        Lint errors found in the listed files.
        ```
        * `@angular-eslint/no-empty-lifecycle-method`というESLintのルールに違反している旨が記載されています。

#### Prettierのインストール
* [Prettier](https://prettier.io/)とはフォーマッターライブラリの1つで、TypeScriptやHTMLなど、様々な言語に対応しています。
* ESLintではPrettierのプラグインを組み込むことができ、プラグインを追加することで上述のTypeScriptやAngularのルールに加えてコードフォーマット周りもチェックできます。

  参考：https://github.com/angular-eslint/angular-eslint#notes-for-eslint-plugin-prettier-users

1. PrettierおよびESLint Prettierのインストール
    * 下記3つをインストールします
      * prettier: Prettier本体
      * [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier): ESLintでPrettierのルールを適用するプラグイン
      * [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier): Prettierとその他プラグインで競合するESLintのルールをオフにするライブラリ

    ```
    > npm install --save-dev prettier eslint-plugin-prettier eslint-config-prettier
    ```
1. Prettier設定ファイル`.prettierrc`の追加
    * プロジェクト直下に`.prettierrc`ファイルを追加し、設定を記述します。
      * 1行に表示させる文字数や、文字列等をシングルクォートにするか等の設定が可能です。
      * 詳細: https://prettier.io/docs/en/configuration.html
      
    ```json
    {
      "printWidth": 80,
      "singleQuote": true,
      "useTabs": false,
      "tabWidth": 2,
      "semi": true,
      "bracketSpacing": true,
      "endOfLine": "auto"
    }
    ```
1. `.eslintrc`のPrettierプラグインの追加

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

1. ESLintの実行
    * `ng lint`の実行例は下記の通りです。
    * インデントやカッコがprettierのルールに則りチェックされていることが確認できます。
    
    ```
    C:\Users\username\Documents\angular-example\src\main.ts
    11:25  error  Insert `⏎··`                prettier/prettier
    12:10  error  Replace `err` with `(err)`  prettier/prettier
    ```

#### VSCode拡張機能
Visual Studio Codeでは[ESLint拡張機能](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)があり、VSCodeのエディタ上でESLintによるコードチェックや自動フォーマットを行うことができます。

上述の`ng lint`の実行無しでもリアルタイムにコードチェックが行われるのが嬉しい点です。

1. ESLint拡張機能をインストール
1. 設定ファイルの編集
    * settings.jsonを開き、下記の設定を追加します。
        * `eslint.options`と`eslint.validate`はTS、HTMLファイルに対しESLintのコードチェックを行うことができる設定です。
        * `editor.codeActionsOnSave`はドキュメントの保存時に自動的にコードフォーマットを実行する設定です。Prettierを適用している場合に有効です。

    ```json
    {
      "eslint.options": {
        "extensions": [".ts", ".html"]
      },
      "eslint.validate": [
        "javascript",
        "javascriptreact",
        "typescript",
        "typescriptreact",
        "html"
      ],
      "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
      }
    }
    ```
1. コード自動チェックの確認
    
    以下のキャプチャのようにHTMLやTSファイルに対して、自動的にコードチェックを行っていることが確認できます。

    ![eslint1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/93b8181b-d838-2360-ab25-f089c9814be1.png)

    ![eslint2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/0e338daf-e7c2-ed78-2cd7-91a8eb4fdc6a.png)


1. 自動フォーマットの確認
    
    以下のとおりインデント周りのエラーが起こっているファイルがありますが、このファイルを保存してみます。
    ![eslint3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/00b7dcab-71c7-e165-b27b-e5a4ec725a9f.png)

    すると、このように自動的にコードフォーマットが実行され、フォーマット周りのエラーが解決できます。
    ![eslint4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398865/ee6a5eb3-7ed3-161b-de10-00b44cef9c70.png)



#### 補足
* ESLintによるエラーを無視させたい場合
    * ESLintによるエラーを無視させたい場合、エラーが出ている箇所の1行前に`// eslint-disable-next-line [ESLintルール名]`のコメントを追記することで対応ができます。
    * 例えばこのような書き方になります。
    
    ```ts
    export class HeaderComponent implements OnInit {

      constructor() { }

      // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method
      ngOnInit(): void {
      }

    }
    ```
* 特定のファイルをコードチェックの対象外にしたい場合
    * Angularプロジェクト直下に`.eslintignore`ファイルを追加し、以下の通りコードチェックの対象外とするファイルを記載します。
    ```
    src/app/**/*.spec.ts
    ```

#### おわりに
以上で、Angular12のESLintの適用手順は完了です。

私も実際に複数人が開発するAngularプロジェクトでESLintを組み込んでいますが、

開発やコードレビューのスピードがかなり上がったと感じています。

ぜひ、皆さんもESLintで快適なAngularアプリ開発をお試しください！