LaravelにESLintとPrettierを導入する時にやったことの全て

## はじめに
この記事では`Laravel5.8`に`ESLint`と`Prettier`を導入します。

`Laravel`のMVCモデルでは、Viewの部分は `*.blade.php`ファイルによって書くことが一般的です。
しかし最近では、JavaScriptの描画技術の幅やページの描画スピードの速さなどを理由として、**bladeは完全に捨ててVue.jsにフロントエンドの全てを任せる**構成をとるプロジェクトが多いと感じています。

今回、ESLintを導入する対象となった`Laravel5.8`のプロジェクトは僕がPMをしているプロジェクトです。

このプロジェクトでも、`Laravel`のbladeはほとんど使用しておらず、画面描画は `resourses/js/`に置かれている`Vue.js`によって行っています。

今回の記事の対象者は、**LaravelでVue.jsを使っているor使いたい方全て**です。

## なぜESLintとPrettierを使うべきなのか
**「なぜ`ESLint`と`Prettier`を併用して使うべきなのか」**ということについては、`Laravel`に限らず、広く議論されていることですので、ここでは触れません。
この議論の結論を言えば、「`ESLint`だけ導入」あるいは「`Prettier`だけ導入」というのは諸事情があって微妙だからどちらも使おうね、ということです。

以下では`ESLint`と`Prettier`を導入するにあたり、**僕が感じている利点**について触れておきます。

### 集団開発でコードフォーマットが統一されていないのはかなりしんどい
「何を綺麗と感じるか」は人それぞれです。
しかし、一方で個々の感性が異なるために、しばしば地獄をみることになります。

- 「あれ？末尾のセミコロンは前全部消したはずなのにまたAさんが足し直してる、、、」
- 「キャメル？パスカル？命名規則が混在している、、、」
- 「シングルクォーテーションとダブルクォーテーションが混在している、、、」

これを十人十色などと言ってはいけません。**阿鼻叫喚**です。
コードのフォーマットや変数の命名規則が理由で議論が始まったりプルリクエストが通らないとしたら、せっかく`Laravel`を使っているのにあなたの開発スピードは早いとは言えなくなりませんか？

- フォーマットや変数の命名規則は開発者間で統一する
- 開発者ごとのフォーマット調整による余計な差分はなくし、**コードレビューの可読性をあげる**

この重要性を理解しましょう。コードレビューは常にロジックにのみ集中するべきです。

### 1人で開発するからといってフォーマットが煩雑なのは許されない
僕の価値観では、コードというものは**「誰が見ても美しくあるべき」**です。あなたがフォーマッターを使わずに書いたコードは、他人が見ても必ず美しいと思えるでしょうか。また、開発者が感じる「美しさ」は誰が保証してくれるのでしょうか？

「ソースコードは1人で扱うから」とは言っても、いつかもう1人のメンバーが加わる場合もあります。
そう言った際に無駄なコストを払わないように、1人だとしてもフォーマットには基準を設けて整形しておくのがマナーだと僕は考えています。

`ESlint`と`Prettier`は非常に優秀なフォーマッターなので、**「ESLintとPrettierが共通のルールによって整形してくれたのだから信じよう」**と開発者は思うのです。


## いつESLintとPrettierを導入するのか

上記で「`ESLint`と`Prettier`を導入しなさい」と布教したのですが、僕も最近になってようやくこれらのフォーマッターを導入したのです。

実は、`ESLint`と`Prettier`を導入するまでにGitHubでのcommitは500を超えており、そこそこの規模のプロジェクトになっていました。ですから、かなりの数の `*.js` `*.vue`ファイルが存在していました。

### 導入パターン

`ESLint`を全てのファイルにかける（＝現存する`*.js`ファイルや`*.vue`ファイルを一気に整形する）場合、**非常にコンフリクトが発生しやすくなります。**

対象の全てのファイルの全体に対して改行ポイントやスペース、コンマや命名規則、変数宣言や比較演算子などありとあらゆるコードを修正することを想像すれば「コンフリクトが発生しやすい」というのは火を見るより明らかです。そして、そのコンフリクトは激しくなりがちであることも理解できるでしょう。

`ESLint`を導入するタイミングはおおよそ次のパターンに分類できます。

1. 今からLaravelをセットアップするあなた
**→後悔はさせないので、いますぐ導入しましょう。最もEasyです。このタイミングで気づいたあなたは偉い！**

2. すでにそこそこの規模になっているあなた
**→プロジェクト全体で大きな変更がないタイミングを伺いましょう。そこそこの努力と忍耐が必要です。**

3. かなりの規模になっていて集団開発が盛んになっているあなた
**→この時点で何かしらのフォーマッターを入れていないのはまずい状況ですが、導入のタイミングも難しいです。大量のコンフリクトを覚悟して慎重にタイミングを見計らいます。開発者全体で打ち合わせなどをする必要があるかもしれません。**

僕は2番に該当していたつもりですが、それでも一気に`ESLint`を全てのファイルにかけて本当に血の海を見ました。全ファイルが血を流して倒れました。

それでもなんとかコンフリクトが少なくなるようなタイミングを見計って行えば、**ギリギリ耐えます。** 
あなたのフォーマッターへの想いだけを信じてください。

## ESLintとPrettierを導入する
やっと本題です。しかしやることはそんなに多くありません。

今回は、**プロジェクトの途中から`ESLint`と`Prettier`を導入**します。（上記での2or3番を想定しています。1番でももちろん全く問題なし！）
ここから先は`Laravel`がどうこうというより、**`ESLint`と`Prettier`自体をよく理解している**ことが重要です。

### パッケージをインストールする
今回必要なパッケージは以下になります。たくさんあります。
以下のパッケージは開発時にしか必要ありませんので `--save-dev`オプションをつけてインストールしてあげます。

```
$ npm install babel-eslint eslint eslint-config-prettier eslint-config-standard eslint-friendly-formatter eslint-loader eslint-plugin-html eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-node eslint-plugin-prettier eslint-plugin-promise eslint-plugin-standard eslint-plugin-vue laravel-mix-eslint --save-dev
```

### ESLintの設定ファイルを作成する
続いて、`.eslintrc.js`ファイルを新しく作成します。
このファイルでは**ESLintとPrettierの整形ルールを定めます**。

```
$ cd yourLaravelProject
$ vim .eslintrc.js
```

``` ..eslintrc.js
module.exports = {
  root: true,
  parserOptions: {
    parser: 'babel-eslint',
  },
  env: {
    browser: true,
  },
  extends: [
    'standard',
    'plugin:vue/recommended',
    'plugin:prettier/recommended',
    'prettier/vue',
  ],
  plugins: [
    'vue',
    'prettier', // prettierをESLintと併用します
  ],
  rules: {
    // ESLintが使用する整形ルールのうち、自分がoffにしたいルールなどを指定する
    'vue/no-v-html': 'off', // v-htmlの使用について
    'vue/prop-name-casing': 'off', // Propsの変数の命名規則について
    'no-console': 'off', // console.log()の使用について
    'no-unused-vars': 'off', // 使われていない変数について
    'camelcase': 'off', // camelcaseについて

    // この先はPrettierのルール
    "prettier/prettier": [ 
      "error",
      {
        printWidth: 120,
        tabWidth: 2,
        useTabs: false,
        singleQuote: true,
        trailingComma: 'all',
        bracketSpacing: true,
        arrowParens: 'avoid',
        semi: false,
      },
    ]
  }
}
```

この設定ファイルは結構厳しめにルールを設けているつもりです。
そもそもせっかくコードフォーマッターを導入するのにルールを緩くしておく必要はないからです。

しかし、もしプロジェクトの途中での導入に際してあまりルールを厳しく入れたくないという場合は、`extends:[]`の部分を見直すと良いと思います。

このあたりは下記サイトが参考になりました。
[（参考）Vue.jsスタイルガイドとeslint-plugin-vue検証ルールのマッピング](https://qiita.com/ota-meshi/items/85bf17494c8ea0be05d7)

また`Prettier`のルールもあなたの好みです。
`Prettier`のルールは公式ドキュメントを参考に変更すると良さそうです。
[（参考）Options - Prettier](https://prettier.io/docs/en/options.html)


### ファイル変更時にESLintを使用する
`webpack`が上記の整形ルールを使用してファイル変更を`watch`してくれるように`webpack.mix.js`を編集します。

```webpack.mix.js 
const mix = require('laravel-mix')

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

// ESLintに関する設定（この部分を丸ごと追記するイメージです）
if (!mix.inProduction()) { // 本番環境ではESLintは使用しない
  mix.webpackConfig({
    module: {
      rules: [
        {
          enforce: 'pre',
          exclude: /node_modules/,
          loader: 'eslint-loader',
          test: /\.(js|vue)?$/,
        },
      ],
    },
  })
}

// watchするファイルやポート番号などに関する設定（今回の内容とは関係ありません）
mix
  .js('resources/js/app.js', 'public/js')
  .sass('resources/sass/app.scss', 'public/css')
  .browserSync({ // browserSyncの設定
    files: ['resources/js/**/*', 'resources/sass/**/*', 'resources/views/**/*', 'public/css/**/*'],
    port: 3000,
    ui: {
      port: 3001,
    },
    proxy: 'localhost:8000', //php artisan serveで立ち上げた8000番をProxyする
  })

// 本番環境ではバージョン付けによるキャッシュ対策を施す（今回の内容とは関係ありません）
if (mix.inProduction()) {
  mix.version()
}
```

これで基本的なセットアップは全て終了です。

```
$ npm run watch
```

を唱えることによっていつも通り開発を開始しましょう。コンソールでESLintとPrettierが大量のエラーを吐いてくれるはずです。

### 実際に動作を確認する
あなたのコンソールを見てください。
例えば次のようになっている場合、

```
/Users/yourName/Laravel/resources/js/pages/A/B.js
350:1  error  Delete `····`
       prettier/prettier
```

これは`Prettier`が怒っている様子です。

このエラーが指し示すところは、
**「`/js/pages/A/`にあるファイル`B.js`の350行目の1列目から無駄な空白があるから消せ」**
ということです。

これらのエラーは地道に解消しても良いですが、あなたの見ているエラーの量を見てください。地獄ですよね。

でも安心してください、自動でこれらのエラーをほとんど解消してくれる`ESLint`のコマンドがあります。

エラーを吐いているファイル名とそのディレクトリを確認して、コンソールで

```
// ESLintとPrettierの両方を実行する
$ eslint resources/js/pages/*/*.js --fix
```

を実行しましょう。
ファイル名は`resources/js/pages/*/*.js`のようにワイルドカードを使用して指定できます。
これによって`resources/js/pages/*/*.js` に該当するファイルのエラーが自動で解消されていきます。

`eslint ファイル名 --fix`コマンドによって**ESLintとPrettierの両方が実行されることに注意してください**。
これはすでに上記で導入した `eslint-config-prettier`の恩恵を受けています。
ESLintとPrettierの併用に関する詳しい説明は以下の記事などがわかりやすいと思います。
[（参考）ESLint - Prettier連携のやり方と仕組み](https://qiita.com/ikngtty/items/4df2e13d2fa1c4c47528)

これでLaravelの`*.js`ファイルや`*.vue`ファイルに対してESlintとPrettierを導入することができました。

どのようなエラーを吐いているかはあなたのプロジェクト次第です。

コンソールでのエラーを見ながら `.eslintrc.js`ファイルで整形方法を調整しましょう。特定の整形ルールを`off`にすることもできますから、あなたの開発チームメンバーにとって最良の設定を記述し、幸せな開発サイクルを目指しましょう。

## 最後に

この設定を行ったことで、あなたのLaravelの`*.js`ファイルや`*.vue`ファイルは全ての開発者間でフォーマットが統一されました。

今後の展望としては
1. **git commit**のときに**ESLintを自動で強制する**
2. **`*.php`ファイルに対しても**何かしらの`Lint`を施す

本記事ではこれらの設定はオーバーワークになりますので、別記事で紹介しようと思います。

長くなりましたが、ありがとうございました。