Angular 11のプロジェクトをCodelyzerとTSLintからESLintへマイグレーションしてみた

2020.11.27

こんにちは!DA(データアナリティクス)事業本部 インテグレーション部の大高です。

先日、Angular 11がリリースされました。以前からロードマップに上がっていましたが、Angularブログのリリース紹介記事でもLintingについて記載されています。

In previous versions of Angular, we’ve shipped a default implementation for linting (TSLint). Now, TSLint is deprecated by the project creators who recommend migration to ESLint.
(中略)
We’re deprecating the use of TSLint and Codelyzer in version 11. This means that in future versions the default implementation for linting Angular projects will not be available.

上記のとおり、TSLintとCodelyzerは非推奨になり、将来的にはAngularプロジェクトでのLintingに関するデフォルト実装は無くなる旨が改めて記載されています。

ESLintへのマイグレーションの方法については、下記リポジトリのREADMEにて解説されているので、実際に試してみたいと思います。

プロジェクトの作成

サンプルプロジェクトとして、まずはそのままプロジェクトを作成します。

$ ng new eslint-sample
? Do you want to enforce stricter type checking and stricter bundle budgets in the 
workspace?
  This setting helps improve maintainability and catch bugs ahead of time.
  For more information, see https://angular.io/strict Yes
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? SCSS   [ https://sass-lang.com/doc
umentation/syntax#scss                ]
CREATE eslint-sample/README.md (1021 bytes)
CREATE eslint-sample/.editorconfig (274 bytes)
CREATE eslint-sample/.gitignore (631 bytes)
CREATE eslint-sample/angular.json (3761 bytes)
CREATE eslint-sample/package.json (1203 bytes)
CREATE eslint-sample/tsconfig.json (737 bytes)
CREATE eslint-sample/tslint.json (3185 bytes)
CREATE eslint-sample/.browserslistrc (703 bytes)
CREATE eslint-sample/karma.conf.js (1108 bytes)
CREATE eslint-sample/tsconfig.app.json (287 bytes)
CREATE eslint-sample/tsconfig.spec.json (333 bytes)
CREATE eslint-sample/src/favicon.ico (948 bytes)
CREATE eslint-sample/src/index.html (298 bytes)
CREATE eslint-sample/src/main.ts (372 bytes)
CREATE eslint-sample/src/polyfills.ts (2826 bytes)
CREATE eslint-sample/src/styles.scss (80 bytes)
CREATE eslint-sample/src/test.ts (753 bytes)
CREATE eslint-sample/src/assets/.gitkeep (0 bytes)
CREATE eslint-sample/src/environments/environment.prod.ts (51 bytes)
CREATE eslint-sample/src/environments/environment.ts (662 bytes)
CREATE eslint-sample/src/app/app-routing.module.ts (245 bytes)
CREATE eslint-sample/src/app/app.module.ts (393 bytes)
CREATE eslint-sample/src/app/app.component.scss (0 bytes)
CREATE eslint-sample/src/app/app.component.html (25757 bytes)
CREATE eslint-sample/src/app/app.component.spec.ts (1078 bytes)
CREATE eslint-sample/src/app/app.component.ts (218 bytes)
CREATE eslint-sample/e2e/protractor.conf.js (904 bytes)
CREATE eslint-sample/e2e/tsconfig.json (274 bytes)
CREATE eslint-sample/e2e/src/app.e2e-spec.ts (664 bytes)
CREATE eslint-sample/e2e/src/app.po.ts (274 bytes)
✔ Packages installed successfully.

問題ありませんね。

マイグレーションしてみる

作成できたら、あとはREADMEのガイドに従ってマイグレーションを進めてみます。

angular-eslint/README.md at master · angular-eslint/angular-eslint

Step 1 - Add relevant dependencies

まずは@angular-eslint/schematicsの追加です。

$ cd eslint-sample/
$ ng add @angular-eslint/schematics
? Would you like to share anonymous usage data about this project with the Angular Team at
Google under Google’s Privacy Policy at https://policies.google.com/privacy? For more
details and how to change this setting, see http://angular.io/analytics. Yes

Thank you for sharing anonymous usage data. Would you change your mind, the following
command will disable this feature entirely:

    ng analytics project off

Installing packages for tooling via npm.
Installed packages for tooling via npm.
UPDATE package.json (1703 bytes)
✔ Packages installed successfully.

これも特に問題ありませんね。

Step 2 - Run the convert-tslint-to-eslint schematic on a project

このステップでは、angular.jsonにいくつprojectの定義があるかで変わり、複数のprojectを定義している場合には、移行対象を選択すべしとのことです。

今回はprojectは1つだけなので、単純にプロジェクトのeslint-sampleを指定して実行します。

$ ng g @angular-eslint/schematics:convert-tslint-to-eslint eslint-sample
CREATE .eslintrc.json (1084 bytes)
UPDATE angular.json (3712 bytes)

新しく.eslintrc.jsonが追加され、angular.jsonも更新されました。

それぞれ見てみましょう。

.eslintrc.json

{
  "root": true,
  "ignorePatterns": [
    "projects/**/*"
  ],
  "overrides": [
    {
      "files": [
        "*.ts"
      ],
      "parserOptions": {
        "project": [
          "tsconfig.json",
          "e2e/tsconfig.json"
        ],
        "createDefaultProgram": true
      },
      "extends": [
        "plugin:@angular-eslint/ng-cli-compat",
        "plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
        "plugin:@angular-eslint/template/process-inline-templates"
      ],
      "rules": {
        "@angular-eslint/component-selector": [
          "error",
          {
            "type": "element",
            "prefix": "app",
            "style": "kebab-case"
          }
        ],
        "@angular-eslint/directive-selector": [
          "error",
          {
            "type": "attribute",
            "prefix": "app",
            "style": "camelCase"
          }
        ]
      }
    },
    {
      "files": [
        "*.html"
      ],
      "extends": [
        "plugin:@angular-eslint/template/recommended"
      ],
      "rules": {}
    }
  ]
}

.eslintrc.jsonでは、*.tsおよび*.htmlに対して、それぞれangular-eslintのプラグインが適用されるようになっているのが見て取れますね。

angular.json(変更前-抜粋)

        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "tsconfig.app.json",
              "tsconfig.spec.json",
              "e2e/tsconfig.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        },

angular.json(変更後-抜粋)

        "lint": {
          "builder": "@angular-eslint/builder:lint",
          "options": {
            "lintFilePatterns": [
              "src/**/*.ts",
              "src/**/*.html"
            ]
          }
        },

lint設定が書き換わって、angular-eslintを利用するように変わっていますね。

では、早速lintを走らせてみます。

$ ng lint

Linting "eslint-sample"...
All files pass linting.

ng newしただけのプロジェクトなので、問題なくpassしました!

試しにちょっとapp.component.tsのリテラルをダブルクォーテーションで括るように変更してみましょう。

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = "eslint-sample";  //'eslint-sample';
}
$ ng lint

Linting "eslint-sample"...

/home/ec2-user/src/eslint-sample/src/app/app.component.ts
  9:11  error  Strings must use singlequote  @typescript-eslint/quotes

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

Lint errors found in the listed files.

ビシッと指摘してくれました!ついでに--fixオプションをつけて修正してもらいます。

$ ng lint --fix

Linting "eslint-sample"...
All files pass linting.

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'eslint-sample';  //'eslint-sample';
}

バッチリ直してくれました!

Step 3 - Remove root TSLint configuration and use only ESLint

最後は不要になったTSlintの削除です。

Once you are happy with your ESLint setup, you simply need to remove the root-level tslint.json and potentially uninstall TSLint and any TSLint-related plugins/dependencies if your Angular CLI workspace is now no longer using TSLint at all.

とあるので、削除してしまいます。

$ rm tslint.json 
$ npm uninstall tslint
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules/watchpack-chokidar2/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules/webpack-dev-server/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

audited 1600 packages in 7.467s

94 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

これで不要になったTSLintについても削除できました。

まとめ

以上、Angular 11のプロジェクトをCodelyzerとTSLintからESLintへマイグレーションしてみました。

今回は特に既存の設定もないシンプルなプロジェクトだったので、サクッと対応できました。対応できるものは、徐々にESLintへのマイグレーションを進めてしまっても良いかもしれませんね。

どなたかのお役に立てば幸いです。それでは!

参考