Angular ESLintの導入と推しルール6選(2023)
はじめに
今回は、Angular ESLintの導入と推しルール6選について紹介します。
Angular ESLintとは
Angular ESLintは、ESLintでAngularプロジェクトをlintするための便利なルールがまとまっているライブラリです。
Angular ESLintができた経緯
ESLintは2023年現在、JavaScriptのリンター、静的解析ツールとして広く使われていますが、もともとAngular(not AngularJS)では、TypeScriptが導入されていたこともあり、当時使われていたTypeScriptのリンターであるTSLintが使用されていました。しかし、TSLintが2020年にアーカイブされ非推奨になり、Angularでは、バージョン12でTSLintとAngular用のTSLintルールセットライブラリであったCodelyzerが非推奨になりました。それから、TSLintをESLintのプラグインとして統合していくtypescript-eslintと、それを使ってCodelyzerを再現しつつ、新たなルールセットライブラリとしてのAngular ESLintができました。
そのため、基本的にはCodelyzerが非推奨になったAngularバージョン12以降からのサポートが充実しています。この記事では、最新のバージョン17で検証しています。
Angular ESLintを導入する
導入方法
ng new
などで作成済みのAngularアプリケーションに、次のコマンドで導入することができます。
ng add @angular-eslint/schematics
変更される箇所
angular.json
にlintのコマンド、cliの設定が記述され、package.jsonにnpm run lint
でng lint
が実行できるように設定が記述されます。
また、eslintの設定ファイルがない場合は.eslintrc.json
が生成され、ある場合は次のような設定が追記されます。
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended",
"plugin:@angular-eslint/template/accessibility"
],
"rules": {}
}
]
}
注目する点はextendsに記述される@angular-eslintのpluginです。
@angular-eslint/recommended
これは、tsファイルに記述されているTypeScriptに対して、Angular ESLintが推奨するルールを有効にするプラグインです。
推奨ルールの一覧は、packages/eslint-plugin/src/configs/recommended.json
にあります。
すべての各ルールについての詳細な一覧は、packages/eslint-plugin
のREADMEにまとめられており、スタイルガイドへのリンクが付いているものもあるので読んでみると学びがありました。
ちなみに、@angular-eslint/recommended
を@angular-eslint/all
にするとすべてのルールが有効になります。
@angular-eslint/template/process-inline-templates
これは、tsファイルに記述されているコンポーネントなどのインラインテンプレートのhtmlに対して、@angular-eslint/templateのルールを適応するためのプラグインです。
@angular-eslint/template/recommended
これは、htmlファイルに記述されているテンプレートのhtmlに対して、Angular ESLintが推奨するルールを有効にするプラグインです。
推奨ルールの一覧は、packages/eslint-plugin/src/configs/recommended.json
にあります。
すべての各ルールについての詳細な一覧は、packages/eslint-plugin-template
のREADMEにまとめられています。
ちなみにこちらも、@angular-eslint/template/recommended
を@angular-eslint/template/all
にすると、すべてのルールが有効になります。
@angular-eslint/template/accessibility
こちらは、htmlファイルに記述されているテンプレートのhtmlに対して、Angular ESLintにあるアクセシビリティ系のルールを適応するためのプラグインです。
アクセシビリティ系のルールの一覧は、packages/eslint-plugin-template/src/configs/accessibility.json
にあります。
余談:Prettierの導入について
余談ですが、eslintを一緒に使うことの多いコードフォーマッターPrettierを一緒に導入するためのeslint-plugin-prettier
の設定についてREADMEに書いてあったのが親切だと思いました。(PRした人えらい)
ちなみにeslint-plugin-prettier
の推奨構成を参考にすると、次のように導入するのが良さそうです。
npm install -D eslint-plugin-prettier eslint-config-prettier
...
"files": [
"*.ts"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
+ "plugin:prettier/recommended",
],
...
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended",
"plugin:@angular-eslint/template/accessibility",
+ "plugin:prettier/recommended",
],
自分の環境ではsrc/index.htmlの!doctype宣言でprettierがparse errorになったので、一旦.eslintignore
に追加しました。
src/index.html
個人的な推しルール6選
@angular-eslint/no-output-native
ドキュメントのリンク
これは、ts側の@Outputで使うイベントに標準のDOMイベントと同じ名前をつけないようにするルールです。
@angular-eslint/recommended
で有効になります。
これを有効にすることで標準のDOMイベントと@Outputによるイベントで、2度イベントが発火している箇所に気づけたというメリットがありました。対応している標準のDOMイベントの一覧は、get-native-event-names.tsにあります。
次のようなコードがエラーになります。
@Component(...)
class SampleComponent {
@Output() change: new EventEmitter<string>();
~~~~~~
}
こう直すと、エラーになりません。
@Component(...)
class SampleComponent {
- @Output() change: new EventEmitter<string>();
+ @Output() changeText = new EventEmitter<string>();
}
@angular-eslint/prefer-on-push-component-change-detection
ドキュメントのリンク
これは、ts側のコンポーネントのchangeDetection
がChangeDetectionStrategy.OnPush
に設定されていることを確認するルールです。
@angular-eslint/recommended
では有効になりません。
ChangeDetectionStrategy.OnPush
はコンポーネントに設定することで、必要のない変更検知を減らすことのできるオプションです。Zonelessになるのはもう少しかかりそうなので、これを静的解析で気付き、warnに設定して段階的に直していけるのは良いなと思って選出しました。
次のようなコードがエラーになります。
@Component({
...
~~~~~~~~~~~~~
})
class SampleComponent {
}
こう直すと、エラーになりません。
@Component({
...
+ changeDetection: ChangeDetectionStrategy.OnPush,
})
class SampleComponent {
}
@angular-eslint/use-component-view-encapsulation
ドキュメントのリンク
これは、ts側のコンポーネントのViewEncapsulation.None
の使用を禁止するルールです。
@angular-eslint/recommended
では有効になりません。
ViewEncapsulation.None
はコンポーネントに設定することで、ビューのスタイルのカプセル化をやめ、スタイルをグローバルに適用するオプションです。自分がこのオプションが設定されているのに出会ったことは数回しかないですが、既存の大規模なAngularプロジェクトだと設定されていることがあるのかなと想像しています。そのためこれを静的解析で気付き、warnに設定して段階的に直していけるのは良いなと思って選出しました。
次のようなコードがエラーになります。
@Component({
...
encapsulation: ViewEncapsulation.None,
~~~~
})
class SampleComponent {
}
こう直すと、エラーになりません。
@Component({
- encapsulation: ViewEncapsulation.None,
})
class SampleComponent {
}
@angular-eslint/prefer-standalone-component
ドキュメントのリンク
これは、ts側のコンポーネントのstandalone
プロパティがtrue
に設定されていることを確認するルールです。
@angular-eslint/recommended
では有効になりません。
standalone
プロパティはコンポーネントに設定することで、@NgModuleを介さずともコンポーネントを解釈できるようにする機能です。Standalone Componentsはマイグレーションするコマンドが提供されているのですが、これも諸般の事情などで一気にマイグレーションできない時に、warnに設定して意識して段階的に直していけるのは良いなと思って選出しました。ちなみにこのルールはコンポーネントに限られているため、DirectiveやPipeなどのルールが欲しいと思ったらコントリビュートチャンスかもしれないです。
次のようなコードがエラーになります。
@Component({
...
~~~~~~~~~~~~~
})
class SampleComponent {
}
こう直すと、エラーになりません。
@Component({
...
+ standalone: true,
})
class SampleComponent {
}
@angular-eslint/template/prefer-ngsrc
ドキュメントのリンク
これは、html側のテンプレートで使われているimg要素のsrc
属性の代わりにngSrc
が使用されるようにするルールです。
@angular-eslint/template/recommended
では有効になりません。
ngSrc
はimg要素に設定することで、NgOptimizedImageを機能を使って画像を最適化できます。これもwarnに設定して意識して段階的に直していけるのは良いなと思って選出しました。NgOptimizedImage
に関しては、Angular Advent Calendar 2023の14日目に@hoshima
さんがNgOptimizedImageに入門するという記事も書かれています。
次のようなコードがエラーになります。
<img [src]="value">
~~~~~~~~~~~~~
こう直すと、エラーになりません。
- <img [src]="value">
+ <img [ngSrc]="value">
@angular-eslint/template/prefer-control-flow
ドキュメントのリンク
これは2023年12月現在、開発者プレビューであるBuilt-in control flowをhtml側のテンプレートで使うようにするルールです。
@angular-eslint/template/recommended
では有効になりません。
Built-in control flow
はAngularテンプレートの新しい構文で、@if
や@for
、@defer
ブロックなどが使えるようになります。マイグレーションするコマンドも提供されているようですが、これも諸般の事情などで一気にマイグレーションできない場合にwarnに設定して段階的に直していけるのは良いなと思って選出しました。
Built-in control flow
に関しては、Angular Advent Calendar 2023の13日目に@noxi515
さんがControl FlowとViewレンダリングという記事も書かれています。
次のようなコードがエラーになります。
<div *ngIf="condition; else elseBlock">true</div>
~~~~~~~~~~~~~~~~~
<ng-template #elseBlock>
<div>false</div>
</ng-template>
こう直すと、エラーになりません。
- <div *ngIf="condition; else elseBlock">true</div>
- <ng-template #elseBlock>
- <div>false</div>
- </ng-template>
+ @if (condition) {
+ <div>true</div>
+ } @else {
+ <div>false</div>
+ }
おわりに
Angular ESLintについて、リポジトリを見つつルールをまとめてみました。
以前見た時よりもREADMEの量も更新され充実していて、ルール一覧のドキュメントに貼ってあるスタイルガイドのリンクやルールのドキュメントなど学びになることが多かったです。
また今回は紹介しなかったですが、アクセシビリティ周りのルールが多いのが知らなくて、今度使ってみようと思いました。
個人的にはWebフロントエンド開発者にとってLinterは、LSP(Language Server Protocol)やテストなどのように開発者体験やコーディングの効率化にかなり関わってくるものだと考えています。Angular ESLintを使ってAngularの機能が追加・変更された時に便利になる、できる可能性があるので、今後も見ていきたいです。
ここまで記事をお読みいただきありがとうございました!
Discussion