target=”_blank”を使うときはrel=”noreferrer”を指定しよう

ウェブサイトを運営する際、外部リンクを新しいタブやウィンドウで開くために、リンクにtarget="_blank"を指定することがあります。しかし、この指定だけではセキュリティ上のリスクが生じる可能性があります。そこで、rel属性にnoopenernoreferrerを追加することが推奨されています。この記事では、noopenernoreferrerの違い、サポートブラウザの違い、両方を併用する理由、そしてそれぞれの使い分けについて解説します。

noopenerとは?

<a href="..." target="_blank" rel="noopener">リンク</a>

noopenerは、リンク先のページが元のページ(リンク元)への参照を持たないようにするための値です。具体的には、target="_blank"を指定したリンクをクリックすると、新しいタブやウィンドウでリンク先が開かれますが、その際、リンク先のページからwindow.openerプロパティを介してリンク元のページにアクセスできてしまいます。これにより、リンク先のページがリンク元のページを操作するリスクが生じます。rel="noopener"を指定することで、window.openerプロパティがnullとなり、リンク先からリンク元へのアクセスを防ぐことができます。

noreferrerとは?

<a href="..." target="_blank" rel="noreferrer">リンク</a>

noreferrerは、noopenerの機能に加えて、リンク元のURL情報(リファラー)をリンク先に送信しないようにするための値です。通常、リンクをクリックすると、リンク元のURLがリファラーとしてリンク先に送信されますが、rel="noreferrer"を指定することで、これを防ぐことができます。これにより、プライバシーの保護や、リンク元の情報漏洩を防ぐことが可能となります。

サポートブラウザの違い

noopenernoreferrerのサポート状況はブラウザによって異なります。主要なブラウザの対応状況は以下の通りです。

noopenerをサポートするブラウザ

noopenerは比較的新しい仕様で、対応しているブラウザは後述のnoreferrerと比べると狭くなります。

rel=noopener – HTML: ハイパーテキストマークアップ言語 | MDN

noreferrerをサポートするブラウザ

前述のnoopenerと比べると対応しているブラウザの範囲は広くなります。

rel=noreferrer – HTML: ハイパーテキストマークアップ言語 | MDN

両方を同時に指定することが推奨されていたのは何故か?

<a href="..." target="_blank" rel="noopener noreferrer">リンク</a>

ここまで見ると、noreferrerはカバーしている機能もサポートブラウザもnoopenerよりも広いため同時に指定する理由はないように見えます。

では何故同時に推奨されていた時期があったのでしょうか?

この点について理解するためにnoopenernoreferrerに関する議論をいくつか調べました。

同時に指定することを推奨されていた理由

過去の話であるため、どこまで信憑性があるかは不明ですが、次のような理由でnoopenernoreferrerを両方指定することが推奨されていた時期があったようです。

  • 仕様に準拠していないレガシーブラウザに対応するため
  • Firefox 33-35で発生していた不具合に対する対策

非準拠ブラウザに対する対策

仕様に準拠していないブラウザでnoreferrerを指定してもwindow.openernullにならないことに対する対策として、noopenerを同時に指定していた、そういうブラウザが存在する可能性を想定して同時に指定していたようです。

@seancrater I don’t; the spec is often aspirational, and doesn’t describe historical (noncompliant) engines.

In general, if any version of any browser ever required both, then we should use both for the foreseeable future.

確かに、過去ChromeとFirefoxで動作が異なったり、一部のブラウザで問題が起きるといったことはありました。以下の記事では、EdgeでYahoo! Japanを表示したときに正しく表示されないという問題について問い合わせています。

今後もこのように特定のブラウザの特定のバージョンでのみ不具合が起きる可能性を考慮し、同時に指定することに対して、若干バンドルサイズが大きくなることしかデメリットがないことを考えると両方を指定しておくことは心理的安心という面からも適切な判断だと考えられます。

Firefox 33-35で発生してた不具合に対する対策

もう一つの理由はFirefox 33-35で発生していた、noreferrerを指定すると別タブで開けなくなる不具合に対する対策で、ESLintのIssueでこの点について議論されています。

Actually, I found a counter-example: Firefox 33–35 removes opener with rel="noreferrer" but doesn’t with rel="noreferrer noopener" (probably because it encounters an unsupported rel value). If you have a Browserstack account, you can verify it by opening http://noreferrer.hypnosphi.de (source) in FF 33–35 and clicking the links there.

Firefox側のIssueを見ると、noreferrerをつけていてもリファラーを送っているとありますが、これがwindow.openernullになっていないことと同じことなのかは今ひとつわかりませんでした。

If you open a link with the rel=”noreferrer” attribute in a new tab (eg. over middle click) it will send a referrer anyway.

ESLintではnoopenernoreferrerを両方指定するようにチェックしていた時期がありましたが、現在ではnoreferrerがついていることをチェックし、noopenerもついているかどうかはチェックしないようになっています。

WordPressでrel=”noopener”が自動付与される理由

WordPressでは、バージョンによって、target="_blank"を持つリンクにrel="noopener"が自動付与されるのか、rel="noopener noreferrer"が付与されるのかが変わっていたようです。

WorkPress 4.7.4からセキュリティ対策のためにrel="noopener noreferrer"が自動的に付与されるようになりました。しかし、WordPress 4.8では、rel="noopener"だけが自動付与されるように変更されています。

WordPress 5.0では新しいエディタ「Gutenberg」が導入され、rel="noopener noreferrer"が自動付与されるようになった一方で、クラシックエディタを使用している場合にはrel="noopener"だけが自動付与されるようになっていました。

WordPress 5.6ではrel="noopener"だけが自動付与されるようになり、以降はrel="noopener"だけが自動付与される仕様に落ち着いているようです。

WordPressが、rel="noreferrer"ではなくrel="noopener"を付与しているのは、セキュリティ対策をしつつアフィリエイトリンクなどのためにリファラーを送りたい(参照元を知らせたい)という点にあります。認証が必要なページと違って、ページのURLを知ってもらう機会を少しでも減らさないためにも、noreferrerではなくnoopenerが求められます。

パフォーマンス対策としてのnoopener

仕様には記載がなく、実装依存の話としてnoopenerを指定する効果のひとつにパフォーマンス対策を挙げている記事を見かけます。しかし、この主張は必ずしも正しいというわけではなく、ブラウザの実装依存であるという点は理解しておく必要があります。

window.openernullでない場合、元ページを開いているタブとtarget="_blank"で開いたページのタブは同じプロセス・スレッドで動作することになり、開いたページで重いスクリプトを実行すると、元ページのパフォーマンスにも影響を与えるというものです。

実際のブラウザのコードを見たわけではありませんが、最近のバージョンではここら辺は対策済みになっているのではないかと思います。タブの数だけスレッドが作成されるわけでもありませんし、特のタブが応答しなくても他のタブは問題なく操作できているので、主要ブラウザではこの点はあまり気にする必要がないと思います。

結局、どれを付与すればよいのか?

noopenernoreferrerのどちらを付与すればよいかについてまとめます。

「どちらも付与しない」は非推奨

タブブラウザが登場する以前ならまだしも、現在のブラウザではtarget="_blank"を指定した場合はnoopenernoreferrerのいずれかを指定すべきです。特に外部サイトのページをtarget="_blank"で開く場合はrel属性を付与することは必須であるといっても差し支えないと思います。

同一サイト内であっても、モードレスダイアログのようなユーザー体験を実現したければ、別タブで操作させるのではなく、同一タブ内にモードレスダイアログをHTML/CSS/JSを使って実現すれば済むので、そういった意味でもwindow.openerを使うことはもうないのではないかと思います。

認証が必要なページから外部ページを開くときはnoreferrerを指定する

認証されたユーザーのみが表示できるページで外部ページを開くときはそのページのURLを知られないようにするという意味でもnoreferrerを指定することが強く推奨されます。

もう少し簡単に言ってしまえば、リファラーを送りたいケース以外はnoreferrerを指定するのがよいと思います。noreferrerの方がサポートされているブラウザの範囲が広いため、セキュリティ対策を考えるとnoreferrerを使う方が安全なためです。

リファラーを送信する必要がある場合のみnoopenerを指定する

ブログやアフィリエイトサイトなど、target="_blank"で表示したサイトに元ページのURLを伝えたい、流入元がどこかを伝えたいというケースにおいてはnoopenerを指定するのがよいでしょう。

WordPressがnoreferrerを自動付与せずnoopenerを自動付与しているのはこれが理由だと考えられます。アフィリエイトの種類にもよりますが、リファラーがないとアフィリエイト報酬に計算されない場合もnoreferrerではなくnoopenerを使う必要があるので、アフィリエイトサイトの仕様を事前に確認しておくことが重要です。

rel属性が設定されていることをチェックしよう

基本的にはESLintなどの静的解析ツールでチェックするのが望ましいですが、アプリケーション開発ではURL部分が変数になることがあり、この場合は静的解析ツールではチェックしきれないという問題があります。

そのため、静的解析だけを頼りにするのではなく、他の手段も組み合わせて多層的にチェックするのがよいでしょう。

静的解析ツールでチェックする

チェック漏れを防ぐという点ではESLintなどの静的解析ツールを導入し、エディタの拡張機能でチェックしたり、CIでチェックすることは非常に重要です。しかし、すべてのケースをチェックしきれなかったり、必要ない場合でもエラーになるなどの弊害もあるため、導入できるかどうかはチームで慎重に検討することが望ましいです。

ESLintでチェックする場合、

npm install --save-dev eslint @html-eslint/parser @html-eslint/eslint-plugin

でHTMLファイルをチェックするためのプラグインも導入します。

設定ファイルでは、

import html from "@html-eslint/eslint-plugin";
import htmlParser from "@html-eslint/parser";
...

export default defineConfig([
  ...
  {
    files: ["**/*.html"],
    plugins: {
      "@html-eslint": html,
    },
    languageOptions: { parser: htmlParser },
    rules: {
      "@html-eslint/no-target-blank": "error",
    },
  },
]);

HTMLファイルを処理するルールを追加することで、HTMLファイルに対してLintingできるようになります。

aタグにtarget="_blank"があり、href属性が相対パスでない場合に、rel="noreferrer"がないと

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <a target="_blank" href="http://example.com/">Home</a>
  </body>
</html>

以下のようにエラーが出るようになります。

> test1@1.0.0 lint
> eslint *.html


/Users/user/test/index.html
  9:8  error  Missing `rel="noreferrer"` attribute in a tag  @html-eslint/no-target-blank

相対パスの場合はチェックが行われない点に注意が必要です。(あくまでも外部サイトを表示するためのセキュリティ対策にフォーカスされている)

また、先ほど参照したESLintのIssueでも触れられていますが、noopenerの有無はチェックしないようになっているので、rel="noreferrer"rel="noopener noreferrer"(順不同)のいずれかの場合にパスするようになっているため、noopenerがあることをチェックできない点にも注意してください。

CopilotなどのAIエージェントにチェックしてもらう

Copilotなどソースコードを参照できるAIエージェントにチェックしてもらうというのも手です。ワークスペース全体をチェックできる場合は網羅的にチェックしてもらえるので、非常に効率的です。

レビューの観点に加える

修正箇所に限定するのであれば、プルリクなどのレビューの観点としてリンク使用時にrel属性を付与しているかをチェックするのもよいでしょう。ただし、チェック漏れのリスクもあるため、前述のようなツールでのチェックを併用したり、チェックリストでのチェックを行うなどの対策を併用することも検討すべきです。

まとめ

noopenernoreferrerを指定することでどういった効果があるのか、これらのrel属性に対して過去にどのような経緯があったのかについて確認しました。

また、現在においてはどのように指定すればいいのか、どうやってrel属性の付与漏れを防ぐのがよいかについてもまとめました。

動作確認という点では、rel属性の有無にかかわらず問題なく動いてしまうので、発見しにくい問題ではありますが、セキュリティに関する重要な対策の1つであるため、ツールなども活用しながら付与漏れがないようにしていくことが重要です。

昨今ではCopilotなどでワークスペース全体をチェックすることも可能になってきているので、今一度点検をしてみてもよいかもしれません。

AngularプロジェクトにHuskyを導入する

今回、Huskyを導入しますが、これにはトレードオフ(メリットとデメリット)があります。

メリット:

  1. コードの品質を保つ: Huskyはコードがリポジトリにコミットされる前に自動的にリントやテストを行うことができます。これにより、間違ったコードやコーディング規約に適合しないコードがマージされるのを防ぐことができます。
  2. 自動化: Huskyを設定することで、手動でリントやテストを行う手間を省くことができます。
  3. チームの一貫性: Huskyをプロジェクトに組み込むことで、全ての開発者が同じリントやテストを実行することを保証することができます。

デメリット:

  1. 初期設定の複雑さ: Huskyの設定は少々複雑であり、最初に設定する際には時間と労力が必要となります。
  2. 間違った設定による問題: Huskyが間違って設定された場合、全く関係のないファイルがコミットの対象になってしまったり、正常なコードでもコミットできなくなる可能性があります。
  3. コミットの遅延: もし大きなプロジェクトでテストが時間を要する場合、Huskyによりコミットが遅延する可能性があります。ただし、これは通常はリントやテストの速度問題であり、Husky自体の問題ではありません。

最も注意しなければならないのは、修正した箇所とは関係ない箇所でリントエラーが発生してコミットができないという自体が起こる可能性があるか、という点です。特に途中から導入する場合はリントエラーだらけでその対応に追われるということがあります。

リントエラーが解消したコードがコミットされることが理想的ではありますが、時と場合によってはそれよりもコミットすることが優先事項であることもありますし、プロジェクトの事情で修正箇所以外のエラーは一旦見なかったことにしたいということもあると思います。

また、コードベースが非常に大きく、リントに時間がかかってコミットがストレスになるというリスクもあります。こちらについては対策がありますので、併せてご紹介します。

Huskyとは

Huskyは、JavaScriptプロジェクトにおいてGitのフック(特定のGitイベントが発生した時に実行されるスクリプト)を簡単に管理できるようにするツールです。

Gitフックは、コミット、プッシュなどのGit操作の前後に自動的に実行されるスクリプトです。これを活用することで、コードの品質を一定に保つためのチェックやテストを自動化したり、特定の操作を制限したりすることが可能になります。

しかし、GitフックはGitリポジトリごとに設定され、通常はGitリポジトリ自体と一緒にバージョン管理されません。これは、他の開発者が同じフックを設定するのを難しくするだけでなく、フックの変更を追跡するのも困難にします。

Huskyはこれらの問題を解決します。Huskyを使用すると、フックはプロジェクトの一部としてバージョン管理でき、設定はすべての開発者間で共有できます。また、Huskyの設定は通常、プロジェクトのpackage.jsonファイルに記述され、設定の変更もGitを通じて追跡することができます。

このように、HuskyはJavaScriptプロジェクトにおけるGitフックの管理を効率化し、プロジェクト全体のコード品質を向上させる強力なツールとなることができます。

Huskyのインストール

まずはじめにHuskyをインストールします。

$ npm install husky --save-dev

added 1 package, and audited 1098 packages in 1s

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

found 0 vulnerabilities

インストール自体に難しいところはありません。

pre-commitフックを設定する

では早速pre-commitフックを設定しましょう。

$ npx husky install
husky - Git hooks installed

上記のコマンドを実行すると.huskyディレクトリが作成されます。

次にpre-commitフックを追加します。実行するコマンドは前回設定したnpm run lintにします。

$ npx husky add .husky/pre-commit "npm run lint"
husky - created .husky/pre-commit

では実際に実行してみましょう。Huskyをインストールしたときの変更のコミットがまだなので、これをコミットします。

$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   package-lock.json
        modified:   package.json

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .husky/

no changes added to commit (use "git add" and/or "git commit -a")
$ git add .  
$ git commit -m 'install husky'

> angular-tutorial@0.0.0 lint
> ng lint


Linting "angular-tutorial"...

All files pass linting.

[main e0c8f78] install husky
 3 files changed, 21 insertions(+)
 create mode 100755 .husky/pre-commit

コミット時にリントが実行されていることが確認できます。

pre-commitフックでフォーマットを行う

次にpre-commitフックでPrettierを実行するようにしてみましょう。ついでに動作を確認もしてみます。

まず、Huskyのコマンドにはpre-commitフックを削除するコマンドがありません。では変更したい場合はどのようにするかを見ていきます。

現在の状態を確認する

まず、現在の状態はnpm run lintを設定してある状態です。

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint

ここに新たなコマンドを追加する場合は変わらずnpx husky addコマンドを使用します。

$ npx husky add .husky/pre-commit "npm run format"
husky - updated .husky/pre-commit

npx husky addコマンドを実行することで現在設定されているコマンドに加えて新たなコマンドがpre-commitフックに追加されます。

次にnpm run formatを削除してnpm run lintだけの状態にしてみます。これを実現するには、npx husky setコマンドを使用してnpm run lintを設定することでnpm run lintだけの状態になります。

$ npx husky set .husky/pre-commit "npm run lint"
husky - created .husky/pre-commit

このコマンドの実行するとnpm run lintだけになっていることが確認できます。

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint

最後にすべて削除する方法を確認します。先ほど使用したnpx husky setコマンドを使って削除ができます。

$ npx husky set .husky/pre-commit ""
husky - created .husky/pre-commit

上記コマンドを実行するとコマンドが削除されます。

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"


pre-commitフックでlintとフォーマットの設定を行う

話を戻してpre-commitフックにnpm run lintコマンドとnpm run formatを設定します。npx husky addコマンドを2回呼び出してコマンドを追加します。

$ npx husky add .husky/pre-commit "npm run lint"
husky - updated .husky/pre-commit
$ npx husky add .husky/pre-commit "npm run format"
husky - updated .husky/pre-commit

これにより期待したとおりコマンドが登録されます。

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"


npm run lint
npm run format

では、動作確認をしていきます。.husky/pre-commitが変更されているのでこれをコミットすることで動作確認とします。

$ git add .
$ git commit -m 'update pre-commit hook'

> angular-tutorial@0.0.0 lint
> ng lint


Linting "angular-tutorial"...

All files pass linting.


> angular-tutorial@0.0.0 format
> prettier "src/**/*.{js,jsx,ts,tsx,html,css,scss}" --write

src/app/app.component.css 9ms
src/app/app.component.html 85ms
src/app/app.component.spec.ts 71ms
src/app/app.component.ts 3ms
src/app/app.module.ts 2ms
src/index.html 1ms
src/main.ts 2ms
src/styles.css 0ms
[main aeba2e0] update pre-commit hook
 1 file changed, 2 insertions(+)

git commitをするとリントに続いてフォーマットが行われていることが確認できます。

リントおよびフォーマットの対象を限定する

現在は非常にコードが少ないためリントやフォーマットの時間がそれほどかかりません。ただ、実際のプロジェクトでは非常にたくさんのコードがある場合もあります。そのような場合、リントやフォーマットに時間がかかるだけでなく、対応した範囲とは関係ない箇所でエラーになってしまい、コミットがいつまでもできない、ということが起きることは容易に想像できます。

こういった問題を解決する一つの方法として、lint-stagedを導入します。

lint-stagedをインストール

普通のパッケージと同じようにインストールしていきます。

$ npm install --save-dev lint-staged

added 37 packages, and audited 1135 packages in 3s

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

found 0 vulnerabilities

lint-stagedを設定する

lint-stagedを設定していきます。まずはHuskyがpre-commitフックで実行するコマンドをnpx lint-stagedに変更します。

$ npx husky set .husky/pre-commit "npx lint-staged"
husky - created .husky/pre-commit

次にlint-stagedでnpm run lintコマンドとnpm run formatを実行するようにします。

{
  "name": "angular-tutorial",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "lint": "ng lint",
    "format": "prettier \"src/**/*.{js,jsx,ts,tsx,html,css,scss}\" --write"
  },
+ "lint-staged": {
+   "*.{js,jsx,ts,tsx}": [
+     "npm run lint"
+   ],
+   "*.{js,jsx,ts,tsx,html,css,scss}": [
+     "npm run format"
+   ]
+ },
  "private": true,
  "dependencies": {
    "@angular/animations": "^16.1.0",
    "@angular/common": "^16.1.0",
    "@angular/compiler": "^16.1.0",
    "@angular/core": "^16.1.0",
    "@angular/forms": "^16.1.0",
    "@angular/platform-browser": "^16.1.0",
    "@angular/platform-browser-dynamic": "^16.1.0",
    "@angular/router": "^16.1.0",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.13.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^16.1.6",
    "@angular-eslint/builder": "16.1.0",
    "@angular-eslint/eslint-plugin": "16.1.0",
    "@angular-eslint/eslint-plugin-template": "16.1.0",
    "@angular-eslint/schematics": "16.1.0",
    "@angular-eslint/template-parser": "16.1.0",
    "@angular/cli": "~16.1.6",
    "@angular/compiler-cli": "^16.1.0",
    "@types/jasmine": "~4.3.0",
    "@typescript-eslint/eslint-plugin": "5.62.0",
    "@typescript-eslint/parser": "5.62.0",
    "eslint": "^8.44.0",
    "eslint-config-prettier": "^8.9.0",
    "husky": "^8.0.3",
    "jasmine-core": "~4.6.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "lint-staged": "^13.2.3",
    "prettier": "^3.0.0",
    "typescript": "~5.1.3"
  }
}

"lint-staged"がコマンドの設定を行っている箇所です。リントとフォーマットで対象としたいファイルが異なるため分けて設定しています。

pre-commitフックを確認するまえに、npx lint-stagedコマンドを実行して動作を確認してみましょう。

$ npx lint-staged
→ No staged files found.

ステージされているファイルが何もないため、処理が行われませんでした。

では、現在変更されているコードをステージしてから実行してみましょう。

$ npx lint-staged
→ No staged files match any configured task.

少しメッセージが変わりました。ステージされているファイルはありましたが、条件にマッチするファイルがなかったため、処理が行われませんでした。

では、1つだけ処理対象となるファイルを変更してステージして動作を確認してみましょう。

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

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

app.component.tsを以下のように変更します。

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
* title = 'angular-tutorial1';
}

titleをちょっとだけ変更しています。

変更をステージして実行してみます。

$ git add .
$ npx lint-staged
✔ Preparing lint-staged...
❯ Running tasks for staged files...
  ❯ package.json — 4 files
    ❯ *.{js,jsx,ts,tsx} — 1 file
      ✖ npm run lint [FAILED]
    ✔ *.{js,jsx,ts,tsx,html,css,scss} — 1 file
↓ Skipped because of errors from tasks. [SKIPPED]
✔ Reverting to original state because of errors...
✔ Cleaning up temporary files...

✖ npm run lint:
Error: Invalid values:
  Argument: project, Given: "/Users/t0k0sh1/Workspace/angular-tutorial/src/app/app.component.ts", Choices: "angular-tutorial"

> angular-tutorial@0.0.0 lint
> ng lint /Users/t0k0sh1/Workspace/angular-tutorial/src/app/app.component.ts 

実行したところエラーになりました。

結論からいうと、lint-stagedに指定したコマンドが原因です。リントを行うためにeslintを使用しているのではなく、ng lintを使用しています。

ng lintはプロジェクト全体に対して実行するコマンドのため、ステージしたファイルに対して限定的に使用することができません。ですので、少しコマンドを変更します。

{
  "name": "angular-tutorial",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "lint": "ng lint",
    "format": "prettier \"src/**/*.{js,jsx,ts,tsx,html,css,scss}\" --write"
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
*     "eslint --fix"
    ],
    "*.{js,jsx,ts,tsx,html,css,scss}": [
      "npm run format"
    ]
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^16.1.0",
    "@angular/common": "^16.1.0",
    "@angular/compiler": "^16.1.0",
    "@angular/core": "^16.1.0",
    "@angular/forms": "^16.1.0",
    "@angular/platform-browser": "^16.1.0",
    "@angular/platform-browser-dynamic": "^16.1.0",
    "@angular/router": "^16.1.0",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.13.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^16.1.6",
    "@angular-eslint/builder": "16.1.0",
    "@angular-eslint/eslint-plugin": "16.1.0",
    "@angular-eslint/eslint-plugin-template": "16.1.0",
    "@angular-eslint/schematics": "16.1.0",
    "@angular-eslint/template-parser": "16.1.0",
    "@angular/cli": "~16.1.6",
    "@angular/compiler-cli": "^16.1.0",
    "@types/jasmine": "~4.3.0",
    "@typescript-eslint/eslint-plugin": "5.62.0",
    "@typescript-eslint/parser": "5.62.0",
    "eslint": "^8.44.0",
    "eslint-config-prettier": "^8.9.0",
    "husky": "^8.0.3",
    "jasmine-core": "~4.6.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "lint-staged": "^13.2.3",
    "prettier": "^3.0.0",
    "typescript": "~5.1.3"
  }
}

実行するコマンドをnpm run lintからeslint --fixに変更しました。変更したついでに--fixオプションをつけて修正もできるようにしてあります。

再度実行してみましょう。

$ npx lint-staged
✔ Preparing lint-staged...
✔ Hiding unstaged changes to partially staged files...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Restoring unstaged changes to partially staged files...
✔ Cleaning up temporary files...

今度はすべて成功しています。

最後にコードを整理してコミット&プッシュ

app.component.tsに加えた変更は不要なので、戻しておきます。

$ git restore --staged src/app/app.component.ts
$ git checkout -- src/app/app.component.ts

それ以外の変更は正式に採用するので、ステージしてコミットし、これまでの変更も含めてプッシュしておきます。

$ git add .
$ git commit -m 'set up husky and lint-staged'
→ No staged files match any configured task.
[main 58ad1f8] set up husky and lint-staged
 3 files changed, 504 insertions(+), 3 deletions(-)
$ git push
Enumerating objects: 19, done.
Counting objects: 100% (19/19), done.
Delta compression using up to 10 threads
Compressing objects: 100% (13/13), done.
Writing objects: 100% (16/16), 5.23 KiB | 892.00 KiB/s, done.
Total 16 (delta 7), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (7/7), completed with 3 local objects.
To github.com:t0k0sh1/angular-tutorial.git
   f20d6df..58ad1f8  main -> main

まとめ

少し長くなりましたが、Huskyとlint-stagedを導入してリントとフォーマットをpre-commitフックで実行できるようになりました。

もう少し設定が必要ですが、それは必要になったときに設定することとします。

開発を行う前に結構時間がかかりましたが、こういった設定は最初の段階で整備しておいた方がよいです。開発途中で導入しようとすると、これまでの分の修正に追われ、本来やるべきことに集中できなくなりますので、最初に説明しました。

次回はTailwind CSSを導入してコンポーネントを作成してみたいと思います。

AngularプロジェクトにPrettierとESLintを導入する

AngularプロジェクトではPrettierとESLintは最初から導入されてはいません。プロジェクト作成後にセットアップすることで利用可能となります。

実際のプロジェクトではPrettierとESLintは導入した方がよいので、実際にセットアップしていきます。

ESLintを導入する

Angular CLIにはng lintというコマンドが用意されています。プロジェクト作成直後はESLintが導入されていないため、lintの実行の代わりにELintのインストールを行うことができます。実際にやってみましょう。

$ ng lint
? Would you like to share pseudonymous 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 https://angular.io/analytics. No
Global setting: enabled
Local setting: disabled
Effective status: disabled
Cannot find "lint" target for the specified project.
You can add a package that implements these capabilities.

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

Would you like to add ESLint now? Yes
ℹ Using package manager: npm
✔ Found compatible package version: @angular-eslint/schematics@16.1.0.
✔ Package information loaded.

The package @angular-eslint/schematics@16.1.0 will be installed and executed.
Would you like to proceed? Yes
✔ Packages 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 (991 bytes)
UPDATE package.json (1424 bytes)
UPDATE angular.json (3085 bytes)
✔ Packages installed successfully.

一番最初の質問はAngular CLIの使用状況データを提供するかどうかを聞いています。その後に@angular-eslint/schematicsのインストールを行うかの確認があります。基本的にはデフォルトのまま進めていただいて構いません。

インストールが完了すると、以下が行われます。

  • AngularプロジェクトでESLintを使用する基本的なパッケージがインストールされる
  • lintを実行するためのスクリプトがpackage.jsonに追加される
  • ESLintの設定ファイル(.eslintrc.json)が追加される
  • angular.jsonにESLintに関する設定が追加される

これでlintが使用可能になります。実際に使ってみましょう。

$ ng lint

Linting "angular-tutorial"...

All files pass linting.

ESLint拡張機能を導入する

Visual Studio Codeを使用している場合は、ESLint拡張機能を導入するとリアルタイムに違反をチェックできるようになりますので、導入をお勧めします。

拡張機能にはいくつか設定項目がありますが、特に設定変更しなくても動作します。

Prettierを導入する

次にPrettierを導入します。こちらはAngular CLIに専用のコマンドが用意されているわけではないため、インストールおよび設定作業は手動で行います。

Prettierをインストールしますが、先にインストールしたESLintと競合した設定が一部あるため、eslint-config-prettierを併せてインストールします。

$ npm install --save-dev prettier eslint-config-prettier

added 2 packages, and audited 1097 packages in 4s

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

found 0 vulnerabilities

これでインストール作業が完了しました。続いて設定作業を行います。

ESLintとPrettierを併用できるようにする設定を追加する

.eslintrc.jsonにPrettierを併用できるようにするための設定を追加します。

{
  "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",
+       "prettier"
      ],
      "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": {}
    }
  ]
}

"prettier"を追記します。前の行にカンマをつけるのを忘れないように気をつけてください。

.prettierrc.jsonを作成する

Prettierの設定ファイルである.prettier.jsonを作成します。

$ touch .prettierrc.json

ファイルを作成したら以下のように記述します。

{
  "printWidth": 120,
  "singleQuote": true
}

ここでは1行の文字数を120文字、文字列でシングルクォーテーションを使用するように設定しています。シングルクォーテーションを使用する設定はEditorConfigの設定ファイル.editorconfigに記載されている

[*.ts]
quote_type = single

と一致するように設定してください。ダブルクォーテーションを使用したい場合は、.prettierrc.jsonの設定を"singleQuote": falseにし、.editorconfigの設定をquote_type = doubleに変更します。ただし、Angularプロジェクトを作成したときに自動生成されているコードはシングルクォーテーションを使用しているため、特段理由がなければシングルクォーテーションを使用してください。

コマンドでフォーマットできるようにする

package.jsonを編集してコマンドでフォーマットできるようにしましょう。

{
  "name": "angular-tutorial",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "lint": "ng lint",
+   "format": "prettier \"src/**/*.{js,jsx,ts,tsx,html,css,scss}\" --write"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^16.1.0",
    "@angular/common": "^16.1.0",
    "@angular/compiler": "^16.1.0",
    "@angular/core": "^16.1.0",
    "@angular/forms": "^16.1.0",
    "@angular/platform-browser": "^16.1.0",
    "@angular/platform-browser-dynamic": "^16.1.0",
    "@angular/router": "^16.1.0",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.13.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^16.1.6",
    "@angular-eslint/builder": "16.1.0",
    "@angular-eslint/eslint-plugin": "16.1.0",
    "@angular-eslint/eslint-plugin-template": "16.1.0",
    "@angular-eslint/schematics": "16.1.0",
    "@angular-eslint/template-parser": "16.1.0",
    "@angular/cli": "~16.1.6",
    "@angular/compiler-cli": "^16.1.0",
    "@types/jasmine": "~4.3.0",
    "@typescript-eslint/eslint-plugin": "5.62.0",
    "@typescript-eslint/parser": "5.62.0",
    "eslint": "^8.44.0",
    "eslint-config-prettier": "^8.9.0",
    "jasmine-core": "~4.6.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "prettier": "^3.0.0",
    "typescript": "~5.1.3"
  }
}

コマンド名は何でも構いませんが、ここではnpm run formatで実行できるようにしています。

これから動作確認のためにコマンドを実行しますが、実行するといくつかのファイルが変更されます。変更したくない場合は記事を読むだけにしてください。

$ npm run format

> angular-tutorial@0.0.0 format
> prettier "src/**/*.{js,jsx,ts,tsx,html,css,scss}" --write

src/app/app.component.css 9ms
src/app/app.component.html 84ms
src/app/app.component.spec.ts 72ms
src/app/app.component.ts 3ms
src/app/app.module.ts 3ms
src/index.html 1ms
src/main.ts 2ms
src/styles.css 1ms

実行するといくつかのファイルについて変更されたことが表示されます。

Prettier – Code formatter拡張機能を導入する

Visual Studio Codeを使用している場合はPrettier – Code formatter拡張機能を導入することで、コードフォーマットを自動化することができます。

こちらは拡張機能導入後にいくつかの設定を行う必要があります。主な設定項目は以下の3つです。

  • Format On Paste
  • Format On Save
  • Default Formatter

他からコピーしたコードをペーストしたときにフォーマットする場合はFormat On Pasteの設定にチェックを入れてください。これは好みかもしれませんが、ペースト後に少しいじってから保存することがほとんどなので私はチェックを入れていません。

次に保存時にフォーマットを行うようにすることでコードフォーマットを自動化できます。基本的にはチェックを入れていただくとよいのですが、自動フォーマットを有効化していると操作性が気になる場合があるかもしれません。実際に試していただいて好みに合うように調整してください。

デフォルトのフォーマッタをPrettierに変更します。これによりPrettierが有効化します。一つだけ注意点があり、PrettierはPythonには対応していません。そのため、Pythonでの開発もVisual Studio Codeで行う場合は、デフォルトのフォーマッタをPrettierに変更した上で、settings.jsonに以下の記述を追加してください。

  "[python]": {
    "editor.defaultFormatter": null,
  },

これにより.pyファイルではPrettierをフォーマッタとして使用しなくなります。少し脱線しますが、blackをフォーマッタとして使用している場合は、

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "python.formatting.provider": "black",
  "[python]": {
    "editor.defaultFormatter": null,
  },
}

のような記載になります。

変更をコミットする

前回からずっとコミットしていなかったので、ここまでの変更をコミットしておきます。

$ git add .
$ git commit -m 'install eslint and prettier'
[main f20d6df] install eslint and prettier
 11 files changed, 3137 insertions(+), 327 deletions(-)
 create mode 100644 .eslintrc.json
 create mode 100644 .prettierrc.json

本記事で使用しているプロジェクトは以下にありますので、必要に応じて参考にしてみてください。

まとめ

ちょっと長くなったので今回はここまでにします。次回はHuskyを使ってpre-commitフックでESLintとPrettierを自動実行するようにしたいと思います。

ただし、若干のトレードオフがあるため、その点についても解説します。

Node.jsで開発環境をセットアップする(ESLint、Prettier、husky)

Node.jsの開発環境で、以下の機能をセットアップする方法について解説します。

  • ESLintによるlint
  • Prettierによるコードフォーマット
  • huskyによるpre-commit git hooks

開発環境を作成する

最初に構築対象となる開発環境を用意します。

$ npm init -y
Wrote to /Users/t0k0sh1/workspace/node_lint/package.json:

{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

今回の説明とは関係ないため、デフォルトのままで進めます。

パッケージをインストールする

次に必要なパッケージをインストールします。

  • eslint – lintツール
  • prettier – formatterツール
  • eslint-config-prettier – eslintのフォーマットがprettierと競合する場合はeslint側をOFFにする
  • husky – pre-commit git hooksツール
$ npm i -D eslint eslint-config-prettier prettier husky

added 85 packages, and audited 86 packages in 4s

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

found 0 vulnerabilities

eslint-plugin-prettierは非推奨になっているため、eslint-config-prettierを使用しています。

インストール後のpackage.jsonは以下のようになっています。

// package.json
{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.13.0",
    "eslint-config-prettier": "^8.5.0",
    "husky": "^7.0.4",
    "prettier": "^2.6.2"
  }
}

lintの設定を行う

まずはESLintの設定を行います。ここでは必要最低限の設定にしています。prettiereslint:recommendの後に書いてください。

// .eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "prettier"
  ]
}

次にeslintでのlint(修正あり)とprettierでのフォーマットを行うスクリプトを追加します。

// package.json
{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint --cache --fix . && prettier --write ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.13.0",
    "eslint-config-prettier": "^8.5.0",
    "husky": "^7.0.4",
    "prettier": "^2.6.2"
  }
}

コードを作成して動作確認を行う

実際のコードを作成して動作確認をしておきましょう。

// index.js
function hello(name) {
  return 'Hello, ' + name;
}

console.log(hello("John"));

簡単なプログラムを書きました。動作確認ができるようにlintでエラーになるコードになっています。

では動作確認します。

$ node index.js
Hello, John

エラーにならず動作していることを確認できました。

では、このコードに対してlintprettierを実行します。

$ npm run lint

> node_lint@1.0.0 lint
> eslint --cache --fix . && prettier --write .


/Users/t0k0sh1/workspace/node_lint/index.js
  6:1  error  'console' is not defined  no-undef

✖ 1 problem (1 error, 0 warnings)

consoleが未定義であるとエラーになりました。これは後で修正(除去)しますが、今はこのままにしておきます。

ここまでに作成したコードをコミットしておきます。

git initコマンドでgitリポジトリを初期化します。

$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint:   git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint:   git branch -m <name>
Initialized empty Git repository in /Users/t0k0sh1/workspace/node_lint/.git/

コミットするにあたり、node_modules.eslintcacheは対象から外したいので、.gitignoreを作成しておきます。

// .gitignore
node_modules/
.eslintcache

作成したファイルをステージングエリアに追加します。

$ git add .

ローカルリポジトリにコミットしておきます。

$ git commit -m 'first commit'
[master (root-commit) ec47452] first commit
 5 files changed, 1682 insertions(+)
 create mode 100644 .eslintrc.json
 create mode 100644 .gitignore
 create mode 100644 index.js
 create mode 100644 package-lock.json
 create mode 100644 package.json

pre-commit git hooksを設定する

huskyを使ってpre-commit git hooksを設定していきます。手順は公式の手順(https://github.com/typicode/husky)に従いますが、pre-commitに追加するコマンドがnpm run lintになっている点にだけ注意してください(公式の手順ではnpm test

$ npm set-script prepare "husky install"
$ npm run prepare

> node_lint@1.0.0 prepare
> husky install

husky - Git hooks installed
$ npx husky add .husky/pre-commit "npm run lint"
husky - created .husky/pre-commit
$ git add .husky/pre-commit

手順どおりに進めると、package.jsonがステージングエリアに追加されていないため、これを追加してローカルリポジトリにコミットします。

$ git add package.json
$ git commit -m 'setup husky'

> node_lint@1.0.0 lint
> prettier --write '**/*.js' && eslint .

index.js 25ms

/Users/t0k0sh1/workspace/node_lint/index.js
  6:1  error  'console' is not defined  no-undef

✖ 1 problem (1 error, 0 warnings)

husky - pre-commit hook exited with code 1 (error)

先ほどコマンド実行で確認した時と同じようにconsoleが未定義であるとエラーになりました。

pre-commitが機能していることを確認できましたが、念のためコミットされていないかを確認しておきます。

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   .husky/pre-commit
        modified:   package.json

コミットが行われておらず、pre-commitが正しく動作していることを確認できました。

コードを修正して再度コミットする

コードを修正して再度コミットしましょう。

ここでは単純にconsole.log関数を削除しておきます。

// index.js
function hello(name) {
  return "Hello, " + name;
}

hello("John");

念のため、コマンドで確認しておきます。

$ npm run lint

> node_lint@1.0.0 lint
> eslint --cache --fix . && prettier --write .

.eslintrc.json 20ms
index.js 7ms
package-lock.json 30ms
package.json 6ms

エラーにならないことを確認できましたので、ステージングエリアに追加します。

$ git add index.js

では、再度コミットしましょう。

$ git commit -m 'setup husky'
> node_lint@1.0.0 lint
> prettier --write '**/*.js' && eslint .

index.js 25ms
[master ed5dcae] setup husky
 3 files changed, 7 insertions(+), 2 deletions(-)
 create mode 100755 .husky/pre-commit

今度はエラーが表示されず、コミットが実行されました。

git statusgit logでもコミットされていることを確認します。

git status
On branch master
nothing to commit, working tree clean
$ git log
commit ed5dcae1e5e2487854e78e0d388a2f503324231d (HEAD -> master)
Author: Takashi Yamashina <takashi.yamashina@gmail.com>
Date:   Sat Apr 9 12:51:04 2022 +0900

    setup husky

commit 15186ea9211ed9d5ee4de9aa7dab7e2e04bac9de
Author: Takashi Yamashina <takashi.yamashina@gmail.com>
Date:   Sat Apr 9 12:37:45 2022 +0900

    first commit

問題なくコミットできていることが確認できました。

ESLintで特定のファイル、フォルダを対象から除外する(.eslintignore)

ESLintで特定のファイルやフォルダを対象から除外する方法について解説します。

.eslintignoreを作成する

.eslintignoreを作成し、そこに対象から除外したいファイルやフォルダを書きます。

config.js
test/

上記の例では、config.jsというファイルと、testフォルダを対象から除外しています。

実際に試してみる

実際にどう動くのか確認しましょう。

package.json

package.jsonは次のとおりです。eslintをインストールし、eslintコマンドを実行するスクリプトを追加しています。

{
  "name": "node_eslint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint ./"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.12.0"
  }
}

.eslintrc.json

.eslintrc.jsonは必要最小限にしています。

{
    "extends": [
      "eslint:recommended"
    ]
}

プロジェクトの構造

プロジェクトの構造は以下のようになっており、用意した4つのJSファイルはすべてLintでエラーが検出されます。

$ tree
.
├── file1.js
├── file2.js
├── dir3
│   └── file3.js
├── dir4
│   └── file4.js
├── .eslintrc.json
├── package-lock.json
└── package.json

ESLintを実行する

最初に.eslintignoreを用意せずに実行してみます。

$ npm run lint                                                                                                                     

> node_eslint@1.0.0 lint
> eslint ./


/Users/t0k0sh1/workspace/node_eslint/dir3/file3.js
  1:10  error  'file3' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/dir4/file4.js
  1:10  error  'file4' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file1.js
  1:10  error  'file1' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file2.js
  1:10  error  'file2' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

✖ 8 problems (8 errors, 0 warnings)

プロジェクト直下の2ファイルもフォルダ内の2ファイルもエラーになっていることがわかります。

次に.eslintignoreを作成し、プロジェクト直下の1ファイルと2つのファイルのうちの1つを除外してから再度実行してみましょう。

file2.js
dir4/

先ほどと同様に実行してみると、除外したファイルとフォルダ内のファイルがエラーに表示されなくなりました。

$ npm run lint

> node_eslint@1.0.0 lint
> eslint ./


/Users/t0k0sh1/workspace/node_eslint/dir3/file3.js
  1:10  error  'file3' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file1.js
  1:10  error  'file1' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

✖ 4 problems (4 errors, 0 warnings)

node_modulesの除外は不要

実行してみるとわかりますが、node_modulesの除外は不要です。

そのため、対象としたいフォルダ内に除外したいファイルやフォルダがない場合は.eslintignoreを作成する必要はありません。

モバイルバージョンを終了