【初心者】Gulpで構文チェック（gulp-htmlhint、stylelint、ESLint）メモ【備忘録】

# はじめに
投稿時点で、筆者は知識ゼロの状態から勉強を初めて2ヶ月程度の実力です。
そのため、理解不足や説明不足、誤った内容や呼び方をしている可能性があります。
万が一参考にする場合は上記の点を考慮した上でご一読ください。
説明文の内容はChatGPT先生からの引用も多いです。


# 目的

こちらは、前回からの続きになります。
前回：[【初心者】Gulpでベンダープレフィックス自動付与（Autoprefixer）メモ【備忘録】](https://qiita.com/miyaayim_study/items/9f6b471775293d87ea09)

GulpでHTML、CSS、JavaScriptの構文チェックを行えるようにするのが目的です。

今回の完成品は[こちらのGitHub](https://github.com/miyaayim-study/template_project_react/tree/01d251e0a3278b5b89ef7e9b75e334886c8aab62)にあります。（一部分、本文にはない変更あり）

# 1.HTML構文チェック（gulp-htmlhint）
Gulpを使用してHTML構文チェックを行う方法をChatGPT先生に尋ねたところ、下記の3つの手段があるそうです。
1. gulp-htmlhint
2. gulp-w3c-html-validator
3. gulp-a11y

それぞれの違いをChatGPT先生に説明してもらいました。
>1.gulp-htmlhintは、HTMLの構文チェックだけを行います。一方、gulp-w3c-html-validatorとgulp-a11yは、W3C HTMLバリデータやアクセシビリティチェックなど、より広範なチェックを行うことができます。
2.gulp-htmlhintとgulp-w3c-html-validatorは、チェックに失敗したHTMLファイルの行数やエラーメッセージを出力することができます。gulp-a11yは、チェックに失敗した箇所に対して、どのようなアクセシビリティ上の問題があるかを説明することができます。
3.これらのパッケージは、使用するチェックルールやオプションをカスタマイズすることができます。gulp-htmlhintは、ルールの設定ファイルを作成することができます。gulp-w3c-html-validatorとgulp-a11yは、オプションを設定することができます。
これらの違いを考慮して、使用するパッケージを選択することが重要です。HTMLの構文チェックだけを行う場合は、gulp-htmlhintが最適です。より広範なチェックを行いたい場合は、gulp-w3c-html-validatorまたはgulp-a11yを使用することをお勧めします。

一応、人気も調べました。
[gulp-htmlhint vs gulp-w3c-html-validator vs gulp-a11y](https://npmtrends.com/gulp-a11y-vs-gulp-htmlhint-vs-gulp-w3c-html-validator)

以上を踏まえて、私はgulp-htmlhintを使ってみたいと思います。

下記を入力して実行します。
```
npm i -D gulp-htmlhint
```
インストールしたら、`gulpfile.mjs`に記述していきます。
前回に続きESM構文で記述します。

```javascript:gulpfile.mjs
import htmlhint from 'gulp-htmlhint'; // gulp-htmlhintのプラグインの読み込み

const html = (done) => { // "html"というgulpタスクを定義
  gulp.src('src/html/*.html') // 構文チェックするファイルを指定
    .pipe(htmlhint()) // htmlhintの実行
    .pipe(htmlhint.reporter()); // 実行した結果をターミナルに表示
    done();
};

export { html };
```

reporter()について

>reporter()はHTMLHintでHTML内のエラーを検知してもは処理は止まらず実行し続けます。

もしreporter()ではなく、failReporter()を使用した場合は、エラー検知時に処理と止める動作になるそうです。
きちんとした解説は末尾の参考リンクを参照ください。

下記を入力して実行してみます。
```
npx gulp html
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/18046c19-0e00-4be6-9097-c69a0c7a42e3.png)

特にエラーなく終了したみたいです。
試しに、わざとHTMLの構文をおかしくしてから実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/b6bf6eb3-9927-0e7f-4b56-b6a7566dd933.png)

なにやらエラーっぽいのが出ましたね、正しく機能しているみたいです。
実験として、`.pipe(htmlhint.reporter());`を抜いて実行してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/5c12d97b-fb02-c0a1-ec7d-7988d00d9d55.png)
さきほどはエラーが表示されたのに、エラーが表示されなくなってしまいました。
`.pipe(htmlhint.reporter());`がないと、実行結果がターミナルに表示されないというのがこれでわかりましたね。

どのような部分を構文チェックするかも細かくルール設定できるようです。
設定するには下記の手段があります。
1.gulpタスク内の`htmlhint`実行部分の引数に直接記述
2.`.htmlhintrc`という新しいファイルをgulpfile.jsと同じディレクトリに作成し、そのファイル内に記述

- 1.gulpタスク内に記述する場合
下記のようになります
```javascript:gulpfile.mjs
// gulp-htmlhint（HTML構文チェック）関連---------------------------------------------
import htmlhint from 'gulp-htmlhint'; // gulp-htmlhintのプラグインの読み込み

const html = (done) => { // "html"というgulpタスクを定義
  gulp.src('src/html/*.html') // 構文チェックするファイルを指定
    .pipe(htmlhint({ // htmlhintの実行
        "tagname-lowercase": true,
        "attr-lowercase": true,
        "attr-value-double-quotes": true,
        "attr-value-not-empty": false,
        "attr-no-duplication": true,
        "doctype-first": true,
        "tag-pair": true,
        "empty-tag-not-self-closed": true,
        "spec-char-escape": true,
        "id-unique": true,
        "src-not-empty": true,
        "title-require": true,
        "alt-require": true,
        "doctype-html5": true,
        "id-class-value": "dash",
        "style-disabled": false,
        "inline-style-disabled": false,
        "inline-script-disabled": false,
        "space-tab-mixed-disabled": "space",
        "id-class-ad-disabled": false,
        "href-abs-or-rel": false,
        "attr-unsafe-chars": true,
        "head-script-disabled": true
    }))
    .pipe(htmlhint.reporter()); // 実行した結果をターミナルに表示
    done();
};

export { html };
```
ルール内容の意味は、下記のリンクが参考になります。
[gulp-htmlhintでHTMLのバリデーションを行う](https://cly7796.net/blog/css/html-validation-with-gulp-htmlhint/)

- 2.`.htmlhintrc`という新しいファイルをgulpfile.jsと同じディレクトリに作成し、そのファイル内に記述

`.htmlhintrc`ファイル内は下記のようになります。
```:.htmlhintr
{
  "tagname-lowercase": true,
  "attr-lowercase": true,
  "attr-value-double-quotes": true,
  "attr-value-not-empty": false,
  "attr-no-duplication": true,
  "doctype-first": true,
  "tag-pair": true,
  "empty-tag-not-self-closed": true,
  "spec-char-escape": true,
  "id-unique": true,
  "src-not-empty": true,
  "title-require": true,
  "alt-require": true,
  "doctype-html5": true,
  "id-class-value": "dash",
  "style-disabled": false,
  "inline-style-disabled": false,
  "inline-script-disabled": false,
  "space-tab-mixed-disabled": "space",
  "id-class-ad-disabled": false,
  "href-abs-or-rel": false,
  "attr-unsafe-chars": true,
  "head-script-disabled": true
}
```

では、これをGulpタスク内で読み込めるようにします。
さきほど、ルール内容を直接記述していた部分に`.htmlhintrc`のファイルパスを指定します。
変更したのが下記になります。
```javascript:gulpfile.mjs
// gulp-htmlhint（HTML構文チェック）関連---------------------------------------------
import htmlhint from 'gulp-htmlhint'; // gulp-htmlhintのプラグインの読み込み

const html = (done) => { // "html"というgulpタスクを定義
  gulp.src('src/html/*.html') // 構文チェックするファイルを指定
    .pipe(htmlhint('.htmlhintrc')) // htmlhintの実行、引数に'.htmlhintrc'へのパスを指定する
    .pipe(htmlhint.reporter()); // 実行した結果をターミナルに表示
    done();
};

export { html };
```


# 2.CSS構文チェック（stylelint）
Gulpを使用してCSS構文チェックを行う方法をChatGPT先生に尋ねたところ、下記の3つの手段があるそうです。。
1. gulp-stylelint
2. gulp-csslint
3. gulp-postcss

それぞれの違いをChatGPT先生に説明してもらいました。
>gulp-stylelint:
gulp-stylelintパッケージは、Stylelintを利用してCSSファイルを構文チェックすることができます。Stylelintは、幅広いCSSスタイルガイドをサポートしており、設定ファイルを使用してルールのカスタマイズが可能です。gulp-stylelintは、設定ファイルを使用してルールを定義できるため、プロジェクトの要件に合わせたルールを適用することができます。

>gulp-csslint:
gulp-csslintパッケージは、CSSLintを利用してCSSファイルを構文チェックすることができます。CSSLintは、CSSの構文エラーや一般的な問題を検出するためのルールを提供しています。gulp-csslintは、CSSLintのルールを使用してCSSファイルをチェックするため、比較的シンプルな構文チェックに適しています。

>gulp-postcss:
gulp-postcssパッケージは、PostCSSを利用してCSSファイルを構文チェックすることができます。PostCSSは、カスタムプラグインを使用してCSSファイルを処理することができます。gulp-postcssは、PostCSSを使用してCSSファイルをチェックするため、PostCSSのプラグインを使用して、CSSファイルを変換したり、CSSファイルにカスタムルールを適用したりすることができます。

`gulp-postcss`は以前ベンダープレフィックス自動付与のときに使ったやつですね、こういうことも可能なのか。

一応、人気も調べました。
[gulp-csslint vs gulp-postcss vs gulp-stylelint](https://npmtrends.com/gulp-csslint-vs-gulp-postcss-vs-gulp-stylelint)

ChatGPT先生にオススメを聞いてみました。
>どのパッケージを選ぶかは、プロジェクトの要件に応じて異なります。しかし、一般的には、gulp-stylelintをお勧めします。
gulp-stylelintは、設定ファイルを使用してルールをカスタマイズできるため、プロジェクトの要件に合わせた構文チェックを行うことができます。また、Stylelint自体が幅広いCSSスタイルガイドをサポートしており、プロジェクトに合わせたルールを定義できるため、より柔軟に対応することができます。
ただし、プロジェクトによっては、gulp-csslintやgulp-postcssを使用することもあります。gulp-csslintは比較的シンプルな構文チェックに適しており、gulp-postcssはPostCSSの機能を利用してCSSファイルに対してカスタムルールを適用することができます。
総じて、どのパッケージを選ぶにしても、プロジェクトに合わせた設定を行い、適切にカスタマイズすることが大切です。

もともと気になってたのが`stylelint`だったのでこちらを使いたいのですが、`gulp-postcss`も`stylelint`を使用できるとのこと。
どうやら、
1.`stylelint`を導入し単独で動かす。
2.`stylelint`を導入し、それを`gulp-stylelint`経由で動かす。
3.`stylelint`を導入し、それを`gulp-postcss`経由で動かす。
の3つがあるっぽい？

どれにするか迷った結果、全て試してみることにしました。

## 1.stylelint単独

まず、下記を入力して`stylelint`本体をインストールします。と、`stylelintの基本設定（stylelint-config-standard）`をインストールするために下記を入力して実行します。
```
npm i -D stylelint
```

次に、`stylelint`本体のルール設定ですが、これは[こちら](https://qiita.com/yuzuru_xa/items/a93a7db2a2465be4cf3a)から引用した文をみてもらったほうが早いと思います。
>**stylelint のルール設定**
次にチームのコーディングルールに合わせて stylelint の設定をしていきます。
全ルールを記述していくのはかなり手間なので、公開されている既存のルールを extends し、そこに必要なルールを追加・上書きをしていきます。
既存ルールとして stylelint-config-recommended および stylelint-config-standard が有名なようですので、これらを extends することによって設定されるルールを確認し、ルール選定を行なっていきます。
npm trend によると、stylelint-config-recommended の方が若干人気があるようです。

ということらしく、公開されている既存のルール`stylelint-config-standard`または`stylelint-config-recommended`をインストールして、そちらを参照するようにしたいと思います。

詳細に設定したい場合は、下記のリンクが参考になると思います。
[CSSのLintをstylelintにする](https://qiita.com/makotot/items/c266ed11ada1423cb96e)

ちなみに、ChatGPT先生に`stylelint-config-standard`と`stylelint-config-recommended`の違いを説明してもらいました。

>stylelint-config-standard と stylelint-config-recommended は、どちらもstylelintの設定ファイルで、CSSのスタイルガイドラインを構成するルールセットの集合です。ただし、ルールの厳しさやルールの種類に違いがあります。
stylelint-config-recommended は、stylelintが推奨するルールのセットであり、比較的緩いルール設定になっています。これにより、開発者がスタイルガイドラインに従うことが推奨されますが、開発者が使いやすく柔軟な方法でスタイルを実装できるように設計されています。
一方、stylelint-config-standard は、より厳しいルール設定になっており、より多くのスタイル規則に従うことが求められます。これは、プロジェクトのスタイルを一貫して保ち、メンテナンスしやすくするためです。通常、stylelint-config-standard を使用することで、より堅牢で一貫性のあるコードを実装できます。
どちらを使用するかは、プロジェクトのニーズに合わせて決定する必要があります。一般的には、スタイルの保守性が高く、開発者がより厳密にスタイルガイドラインに従う必要がある場合は、stylelint-config-standard を選択することが推奨されます。

ひとまず今回は、`stylelint-config-standard`を使用したいと思います。
それでは、下記を入力して`stylelintの基本設定（stylelint-config-standard）`をインストールします。

```
npm i -D stylelint-config-standard
```

`stylelint`本体に`stylelint-config-standard`を適用する方法は調べた感じ下記のようです。

1.`.stylelintrc`または`.stylelintrc.json`に書く　（ファイル名が違うだけでまったく同じ）
2.`.stylelintrc.js`または`.stylelint.config.js`に書く　（ファイル名が違うだけでまったく同じ）
3.`package.json`に書く（stylelintキー）

それぞれやり方をみてみましょう。

## 1.`.stylelintrc`または`.stylelintrc.json`に書く


`.stylelintrc`ファイルを作成し、下記のように記述します。
`.stylelintrc.json`でも記述内容は全く同じです。

```javascript:.stylelintrc
{
  "extends": "stylelint-config-standard"
}
```

## 2.`.stylelintrc.js`または`.stylelint.config.js`に書く
`.stylelintrc.js`ファイルを作成し、下記のように記述します。
`.stylelint.config.js`でも記述内容は全く同じです
jsファイルのメリットはコメントアウトが使用できることです。

```javascript:.stylelintrc.js
module.exports = {
  "extends": [
    "stylelint-config-standard"
  ]
};
```

## 3.`package.json`に書く（stylelintキー）
`package.json`に下記の記述を追加します。

```json:package.json
"stylelint": {
    "extends": "stylelint-config-standard"
  }
```

`package.json`全体はこちらになりました。

```json:package.json
{
  "name": "project_react",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.21.4",
    "@babel/preset-env": "^7.21.4",
    "@babel/preset-react": "^7.18.6",
    "autoprefixer": "^10.4.14",
    "babel-loader": "^9.1.2",
    "browser-sync": "^2.29.1",
    "gulp": "^4.0.2",
    "gulp-htmlhint": "^4.0.2",
    "gulp-imagemin": "^8.0.0",
    "gulp-postcss": "^9.0.1",
    "gulp-sass": "^5.1.0",
    "sass": "^1.61.0",
    "stylelint": "^15.4.0",
    "stylelint-config-standard": "^32.0.0",
    "webpack": "^5.78.0",
    "webpack-cli": "^5.0.1",
    "webpack-stream": "^7.0.0"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "stylelint": {
    "extends": "stylelint-config-standard"
  }
}
```


いずかの方法で記述したら、実行してみます。
コマンド内容は、`npx stylelint ファイルパス/ファイル名`となります。
```
npx stylelint dist/style.css
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/f5059f32-89f1-1480-1943-132907cb9b0f.png)
実行したところ、2件のお叱りを受けました。
まず、実行時の`style.css`の中身は下記のようになっています。

```css:style.css
div {
  background-color: green;
  padding: 1rem;
}
div h1 {
  color: red;
  height: 5rem;
  width: auto;
}
div p {
  color: blue;
}
```

なにもおかしいところはないと思っていたのですが…メッセージをChatGPT先生に解読してもらいました。
>エラーメッセージによると、5行目と10行目にあるルールの前に空白行がないという問題が検出されたようです。これは、 rule-empty-line-before と呼ばれるルールが適用された結果です。
このルールは、ルールが始まる前に空白行を挿入することを強制します。 このルールに違反すると、エラーとして報告されます。これは、スタイルの可読性と保守性を向上させるために役立ちます。
エラーを解消するには、各ルールの前に空白行を追加する必要があります。

これを踏まえて色々試した結果、下記の記述で上手くいきました。
```css:style.css
div {
  background-color: green;
  padding: 1rem;
}

div h1 {
  color: red;
  height: 5rem;
  width: auto;
}

div p {
  color: blue;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/27c7b83a-7a99-4317-3580-a3454afd84cc.png)
チェック結果に問題ない場合は、何もメッセージが表示されないようです。
ひとまずこれで、stylelint単独で動かすのは成功です。

## 2.gulp-stylelint（ボツ案）

次は、先程の`stylelint`を`gulp-stylelint`を使って動かしたいと思います。
下記を入力して`gulp-stylelint`をインストールします。

```
npm i -D gulp-stylelint
```

とここで、インストールしようししたら下記のようなエラーがでました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/2bee45fc-48a1-e76d-9266-2ae52a7557a9.png)

調べた結果、ChatGPT先生により下記のことがわかりました。
>gulp-stylelintがstylelintの古いバージョンを必要としているのに対し、プロジェクトでインストールされているstylelintはより新しいバージョンであるため、依存関係が解決できない状態になっています。

現時点での`stylelint`の最新バージョンは`15.4.0`。
現時点での`gulp-stylelint`の最新バージョンは`13.0.0`。
むりやり解決する方法はあるみたいですが、問題が生じる可能性があるとのことなので却下。
`gulp-stylelint`での`stylelint`実行は諦めました。
`gulp-stylelint`の参考記事が見当たらなかったのはこういうことがあるからだったのかもしれません。

## 3. gulp-postcss

`gulp-postcss`は以前の記事でインストール済みですが、インストールするところから説明します。

下記を入力して実行してインストールします。
```
npm i -D gulp-postcss
```

インストールしたら、`gulpfile.mjs`に記述していきます。

### 単独で実行
まずは、Gulpで`stylelint`を単独実行するようにしてみたいと思います。
```javascript:gulpfile.mjs
// stylelint（CSS構文チェック）関連---------------------------------------------
import postcss from 'gulp-postcss'; // gulp-postcssパッケージをインポートする
import stylelint from 'stylelint'; // stylelintパッケージをインポートする

const css = (done) => {
  const plugin = [stylelint()]; // stylelintを使ったチェックを実行するPostCSSプラグインを定義する

  gulp.src('./dist/style.css') // 構文チェックするファイルを指定
    .pipe(postcss(plugin)) // PostCSSからstylelintプラグインを実行
    done();
};

export { css };
```
では下記を入力して実行してみます。
```
npx gulp css
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/d0fa4051-a848-1382-465f-d64e414205f1.png)
下2行が、構文チェックのお叱りメッセージになります。
赤字にはなっていませんが、内容自体はさきほどの結果と同じようです。
一つ疑問なのが、`stylelint-config-standard`はどのように参照しているかです。
結果としては、`.stylelintrc`を読み込んでくれているようです。
HTML構文チェックのときのように、設定ファイルを参照させる必要があると思ったのですが……まぁいいでしょう。
メッセージ内容を赤字表示にしたいのですが、自分の力量では上手くいきませんでした。

### Sassコンパイルと合わせて実行
では次に、これをSassのコンパイル作業に組み込んでみたいと思います。
先程までのcssタスクは不要ですので削除してかまいません。

Sassタスクに組み込んだ結果が下記になります。
```javascript:gulpfile.mjs
// Sass関連---------------------------------------------
import gulpSass from "gulp-sass";
import sassCompiler from "sass";
const sass = gulpSass(sassCompiler);

// postcss関連
import postcss from 'gulp-postcss';
import autoprefixer from 'autoprefixer';
import stylelint from 'stylelint'; // stylelint（CSS構文チェック）パッケージをインポートする


const compileSass = (done) => {

  const option = [autoprefixer()];
  const plugin = [stylelint()]; // 定数pluginにstylelintを指定して定義

  gulp.src("src/sass/style.scss")
    .pipe(
      sass({
        outputStyle: "expanded"
      })
    )
    .pipe(postcss(option))
    .pipe(postcss(plugin)) // PostCSSからstylelintプラグインを実行
    .pipe(gulp.dest("./dist"))
    done();
};

export { compileSass };
```

コメントアウトの説明がある部分が、追加した行になります。
定数`option`と`plugin`は一つにまとめることが可能でした。
```javascript:gulpfile.mjs
//変更前
const option = [autoprefixer(),stylelint()]; // 定数optionにautoprefixerを指定して定義（ベンダープレフィックス自動付与）
const plugin = [stylelint()]; // 定数pluginにstylelintを指定して定義（CSS構文チェック）

//変更後
const option = [autoprefixer(),stylelint()]; // 定数optionにautoprefixerとstylelintを指定して定義
```

この場合、autoprefixerが実行されて、その後にstylelintが実行されます。
したがって、コンパイルされたCSSには、まずベンダープレフィックスが自動付与された後、stylelintによる構文チェックが実行されます。
整頓した結果、下記になりました。

```javascript:gulpfile.mjs
// Sass関連---------------------------------------------
import gulpSass from "gulp-sass"; // gulp-sassパッケージのgulp-sassモジュールをインポートする
import sassCompiler from "sass"; // sassパッケージに含まれるSassコンパイラ本体のsassモジュールをインポートする
const sass = gulpSass(sassCompiler); // gulp-sassのコンストラクタ関数にsassコンパイラを渡して、コンパイラを使用するための定数sassを定義

// postcss関連
import postcss from 'gulp-postcss'; // gulp-postcssパッケージをインポートする
import autoprefixer from 'autoprefixer'; // Autoprefixer（ベンダープレフィックス自動付与）のパッケージをインポートする
import stylelint from 'stylelint'; // stylelint（CSS構文チェック）パッケージをインポートする

const compileSass = (done) => { // "compileSass"というgulpタスクを定義、 (done)はラストのdone()でタスク完了の合図を受け取るためのもの

  const option = [ // 定数optionにautoprefixerとstylelintを指定して定義
    autoprefixer(), // Autoprefixer（ベンダープレフィックス自動付与）
    stylelint() // stylelint（CSS構文チェック）
  ];

  gulp.src("src/sass/style.scss") // コンパイルするSassファイルを指定
    .pipe(
      sass({ // 定数sassを実行
        outputStyle: "expanded" // 出力されるCSSの書式を"expanded"（展開形式）に設定する
      })
    )
    .pipe(postcss(option)) // PostCSSで定数option内の作業を実行
    .pipe(gulp.dest("./dist")) // 出力先ディレクトリを指定
    done(); //done()でタスク完了の信号を出す
};

export { compileSass };
```


では、Sassコンパイルを実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/7f2cb9a8-124f-647f-b284-4512e853f1e8.png)
無事、コンパイルと構文エラーが出てくれましたね。
途中で気づいてましたが、このやり方だと自動でstyle.cssが生成されるので構文エラーを修正しようがないんですよねぇ。
それをどうにかしようと思ったら設定ファイルを書き換えるとかすればいいのでしょうが……素人には負担が大きい…。
ということでルール設定のファイルを厳しめの`stylelint-config-standard`から、緩めのルールの`stylelint-config-recommended`に変更してみます。
下記を入力してインストールします。
```
npm i -D stylelint-config-recommended
```
その後は設定ファイルも`stylelint-config-recommended`に記述変更したら、実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/8a9f9bdb-e892-1102-fba1-032e07d88003.png)
コンパイル後の叱られメッセージが無くなりました。
わざと叱られてみようと思います、scssファイルの記述を「height」→「heig」と1文字減らして実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/3eba8f60-978f-bb59-6ebf-c191a202d1a5.png)
きちんと叱ってくれました。
この緩めの設定ファイルが今の自分には合っていそうです。


### stylelint-scss
調べていたら、`stylelint-scss`というのを知りました。
みてのとおり、scssファイルの構文チェックみたいです。
早速使ってみたいと思います。
まずは、`stylelint-scss`と`stylelint-config-recommended-scss`の2つをインストールします。
今回は最初から`recommended`の緩めルールでいきます。
```
npm i -D stylelint-scss stylelint-config-recommended-scss
````
`.stylelintrc`ファイルの記述を`stylelint-config-recommended-scss`に変更します。
```json:.stylelintrc
{
  "extends": [
    'stylelint-config-recommended-scss'
  ]
}
```

まずは直接実行してみます。
```
npx stylelint src/sass/layout/_header.scss
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/f02b54c7-56bb-7c80-ba72-788937faa0d7.png)
ちゃんとエラーが出ていますね。
少し気になったので色々実験してみます。
設定ファイルの記述を以前の`stylelint-config-recommended`に戻して実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/4a0bfc03-f8f1-0194-cda3-14eb4be96ded.png)
メッセージが一文増えていますね。
このメッセージは、StylelintがCSS以外の構文を検証しようとしているため、"customSyntax"オプションを使用する必要があるという警告だそうです。
とはいえ、きちんと構文チェックはしてくれているんですね。
では、`.stylelintrc`に2つの設定ファイルを記述します。

```json:.stylelintrc
{
  "extends": [
    'stylelint-config-recommended',
    'stylelint-config-recommended-scss'
  ]
}
```
これで実行するとどうなるのでしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/b99a2146-214a-d08a-e3dd-318a7d9a028d.png)
結果として`stylelint-config-recommended-scss`だけのときと同じ内容ですね。
他の記事でみかけたのをマネしましたが、2つ書いてもいいみたいですね。


では次の実験で、`stylelint-config-recommended-scss`だけの設定ファイル状態で、style.cssの構文チェックをしてみます。
```
npx stylelint dist/style.css
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/28df75b5-723b-1534-8e21-65025aff440b.png)
うーん…構文エラーのみで、sassファイル構文チェックをcssファイルで実行していることに関しては何も言われませんでしたね…。
ここで色々調べた結果、下記のことがわかりました。

>stylelint-config-recommended-scssとstylelint-config-recommendedは、それぞれSassを含むCSSと純粋なCSSに対する推奨設定を提供するために用意されている設定ファイルです。通常、プロジェクトでSassを使用している場合は、stylelint-config-recommended-scssを使い、純粋なCSSの場合はstylelint-config-recommendedを使用することが推奨されています。
ただし、両方の設定ファイルを同時に使用する必要性がある場合もあります。たとえば、プロジェクト内でSassと純粋なCSSを混在して使用している場合や、一部のファイルでSassを使用している場合などです。このような場合、stylelint-config-recommended-scssとstylelint-config-recommendedの両方を同時に使用することが必要になるかもしれません。
ただし、その場合は、どちらか一方の設定ファイルが重複するルールを含むことがあるため、適切な設定を行う必要があります。また、extendsで設定ファイルを指定する順序にも注意する必要があります。Sass用の設定ファイルが先に指定されるようにすると、Sassに関するルールが優先されるため、混在している場合でも問題が発生しなくなります。

>stylelint-config-recommended-scssは、Sassを含むCSSの文法チェックを行うだけでなく、CSSの文法チェックも行います。stylelint-config-recommended-scssは、stylelint-config-recommendedを拡張した設定であり、基本的にはstylelint-config-recommendedと同じようにCSSの文法チェックを行います。ただし、Sass独自の文法をサポートするため、より広範な文法チェックが可能です。

>stylelint-config-recommended-scssは、stylelint-config-recommendedを含んでおり、さらにSassの文法チェックに必要なルールが追加されています。つまり、stylelint-config-recommended-scssを使うことで、stylelint-config-recommendedに含まれるルールもすべて利用することができます。ただし、stylelint-config-recommended-scssにはstylelint-config-recommendedにはないルールも含まれているため、完全な上位互換とは言い切れません。

なるほど、では下記の記述はどちらが優先されるのか聞いてみました。
```json:.stylelintrc
{
  "extends": [
    'stylelint-config-recommended',
    'stylelint-config-recommended-scss'
  ]
}
```

>指定された順番通りに適用されます。つまり、まず stylelint-config-recommended が適用され、その上に stylelint-config-recommended-scss が適用されます。つまり、stylelint-config-recommended-scss で定義された設定は、stylelint-config-recommended で上書きされることがあります。

どちらか1つに絞ったほうがいいのかも聞いてみました。

>そうではありません。stylelint-config-recommendedとstylelint-config-recommended-scssの両方を同時に使うことは、Sassを含めたすべてのCSSの文法チェックを行うために推奨される方法です。ただし、どちらの設定も同じルールを含んでいるため、重複するルールが発生する場合があります。
このため、stylelint-config-recommended-scssがstylelint-config-recommendedを拡張しているため、stylelint-config-recommended-scssだけをextendsに設定することができます。ただし、プロジェクトによっては、stylelint-config-recommendedによって提供されるルールも必要な場合があるため、両方を使うこともあります。

#### 警告メッセージ
少し脱線しますが、ここでメッセージの表示を警告っぽくする方法がわかりました。
`postcss-reporter`というものをインストールします。
>postcss-reporterは、PostCSSプラグインであり、PostCSSプロセスの結果をターミナルに出力することができます。主に、エラーや警告などの問題が発生した場合に役立ちます。通常、このプラグインは他のPostCSSプラグインと一緒に使用され、PostCSSプロセスの最後の段階で実行されます。プロセス中に発生した問題を報告し、修正すべき問題を特定することができます。

```
npm i -D postcss-reporter
```
これをGulpの単独実行で試します。
それと、`stylelint()`はわざわざ定数にする必要はありませんでした…他の方の記事をマネしてたのでわかってませんでした…反省。
数が増えると定数化したほうが管理しやすいですが、今回は定数化せずにしたいと思います。
下記のようになりました。
```javascript:gulpfile.mjs
// stylelint（CSS構文チェック）関連---------------------------------------------
import postcss from 'gulp-postcss'; // gulp-postcssパッケージをインポートする
import stylelint from 'stylelint'; // stylelintパッケージをインポートする
import postcssReporter from 'postcss-reporter'; // postcss-reporterパッケージをインポートする

const css = (done) => {

  gulp.src('./dist/style.css') // 構文チェックするファイルを指定
    .pipe(postcss([
      stylelint(), // stylelintで構文チェック
      postcssReporter({clearMessages: true}) // エラーメッセージ表示
    ]))
    
    done();
};

export { css };
```

これで実行すると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/898258c2-0ba1-1e0a-3544-2c5e18b70ae6.png)
おお、2行増えて警告っぽいメッセージになりましたね、これは読みやすい。
以上です、話が脱線しました。


#### Gulpに組込
それではGulpに組み込みます。
自分の考えでは、sassファイルの構文チェックなのでコンパイル前に行う必要があると思うのですが、参考にした記事ではコンパイル後に`stylelint`を一度だけ実行していました。
今までの実験から、`style.css`に`stylelint-config-recommended-scss`を当てたとしても問題ないことはわかっていますが、これでは`stylelint-config-recommended-scss`を入れている意味が無いのでは？という疑問が生じます。
これに関しては、他の皆がどうしているのかとか調べましたがGulpでsassコンパイルと文法チェック両方を行っている事例が１つしかみつからず素人には結論が出せませんでした。

ってことで自分で決めました。
scssファイルを文法チェック → sassコンパイル → ベンダープレフィックスを付与。
これでやってみたいと思います。
Saaコンパイルに組み込んでみました。

```javascript:gulpfile.mjs
// Sass関連---------------------------------------------
import gulpSass from "gulp-sass"; // gulp-sassパッケージのgulp-sassモジュールをインポートする
import sassCompiler from "sass"; // sassパッケージに含まれるSassコンパイラ本体のsassモジュールをインポートする
const sass = gulpSass(sassCompiler); // gulp-sassのコンストラクタ関数にsassコンパイラを渡して、コンパイラを使用するための定数sassを定義

// postcss関連
import postcss from 'gulp-postcss'; // gulp-postcssパッケージをインポートする
import autoprefixer from 'autoprefixer'; // Autoprefixer（ベンダープレフィックス自動付与）のパッケージをインポートする
import stylelint from 'stylelint'; // stylelint（CSS構文チェック）パッケージをインポートする
import postcssReporter from 'postcss-reporter'; // postcss-reporterパッケージをインポートする


const compileSass = (done) => { // "compileSass"というgulpタスクを定義、 (done)はラストのdone()でタスク完了の合図を受け取るためのもの

  gulp.src("src/sass/style.scss") // コンパイルするSassファイルを指定

    .pipe(postcss([
      stylelint(), // stylelintで構文チェック
      postcssReporter({clearMessages: true}) // エラーメッセージ表示
    ]))

    .pipe(
      sass({ // 定数sassを実行
        outputStyle: "expanded" // 出力されるCSSの書式を"expanded"（展開形式）に設定する
      })
    )

    .pipe(postcss([autoprefixer()]))   // autoprefixerでベンダープレフィックス付与
    
    .pipe(gulp.dest("./dist")) // 出力先ディレクトリを指定
    done(); //done()でタスク完了の信号を出す
};

export { compileSass };
```
実行すると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/85fa7660-39f3-c679-5fdc-954a117621ea.png)
スクショしきれないぐらいのエラーが出ました。
ChatGPT先生に相談しましたが、あまり納得のいく答えはもらえませんでした。
仕方ないので、sassコンパイル後に行います。
```javascript:gulpfile.mjs
// Sass関連---------------------------------------------
import gulpSass from "gulp-sass"; // gulp-sassパッケージのgulp-sassモジュールをインポートする
import sassCompiler from "sass"; // sassパッケージに含まれるSassコンパイラ本体のsassモジュールをインポートする
const sass = gulpSass(sassCompiler); // gulp-sassのコンストラクタ関数にsassコンパイラを渡して、コンパイラを使用するための定数sassを定義

// postcss関連
import postcss from 'gulp-postcss'; // gulp-postcssパッケージをインポートする
import autoprefixer from 'autoprefixer'; // Autoprefixer（ベンダープレフィックス自動付与）のパッケージをインポートする
import stylelint from 'stylelint'; // stylelint（CSS構文チェック）パッケージをインポートする
import postcssReporter from 'postcss-reporter'; // postcss-reporterパッケージをインポートする


const compileSass = (done) => { // "compileSass"というgulpタスクを定義、 (done)はラストのdone()でタスク完了の合図を受け取るためのもの

  gulp.src("src/sass/style.scss") // コンパイルするSassファイルを指定

    .pipe(
      sass({ // 定数sassを実行
        outputStyle: "expanded" // 出力されるCSSの書式を"expanded"（展開形式）に設定する
      })
    )

    .pipe(postcss([autoprefixer()]))  // autoprefixerでベンダープレフィックス付与
    .pipe(postcss([
      stylelint(), // stylelintで構文チェック
      postcssReporter({clearMessages: true}) // エラーメッセージ表示
    ]))
    
    .pipe(gulp.dest("./dist")) // 出力先ディレクトリを指定
    done(); //done()でタスク完了の信号を出す
};

export { compileSass };
```
これで実行すると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/a861b049-e7c7-2153-0c0b-cce006865eed.png)
うん、一応構文チェックはしてくれてますね。
自分ではこれが限界だったのでCSS構文チェックに関してはここまでとします。

#### 備忘録
記述の仕方のメモ
```javascript:gulpfile.mjs
// 変更前
.pipe(postcss([autoprefixer()])) 
.pipe(postcss([stylelint()])) 


//変更後
.pipe(postcss([
  stylelint(),
  autoprefixer()
]))
```
↓　`postcssReporter`追加して
```javascript:gulpfile.mjs
// 変更前
.pipe(postcss([
  stylelint(),
  autoprefixer(),
  postcssReporter({clearMessages: true})
]))

// 変更後
const option = [
  stylelint(),
  autoprefixer()
];
const css = (done) => {
  //省略
  .pipe(postcss(option.concat([postcssReporter({ clearMessages: true })])))
```
`stylelint()`と`autoprefixer()`を定数`option`にまとめて、`option`を`concat()`で結合して、`postcssReporter()`を追加しています。


## CSSプロパティを自動で順序変更
少し脱線しますが、`stylelint-config-recess-order`というのが良さげだったのでこれも試してみたいと思います。
>stylelint-config-recess-order は、CSSプロパティの宣言順序を自動的に整理するためのStylelintの設定です。Stylelintは、CSSコードの検証と整形を行うためのJavaScriptベースのツールで、stylelint-config-recess-orderは、Stylelintが宣言を効果的に並び替えるためのルールを提供します。
この設定では、次のようなルールが含まれます：
1つのCSSプロパティの宣言を1つの行にまとめる
!importantがある場合は、そのプロパティを最上部に移動する
プロパティをアルファベット順で並べる
プロパティのグループごとに特定の順序で並べる
stylelint-config-recess-orderは、より整理されたCSSコードを作成するために使用されます。この設定を使用することで、コードの一貫性を維持し、保守性を向上させることができます。

では下記を実行してインストールします。

```
npm i -D stylelint-config-recess-order
```

インストールしたら`.stylelintrc`に追記します。
```.stylelintrc
{
  "extends": [
    'stylelint-config-recommended-scss',
    'stylelint-config-recommended',
    "stylelint-config-recess-order"
  ]
}
```
まずはGulpを使用せずに直接scssファイルを参照して実行してみます。
```console
npx stylelint src/sass/layout/_header.scss
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/3281b261-077d-8830-b8ad-58340ca7b458.png)
正しいプロパティの順番ではないということをメッセージで表示してくれました。
しかしこれだけでは警告をするだけで、自動で順序変更をしてくれるわけではないのですね。
自動で順序変更するには、実行時に`--fix`を使用するそうです
下記のように実行します。
```console
npx stylelint --fix src/sass/layout/_header.scss
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/a6fc612e-8bec-f423-34a4-6c49c8d3b8c4.png)
今度はエラーを表示せず、代わりにscssファイル内のプロパティ順番が変化しました。

ではGulpのSassコンパイルタスクに組み込みます。
Gulpで行うには、`fix: true`というのを追加すればいいようです。
`gulpfile.mjs`のSassコンパイルタスクを下記のようにしました。

```javascript:gulpfile.mjs
// Sass関連---------------------------------------------
import gulpSass from "gulp-sass";
import sassCompiler from "sass";
const sass = gulpSass(sassCompiler);

// postcss関連
import postcss from 'gulp-postcss';
import autoprefixer from 'autoprefixer';
import stylelint from 'stylelint';
import postcssReporter from 'postcss-reporter';


const compileSass = (done) => {

  gulp.src("src/sass/style.scss")

    .pipe(
      sass({
        outputStyle: "expanded"
      })
    )

    .pipe(postcss([autoprefixer()])) 
    .pipe(postcss([
      stylelint({
        configFile: ".stylelintrc", // .stylelintrcファイルを参照
        fix: true, // 生成するファイルのプロパティ順序を自動修正する
      }),
      postcssReporter({clearMessages: true})
    ]))
    
    .pipe(gulp.dest("./dist"))
    done();
};

export { compileSass };
```
調べていたら`.stylelintrc`ファイルを指名する方法もわかったのでそちらも追記しました。
そして本命の`fix: true`はその下に追加してあります。
では実行してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/bb006cc9-512f-3fef-f5c7-16911db9a5cf.png)
scssファイルは変わりありませんが、生成された`style.css`はプロパティ順序が変更されています。
成功ですね、本当はscssファイルにも適用したいのですが、ちょっと今の自分にはできそうにないのでここまでとします。




# 3.JavaScript構文チェック（ESLint）
Gulpを使用してJavaScript構文チェックを行う方法をChatGPT先生に尋ねたところ、下記の5つの手段があるそうです。
1. ESLint 
2. JSHint 
3. JSLint 
4. TypeScript
5. Flow

それぞれの違いをChatGPT先生に説明してもらいました。
>ESLintは、カスタマイズ可能なルールを使って、コードの品質や一貫性を向上させる静的解析ツールです。JSHintやJSLintよりも柔軟で、開発者は独自のルールを定義することができます。また、ESLintは、JavaScriptのエコシステムで非常に人気があります。

>JSHintは、シンプルで軽量な構文チェッカーで、JavaScriptの構文エラーを検出します。JSLintよりもカスタマイズ性は低いですが、JSLintと比較して高速で、構文エラーを簡単に修正することができます。

>JSLintは、JavaScriptの構文エラーを検出し、プログラムのコード品質を評価する静的解析ツールです。JSHintやESLintよりも厳格で、コーディングスタイルに対する強制力が高いです。また、JSLintは、ワンライナーのコードを好ましくないと判断することがあります。

>TypeScriptは、静的型付けのJavaScriptの拡張で、コンパイル時に構文エラーを検出できます。TypeScriptは、JavaScriptの構文を拡張しているため、JavaScriptと比較して、より厳密な型検査を行うことができます。

>Flowは、静的型チェッカーで、JavaScriptコードに型アノテーションを追加することで、構文エラーを検出できます。TypeScriptと同様に、より厳密な型検査が可能ですが、TypeScriptと比較してシンプルで、JavaScriptコードに手軽に導入できます。

`TypeScript`と`Flow`は今回やりたいこととは違う気がするので、それ以外の3つで考えたいと思います。
一応、人気も調べました。
[eslint vs jshint vs jslint](https://npmtrends.com/eslint-vs-jshint-vs-jslint)

`ESLint`が人気で参考記事も多いので、こちらを使ってみたいと思います。

下記を入力して、`ESLint`本体をインストールします。
```console
npm i -D eslint
```

インストールしたら、下記を実行して設定ファイルを作成します。
```console
npx eslint --init
```
実行すると、下記のメッセージが表示されます。
これは、「`@eslint/create-config`パッケージのインストールを続行してもいいですか？」
という意味なので、<y>キーを押して続行します。
```console
You can also run this command directly using 'npm init @eslint/config'.
Need to install the following packages:
  @eslint/create-config@0.4.2
Ok to proceed? (y) y
```

ここからコンソールログに表示される質問に回答していき、設定ファイルをどのようなものにするかを選択していきます。
（下記の私の回答は素人なので、参考にしないほうイイデス…。）


質問1：ESLintをどのように使用しますか？（矢印キーで選択する）
（? How would you like to use ESLint? (Use arrow keys)）

1.構文のみをチェックする場合
2.構文を確認し、問題を発見するため
3.構文チェック、問題点の発見、コードスタイルの適用のため

私は、2を選択しました。

質問2：プロジェクトではどのようなモジュールを使用していますか？（矢印キーで選択）
（? What type of modules does your project use? (Use arrow keys)）

1.JavaScript modules (import/export)
2.CommonJS (require/exports) 
3.いずれもなし

私は、1を選択しました。

質問3：プロジェクトではどのフレームワークを使用していますか？（矢印キーで選択）
（? Which framework does your project use? (Use arrow keys)）

1.React 
2.Vue.js 
3.いずれもなし

私は、3を選択しました。

質問4：プロジェクトではTypeScriptを使用していますか？（<y>キーか<n>キーで選択）
（? Does your project use TypeScript? (y/N) ）

私は、Noを選択しました。

質問5：コードはどこで実行されますか？（(<space>キーを押すと選択、<a>キーを押すとすべて切り替え、<i>を押すと選択を反転）
（? Where does your code run? (Press <space> to select, <a> to toggle all, <i> to 
invert selection)）

1.ブラウザ
2.ノード

私は、1のみを選択しました。

質問6：プロジェクトのスタイルをどのように定義しますか？（矢印キーで選択）
（? How would you like to define a style for your project? (Use arrow keys)）

1.人気のスタイルガイドを使う
2.自分のスタイルに関する質問に答える
3.JavaScriptファイルを確認する

参考記事ではこれを質問されていたのですが、私はこの質問をされませんでした。
もし質問されていたら私は、1を選択するつもりでした。

質問7：どのスタイルガイドに従いますか？（矢印キーで選択）
（? Which style guide do you want to follow? (Use arrow keys)）

1.Airbnb: https://github.com/airbnb/javascript
2.Standard: https://github.com/standard/standard
3.Google: https://github.com/google/eslint-config-google

参考記事ではこれを質問されていたのですが、私はこの質問をされませんでした。
もし質問されていたら私は、1を選択するつもりでした。（ChatGPT先生に聞いた説明を後述に記載。）

質問8：コンフィグファイルの形式は？（矢印キーで選択）
（? What format do you want your config file to be in? (Use arrow keys)）
1.JavaScript
2.YAML
3.JSON

私は、3を選択しました。（他のやつもJSONファイルなので今回は揃えてみただけ。1と2はコメントアウトで説明書きを記述できるので使いやすさはそっちのほうがいいと思う）

質問9：npmで今すぐインストールしますか？（<y>キーか<n>キーで選択）

参考記事ではこれを質問されていたのですが、私はこの質問をされませんでした。


今回の回答結果は下記になります。
```console
F:\webcoding\template\project\project_react>npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
Need to install the following packages:
  @eslint/create-config@0.4.2
Ok to proceed? (y) y
√ How would you like to use ESLint? · problems    
√ What type of modules does your project use? · esm
√ Which framework does your project use? · none
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · browser
√ What format do you want your config file to be in? · JSON
Successfully created .eslintrc.json file in F:\webcoding\template\project\project_react

F:\webcoding\template\project\project_react>
```

生成された`.eslintrc.json`は下記になります。
```json:.eslintrc.json
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": "eslint:recommended",
    "overrides": [
    ],
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "rules": {
    }
}
```

※補足
質問7：どのスタイルガイドに従いますか？（矢印キーで選択）
（? Which style guide do you want to follow? (Use arrow keys)）

1.Airbnb: https://github.com/airbnb/javascript
2.Standard: https://github.com/standard/standard
3.Google: https://github.com/google/eslint-config-google

についてですが、ChatGPT先生に教えてもらいました。
>Airbnb
Airbnbのスタイルガイドは、JavaScript、React、CSSなどの様々な技術についてのスタイルガイドが用意されています。JavaScriptのスタイルガイドでは、次のような特徴があります。
インデントにはスペースを使用する（タブを使用しない）。
シングルクオートを使用する。
セミコロンを必ず使用する。
== ではなく === を使用する。
ブロックの開始括弧は、同じ行に置く。

>Standard
Standardのスタイルガイドは、JavaScriptのスタイルガイドにフォーカスしています。Standardのスタイルガイドでは、次のような特徴があります。
インデントにはスペースを使用する（タブを使用しない）。
シングルクオートを使用する。
セミコロンを省略する。
== ではなく === を使用する。
ブロックの開始括弧は、同じ行に置く。

>Google
Googleのスタイルガイドは、JavaScript、HTML、CSS、JSONなどの様々な技術についてのスタイルガイドが用意されています。JavaScriptのスタイルガイドでは、次のような特徴があります。
インデントにはスペースを使用する（タブを使用しない）。
ダブルクオートを使用する。
セミコロンを必ず使用する。
== ではなく === を使用する。
ブロックの開始括弧は、別の行に置く。
以上が、Airbnb、Standard、Googleのスタイルガイドの特徴です。それぞれに違いがあるため、チームでの共通のスタイルガイドの採用が推奨されます。

設定ファイルの作成ができたので、ESLintを実行してみます。
実行するときは、`npx eslint ファイルパス`で行います。
今回は、昔作成したアコーディオンメニューのJSファイルで試してみます。
エラーが出るように、波括弧（｛｝）を片方わざと削除しておいてから実行します。
```console
npx eslint dist/accordion.js
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/1fb751e7-7e6c-68ab-36c4-a3ada0559127.png)
エラーが出てくれましたね。
では波括弧をもとに戻して再度実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/c2a973cb-4fba-46bc-1d6b-f2bfc0604dc9.png)
なにもメッセージは表示されませんでした。
エラーがないときはこのように表示されるのですね。

細かいルールも設定できるので、お好みに合わせて調整してください。
自分は素人なので、ここまでとします。

## React使用を想定して設定ファイルをインストールしてみる
設定ファイルの`.eslintrc.json`を削除して、もう一度設定ファイルの作成を一から行うことにします。
前回の回答と違う部分はこちらになります。

質問3：プロジェクトではどのフレームワークを使用していますか？（矢印キーで選択）
（? Which framework does your project use? (Use arrow keys)）

1.React 
2.Vue.js 
3.いずれもなし

私は、1を選択しました。

すると、最後の回答後に前回とは違う質問が表示されました。
`eslint-plugin-react@latest`についての質問です。
`eslint-plugin-react` は Reactライブラリに特化した追加ルールを提供しているそうです。

質問1：今すぐインストールしますか？（<y>キーか<n>キーで選択）
（? Would you like to install them now? (y/N)）

私は、Yesを選択しました。

質問2：どのパッケージマネージャーを使用しますか？（矢印キーで選択）
（? Which package manager do you want to use? (Use arrow keys)）

1.npm
2.yarn
3.pnpm

私は、1を選択しました。

最終的な回答結果は下記になります。
```console
F:\webcoding\template\project\project_react>npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
√ How would you like to use ESLint? · problems    
√ What type of modules does your project use? · esm
√ Which framework does your project use? · react
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · browser
√ What format do you want your config file to be in? · JSON
The config that you've selected requires the following dependencies:

eslint-plugin-react@latest
√ Would you like to install them now? · No / Yes
√ Which package manager do you want to use? · npm
Installing eslint-plugin-react@latest
```

生成された`.eslintrc.json`はこちらになります。
```json:.eslintrc.json
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended"
    ],
    "overrides": [
    ],
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
    }
}
```

Reactに関しては下記のリンクが参考になるかも。
[ESlintの導入・使い方](https://almonta2021blog.com/eslint%E3%81%AE%E5%B0%8E%E5%85%A5/)

ではReactのjsxファイルで実行してみたいと思います。
下記のように記述することで、jsxディレクトリ下の`.jsx`ファイル全てをチェックしてくれます。

```console
npx eslint ./src/jsx/**/*.jsx
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/e76302f7-f270-7af1-82a6-07edfc9622c8.png)
実行しましたが、エラーがでました。
ChatGPT先生によると、
>このメッセージは、npx eslint コマンドを実行した際に表示された警告メッセージです。この警告は、eslint-plugin-react プラグインが React コードを解析する際に、React のバージョンが指定されていないために発生しています。
React のバージョンを指定しないと、eslint-plugin-react は、プロジェクト内で使用されている React のバージョンに関する警告やエラーを検出できません。このため、React のバージョンを指定することが推奨されています。
この警告メッセージには、eslint-plugin-react の設定方法に関するリンクが示されています。リンク先のページで、React のバージョンを指定する方法が説明されています。設定を行うことで、この警告メッセージを解消することができます。

とのことなので、React のバージョンを指定します。
`package.json`を確認したところ、`"react": "^18.2.0",`とあったので、これと同じバージョンを`.eslintrc.json`に追加します。
```json:.eslintrc.json
{
  "settings": {
    "react": {
      "version": "18.2.0"
    }
  }
}
```

最終的に下記になりました。
```json:.eslintrc.json
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended"
    ],
    "overrides": [
    ],
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
    },
    "settings": {
        "react": {
            "version": "18.2.0"
        }
    }
}
```

では実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/f1088616-a705-bee4-af8a-c62d7dd9511b.png)
特にメッセージが表示されないということは、エラーがなかったということですね。
ではわざとエラーを出してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/b64668d7-f1f0-c772-f092-412dd10e6d5c.png)
きちんとエラーを検出してくれました。

### ReactのHooksルールを有効にする
`eslint-plugin-react-hooks`プラグインを入れて、ReactのHooksルールを有効にします。
説明は下記のChatGPT先生より
>eslint-plugin-react-hooksは、ReactのHooksルールを有効にするためのプラグインです。このプラグインを使用しない場合、React Hooksルールは検出されず、警告やエラーは表示されません。eslint-plugin-react-hooksをインストールし、設定ファイルにプラグインを追加することで、Hooksルールを有効にすることができます。

下記を入力してインストールします。
```console
npm i -D eslint-plugin-react-hooks
```

次に、`.eslintrc.json`ファイルに記述を追加し、最終的にこうなりました。

```json:.eslintrc.json
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended"
    ],
    "overrides": [
    ],
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "react",
        "react-hooks"
    ],
    "rules": {
    },
    "settings": {
        "react": {
            "version": "18.2.0"
        }
    }
}

```
これでOKのはずです。

## ショートカット作成
毎回、
```console
npx eslint ./src/jsx/**/*.jsx
```
のように入力するのは手間なので。簡単にしたいと思います。
`package.json`の`scripts`に下記を追加しました。
```json:package.json
"eslint": "eslint ./src/jsx/**/*.jsx"
```
結果、全体としてはこうなりました。

```json:package.json
{
  "name": "project_react",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "eslint": "eslint ./src/jsx/**/*.jsx",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.21.4",
    "@babel/preset-env": "^7.21.4",
    "@babel/preset-react": "^7.18.6",
    "autoprefixer": "^10.4.14",
    "babel-loader": "^9.1.2",
    "browser-sync": "^2.29.1",
    "eslint": "^8.38.0",
    "eslint-plugin-react": "^7.32.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "gulp": "^4.0.2",
    "gulp-htmlhint": "^4.0.2",
    "gulp-imagemin": "^8.0.0",
    "gulp-postcss": "^9.0.1",
    "gulp-sass": "^5.1.0",
    "postcss-reporter": "^7.0.5",
    "sass": "^1.61.0",
    "stylelint": "^15.4.0",
    "stylelint-config-recommended": "^11.0.0",
    "stylelint-config-recommended-scss": "^10.0.0",
    "stylelint-config-standard": "^32.0.0",
    "stylelint-scss": "^4.6.0",
    "webpack": "^5.78.0",
    "webpack-cli": "^5.0.1",
    "webpack-stream": "^7.0.0"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}
```

これで、
```console
npx eslint
```
のようにファイルパスを記述する手間を省くことができるようになりました。


### Webpackと組み合わせる
私は現時点では、JS関係はWebpack側で管理という方向で考えているので、gulpではなくWebpack側でESLintが行えるようにしていきたと思います。

まず、ESLintをWebpackで扱えるようにするものを2つ入れます。
`eslint-loader`と`eslint-webpack-plugin`です。
この2つの説明をChatGPT先生にお願いしました。
>babel-eslintは、ESLintでBabelを使って変換されたコードを正しく解析するためのプラグインです。通常、Babelで変換されたコードは、ESLintのデフォルトのパーサーであるEspreeで解析することができないため、babel-eslintが必要になります。

>eslint-webpack-pluginは、WebpackでESLintを実行するためのプラグインです。Webpackビルド中に自動的にESLintを実行して、検出された問題を出力できます。このプラグインを使用すると、開発者が手動でESLintを実行する必要がなくなり、常に最新のコードを監視して問題を検出できます。

「つまり、WebpackでESLintを実行するためにeslint-webpack-pluginが必要で、eslint-webpack-pluginでESLintの解析を行うためにbabel-eslintも必要になるということであってますか？」
と質問しました。

>そうです、WebpackでESLintを実行する場合、eslint-webpack-pluginプラグインを使用することが一般的です。そして、このプラグインは、ESLintの解析にbabel-eslintパーサーを使用することができます。そのため、babel-eslintも必要になります。ただし、ESLintのパーサーとしてデフォルトで使用されるespreeでも問題なく動作します。

ということらしいので、下記を入力してインストールします。

```console
npm i -D eslint-loader eslint-webpack-plugin
```

`eslint-loader`インストール時にエラーがでました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/e6796bf3-4d71-7cf3-6b7d-2d30e048a1fe.png)
ChatGPT先生によると、
>このエラーは、eslint-loaderパッケージが、使用しているeslintのバージョンと、eslint-loaderパッケージが依存するeslintのバージョンの間に競合が生じていることを示しています。エラーメッセージにあるように、eslint-loaderパッケージが必要とするeslintのバージョンは、6.0.0以上7.0.0未満であり、現在のプロジェクトのルートにインストールされているeslintのバージョンは、8.38.0です。
エラーを解決するには、いくつかのオプションがあります。
プロジェクトのルートにインストールされているeslintパッケージを6.0.0以上7.0.0未満にダウングレードします。
eslint-loaderパッケージをアンインストールしてから、--forceオプションを使用して再度インストールします。
--legacy-peer-depsオプションを使用して、競合を解決するために誤った依存関係の解決を受け入れますが、このオプションを使用することはお勧めできません。
一般的には、1つ目のオプションが最も望ましい解決策です。

んー……ダウングレードはあんまし好きじゃないし、問題を先延ばしにしてみるみたいで嫌だなぁ…。
ということで、`eslint-loader`無しでいこうかなという考えになりました、無くても一応動くみたいですので。

`eslint-webpack-plugin`だけインストールしたら、`webpack.config.mjs`に追記します。
```javascript:webpack.config.mjs
import ESLintPlugin from 'eslint-webpack-plugin'; // eslint-webpack-pluginをインポートして、ESLintを実行できるようにしている。

plugins: [
  new ESLintPlugin({
    extensions: ['.js', '.jsx', '.ts', '.tsx'], // Lintをかける拡張子を指定
    exclude: '/node_modules/', // Lintをかけないディレクトリを指定
  }),
],
```

出来上がった全体がこちらになります。

```javascript:webpack.config.mjs
import path from 'path'; // Node.jsのpathモジュールをインポートして、path.resolve()メソッドを使用できるようにしている。
import ESLintPlugin from 'eslint-webpack-plugin'; // eslint-webpack-pluginをインポートして、ESLintを実行できるようにしている。

export default {
  mode: "development", // 開発モード（"development"）で動作するように設定（ソースマップ有効でJSファイルが出力される、本番環境では"production"に設定すると最適化された状態で出力される）
  entry: `./src/jsx/index.jsx`, // エントリーポイント（メインとなる処理を行うJavaScriptファイル）の指定
  module: {
    rules: [ // モジュールに対するルールを定義する
      {
        test: /\.(js|jsx|ts|tsx)$/, // test = loaderを使う特定の拡張子を指定、今回は複数の拡張子に対応できるようにしてみた
        exclude: '/node_modules/', // Babelをかけないディレクトリを指定
        use: [ // use = testで指定した拡張子にloaderを使いwebpackが読み込めるようにする
          {
            loader: "babel-loader", // Babelを使ってJSXなどの新JS文法を旧JS文法に変換する

            // babel-loader のオプションを指定する
            options: {
              presets: [
                "@babel/preset-env",// ES5に変換
                "@babel/react" // ReactのJSXを解釈
              ]
            }
          }
        ]
      }
    ]
  },
  target: ["web", "es5"], // ES5(IE11等)向けの指定（webpack 5以上で必要）
  output: { // ファイルの出力設定
    path: path.resolve("./dist"), //  出力ファイルのディレクトリ名
    filename: "main.js", // 出力ファイル名
  },
  resolve: { // モジュールを解決するためのオプション
    extensions: [".js", ".jsx", ".ts", ".tsx"]  // importやrequireで指定する際に、拡張子を省略できるようにする
  },
  plugins: [
    new ESLintPlugin({
      extensions: ['.js', '.jsx', '.ts', '.tsx'], // Lintをかける拡張子を指定
      exclude: '/node_modules/', // Lintをかけないディレクトリを指定
    }),
  ],
};
```

これでwebpackを実行すると…
```console
npx webpack 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/14cb6ed6-67cd-fd82-ea0c-f1d8fb3b7821.png)
上手くいったようです。
試しに、わざとエラーをだしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/3841ad07-6bd7-7815-1978-841a336645c9.png)
たくさんのメッセージが表示されました。
しかしここまでESLintが無くても表示されていた部分です。
メッセージの最後に、ESLintによって追加されたエラー文がありました、下記の画像になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310435/c4081066-e236-410b-bc61-74aaa456e2c0.png)

どうやらきちんとESLintは機能してくれてるようですね。
この後にGulp経由でWebpackを呼び出しも試したところ、同じ動作を行ってくれました。



# 感想
予想以上に手こずってかなりの長文になってしまいました。
途中ぐだぐだしてるところも多いので、将来的に理解をもっと深めたら書き直してみたいなと思います。
以上です。

次回：[【初心者】Gulpの監視タスク中にエラー発生してもタスク継続 & 通知 メモ【備忘録】](https://qiita.com/miyaayim_study/items/c616d138510308f36056)


# 参考リンク

- HTML構文チェック
[gulp.jsで便利なタスクを作ってみよう【デバッグ編】](https://liginc.co.jp/250164)
[gulp-htmlhintでHTMLのバリデーションを行う](https://cly7796.net/blog/css/html-validation-with-gulp-htmlhint/)
[Gulp4でHTML / SASS / JavaScriptのLintを自動化](https://qiita.com/hibikikudo/items/adeefff7f6307cb88d54)
[【HTML】HTMLHintで構文チェックを事始める](https://www.i-ryo.com/entry/2020/02/06/061443)

- CSS構文チェック
[【CSS】StyleLintで構文チェックを事始める](https://www.i-ryo.com/entry/2020/02/05/055952)
[stylelintを使ってCSSプロパティのソートと整形を自動化する](https://oshin.tokyo/entry/2020-stylelint)
[stylelint による スタイリング宗教の統一](https://qiita.com/yuzuru_xa/items/a93a7db2a2465be4cf3a)
[stylelintおすすめルール・プラグイン](https://qiita.com/FumiyaShibusawa/items/fdeb7632177643cd42e1)
[GulpでCSSを整える（プレフィックス・文法チェック・自動整形）](https://designsupply-web.com/media/programming/2078/)
[gulpで監視しているscssファイルにstylelintを適用してcssの構文エラーも出るようにしたい！](https://qiita.com/yoshi_atu_090/items/0b98662b8d2050b2cac6)
[ここがすごいぞ！ stylelint！](https://qiita.com/terrierscript/items/ff4f6972c988afbec3a8)
[CSSのLintをstylelintにする](https://qiita.com/makotot/items/c266ed11ada1423cb96e)

- JS構文チェック
[【JS】ESLintで構文チェックを事始める](https://www.i-ryo.com/entry/2020/01/22/233920)
[ESLint 最初の一歩](https://qiita.com/mysticatea/items/f523dab04a25f617c87d)
[【JavaScriptの応用】構文チェックツール -ESLint](https://tcd-theme.com/2021/12/javascript-eslint.html)
[ESLintのセットアップ方法](https://qiita.com/uhooi/items/f22b53b6e39228fc4826)
[ESlintの導入・使い方](https://almonta2021blog.com/eslint%E3%81%AE%E5%B0%8E%E5%85%A5/)
[【ESLint】インストール&設定の手順と、実行結果の見方](https://saki-htr.hatenablog.com/entry/2021/08/26/145418)
[ESLint の使い方](https://lazesoftware.com/ja/blog/230105/)