Angular v18 + ESLint v9 + Prettier v3をセットアップ

ひさしぶりにAngularプロジェクトでESLintをセットアップしたら、prettierのルールがすんなり読み込みできなくてハマりました。

ESLintの設定については以前に別の記事 [Angularでディレクトリ単位の依存を禁止するルールをESLintで実現する](https://qiita.com/ringtail003/items/3ca8a68304a18cef8252) に書いたことがあります。今回はできるだけプラグイン依存の少ない最小構成を求めていたので、ESLint + Prettierだけ最初からセットアップすることにしました。

# 環境

- Angular v18
- ESLint v9
- Prettier v3
- Node v22

# 新規のAngularプロジェクトを作成

```shell
npx -p @angular/cli ng new
```

# ESLintをインストール＋セットアップ

Lintを実行すると、スキーマティクスを経由してESLintがセットアップできます。

```shell
npm run ng lint
```

LintのビルダーがESLintに変更され、設定ファイルが作成されます。

```shell
git status

Changes not staged for commit:
    modified:   angular.json
    modified:   package-lock.json
    modified:   package.json

Untracked files:
    eslint.config.js
```

これだけでLintのコマンドが通るようになります。
毎回思うことですが本当に便利です。

```shell
npm run ng lint

> Linting "demo-eslint"...
> All files pass linting.
```

# Prettierをインストール

```shell
npm i -D prettier \
	prettier-eslint \
	eslint-config-prettier \
	eslint-plugin-prettier
```

ESLint v8+でフォーマットに関するルールはDeprecatedになったようですが、とりあえず安全のために `eslint-config-prettier（ルールが被った時にPrettierを優先するプラグイン）` を入れておきます。

[Deprecation of formatting rules \| ESLint](https://eslint.org/blog/2023/10/deprecating-formatting-rules/)

# 設定ファイルを書き換え

ESLintの設定ファイルを以下のように書き換えます。

```js:eslint.config.js
// @ts-check
import eslint from "@eslint/js";
import angular from "angular-eslint";
import eslintConfigPrettier from "eslint-config-prettier";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import tseslint from "typescript-eslint";

export default tseslint.config(
  {
    files: ["**/*.ts"],
    extends: [
      eslint.configs.recommended,
      ...tseslint.configs.recommended,
      ...angular.configs.tsRecommended,
      eslintPluginPrettierRecommended,
      eslintConfigPrettier,
    ],
    rules: {
      "@angular-eslint/directive-selector": [
        "error",
        {
          type: "attribute",
          prefix: "app",
          style: "camelCase",
        },
      ],
      "@angular-eslint/component-selector": [
        "error",
        {
          type: "element",
          prefix: "app",
          style: "kebab-case",
        },
      ],
      "prettier/prettier": [
        "error",
        {
          semi: true,
          indent: 2,
          singleQuote: false,
          trailingComma: "es5",
        },
      ],
    },
  },
  {
    files: ["**/*.html"],
    extends: [
      ...angular.configs.templateRecommended,
      ...angular.configs.templateAccessibility,
    ],
    rules: {},
  },
);
```

`eslint.config.js` でimportを使っているので、`package.json` ではESMを指定しておきます。

```diff:package.json
{
  "name": "demo-eslint",
+  "type": "module",
```

ESLint v9からFlat Configというものがデファクトになったようですね。

以前のバージョンとだいぶ書き方が変わっていたので「あれ？プラグインはテキストで指定するんじゃなかったっけ？」「ん？module.exportsが怒られている？」とハマってしまいました。

[Migration to Flat Config \| ESLint](https://eslint.org/docs/latest/extend/plugin-migration-flat-config)

# エディタ用の設定を追加

VSCodeの例です。

コマンドパレットで `Preferences: Open Workspace settings(JSON)` を呼び出し、以下のように設定します。

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

この設定はワークスペース上、つまりプロジェクト配下で有効です。

VSCodeのエクステンション「Prettier」と「ESLint」が互いに同じファイルをフォーマットしないよう、このプロジェクトではESLintを優先させます。

# Lintを実行

```shell
npm run lint

/src/app/app.config.ts
  1:63  error  Replace `'@angular/core'` with `"@angular/core"` prettier/prettier
  2:31  error  Replace `'@angular/router'` with `"@angular/router"` prettier/prettier
  4:24  error  Replace `'./app.routes'` with `"./app.routes"` prettier/prettier
  
/src/app/app.routes.ts
  1:24  error  Replace `'@angular/router'` with `"@angular/router"` prettier/prettier
...
```

たくさんエラーが出てきますね。
prettierのルールでフォーマットしておきましょう。

```shell
npm run lint -- --fix
```

以上で完了です！