Vue CLIコマンドを利用してVueのプロジェクトを作成する際のManually select featuresのlinter / formatterの選択時に何を選択したらいいかわからないので一番上の選択肢を迷いもせず選択している人を対象にVue.js環境におけるEslintとPrettierについて説明を行っています。EslintとPrettierについてはVue.jsに限定された話ではなくJavaScriptを使いこなす上で必須な知識なのでESLintが理解できていない人にお勧めの内容になっています。本文書を読んでもESLintやPrettierのルールをすべて理解することができませんがESLint、Prettierが何をしてくれる機能なのかは動作確認を行いながら完全に理解することができます。

Vue CLIでlinter / formatterを選択する

Vue CLIのvue createコマンドを実行した後にManually select featuresを選択すると以下のようにlinter / formatterを選択する必要があります。linter / formatterには4つの選択肢がありますがそれぞれを選択することでどのような機能の違いがあるか見ていきます。


? Pick a linter / formatter config: (Use arrow keys)
❯ ESLint with error prevention only 
  ESLint + Airbnb config 
  ESLint + Standard config 
  ESLint + Prettier 

ESLintは何をしてくれるのか

すべての選択肢の中にESLintという単語が入っているのでESLintが何をしてくれるのか確認していきましょう。

ESLintは構文の記述間違いやあらかじめ決められたルールに沿ってコードが記述されているかをチェックするツールです。ESLintを利用することで潜在的なバグを見つけることができます。言葉での説明よりも実際に動作確認を行うことでESLintが何をしてくるのか簡単に理解することができます。

ここではlinter / formatterの選択で一番上にあるESLint with error prevention onlyを選択した環境で動作確認しています。

vue createコマンドでVue.jsのプロジェクトを作成後npm run serveを実行してください。


 % npm run serve
//略
  App running at:
  - Local:   http://localhost:8080/ 
  - Network: http://192.168.2.181:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

ブラウザを開いてhttp://localhost:8080/にアクセスするとVue.jsのデフォルトのページが表示されます。

デフォルトのページ
デフォルトのページ

次にvue createコマンドで作成したプロジェクトルートフォルダにあるsrc/App.vueファイルを開いて下記のように更新します。templateタグの中にh1タグを追加しコンテンツをHello Eslintとしています。


<template>
  <h1>Hello Eslint</h1>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
//略
}
</style>

App.vueファイルを保存するとnpm run serveコマンドを実行していたコンソールにエラーが表示されるだけではなくブラウザ上にも同じ内容のエラーが表示されます。エラーメッセージを見ると”Hello World”コンポーネントは登録されいるが使われていないと表示されコンパイルに失敗しています。後ほど説明しますがメッセージの後にはvue/no-unused-componentsという文字列も確認できます。


 ERROR  Failed to compile with 1 error                 15:38:42

 error  in ./src/App.vue

Module Error (from ./node_modules/eslint-loader/index.js):

/Users/mac/Desktop/eslint_error/src/App.vue
  11:5  error  The "HelloWorld" component has been registered but not used  vue/no-unused-components

インポートしたコンポーネントを利用しなくてもJavaScriptのコードが動かないわけではありませんが未使用のコンポーネントをコード上に記述しておくことで今後バグにつながる可能性もあるのでコンパイルに失敗するようにESLintで設定が行われています。

ESLintで設定が行われているためこのエラーが発生しないように設定変更することが可能です。

Vue CLIを使ったプロジェクトのインストール中に各選択した機能の設定情報をpackage.jsonファイルに記述するか個別の設定ファイルとして作成するか選択する項目があります。


? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files 
  In package.json 

その選択項目でIn dedicated config filesを選択していればプロジェクトのルートフォルダに.eslintrc.jsファイルが作成されているので.eslintrc.jsを使って先ほどエラーが表示されないように追加設定を行います。In package.jsonを選択した場合はpackage.jsonファイルの中で同様の設定を行うことができます。

.eslintrc.jsファイルでのルール設定

ESLintではルールによってエラーにするか警告にするかoffにするかエラーレベルを個別に設定することが可能です。今回のコンポーネントの未使用エラーはエラー時のメッセージに表示されたvue/unused-componentsというルールによりエラーが発生しています。エラーが発生しないように.eslintrc.jsのrulesを使って設定を行います。

.eslintrc.jsを開いて、rulesの中にvue/no-unused-componentsを追加しその値をoffにします。offはエラーレベルを表しツールをoffにすることを意味します。


module.exports = {
  root: true,
  env: {
    node: true
  },
  'extends': [
    'plugin:vue/vue3-essential',
    'eslint:recommended'
  ],
  parserOptions: {
    parser: 'babel-eslint'
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'vue/no-unused-components': 'off' //追加
  }
}

設定後に再度npm run serveコマンドを実行するとvue/unused-componentsのルールがoffになったためコンパイルは成功し、ブラウザ上にはHello EsLintが表示されます。

ルールの設定値であるエラーレベルには”off”の他にも”warn”(警告)と”error”(エラー)があります。errorに設定するとコンパイルに失敗します。warnに設定すると警告メッセージは表示されますがブラウザ上にはHello Eslintが表示されます。

エラーレベルは数値でも表すことができ、offは0, warnは1, errorは2となります。
fukidashi

このようにESLintは決められたルールに沿ってコードが記述されているのかをチェックを行ってくれます。

ESLintのルールについて

先ほどエラーのルール名はvue/unused-componentsという名前でした。このルールはeslint-plugin-vueの中に含まれているVue特有のルールです。package.jsonファイルを確認するとeslint-plugin-vueを確認することができます。


{
  "name": "eslint_error",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^3.0.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0" //ここ
  }
}

どのようなルールがあるのかもeslint-plugin-vueのドキュメントサイトで確認することができます。

eslint-plugin-vueのルール
eslint-plugin-vueのルール

vue/unused-componentsのルールは、登録されているコンポーネントがテンプレートの中で使われていないのは許可しないと記述されています。

vue/unused-componentsルールの説明
vue/unused-componentsルールの説明

たくさんのルールが存在しますが、個別のルールを一つ一つ設定するのではなく複数のルールをまとめてグループとして適用しています。その設定は.eslintrc.jsファイルのextendsで確認することができます。’plugin:vue/vue3-essential’がeslint-plugin-vueに関する設定でどのようなルールが含まれているかもeslint-plugin-vueのドキュメントから確認することができます。


'extends': [
  'plugin:vue/vue3-essential',
  'eslint:recommended'
],

下記のルールを確認することで’plugin:vue/vue3-essential’の場合にどのようなコードでエラーが発生するのかがわかります。

vue3-essential
vue3-essential

他にはどのようなエラーがあるのか気になるかと思います。その他のルールとしてVueの勉強しはじめによく見かけるvue/require-v-for-keyがあります。これはv-forで要素にv-bind:keyの設定を忘れた時に発生するエラーに関するルールです。

vue以外にどのようなルールがあるのかも確認しておきます。.eslintrc.jsファイルの中のextendsで’plugin:vue/vue3-essential’の下に記述されている’eslint:recommended’がESLintの本来のルールです。


'extends': [
  'plugin:vue/vue3-essential',
  'eslint:recommended'
],

‘eslint:recommended’にどのようなルールがあるのかはESLintのドキュメントから確認することができます。

ドキュメントページのチェックのついたルールがeslint:recommendedを利用した場合に適用されるESLintのルールです。

ESLintのeslint:recommended
ESLintのeslint:recommended

実際にESLintのルールでもエラーが発生するようにApp.vueファイルに未使用の変数を定義してみます。変数nameは定義しただけで利用されていません。


import HelloWorld from './components/HelloWorld.vue'
const name = "John Doe"; //追加

export default {
  name: 'App',
  components: {
    HelloWorld
  },
}

この場合はESLintのルールである”no-unused-vars”によりエラーが発生してコンパイルに失敗します。ESLintのルールの場合はvueの時のように先頭に”vue/”がないのでどちらのルールでエラーが発生しているのか判断することができます。


   7:7   error    'name' is assigned a value but never used                    no-unused-vars

ESLintのフォーマット機能

ESLintはフォーマッター(コード整形)としても利用することができるのでその設定方法についても確認しておきます。フォーマッターを使うことでインデントを設定したりクオテーション、セミコロンありなしをプロジェクトファイル全体で統一することができます。

ここではインデントの設定について確認していきます。App.vueファイルを見ると現在のインデントは2です。


<template>
  <h1>Hello Eslint</h1>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  },
}
</script>
//略

ESLintのルールを利用してインデントを2から4に変更します。フォーマッターについても.eslintrc.jsファイルに記述することができます。設定は配列で行い、1つ目の要素にエラーレベル、2つ目の要素に設定値を設定します。


rules: {
  'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  'vue/no-unused-components': 'off',
  'indent': ['error', 4]
}

変更後、npm run serveコマンドを実行するとコンパイルエラーが発生します。9-12行目はインデントが2しかないためにエラーになっています。


 ERROR  Failed to compile with 1 error

 error  in ./src/App.vue

Module Error (from ./node_modules/eslint-loader/index.js):

/Users/mac/Desktop/eslint_error/src/App.vue
   9:1  error  Expected indentation of 4 spaces but found 2  indent
  10:1  error  Expected indentation of 4 spaces but found 2  indent
  11:1  error  Expected indentation of 8 spaces but found 4  indent
  12:1  error  Expected indentation of 4 spaces but found 2  indent

npm run lintで自動修正

エラーを修正するためにエディターを使ってインデントを2から4に変更することができますが、package.jsonファイルのscriptsに記述されているlintを実行することでインデントを2から4に自動修正してくれます。


"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "lint": "vue-cli-service lint" //ここ
},

実際にnpm run lintコマンドを実行するとApp.vueファイルだけでなくjsファイルはすべてインデントが4になります。自動修正されたファイル名が表示されます。


 % npm run lint

> eslint_error@0.1.0 lint
> vue-cli-service lint

The following files have been auto-fixed:

  src/App.vue
  src/components/HelloWorld.vue
  .eslintrc.js
  babel.config.js

 DONE  All lint errors auto-fixed.

しかしApp.vueファイルを見るとscriptタグ部分はインデントが4になっていますがtemplateタグの中身のHTMLのインデントは変更されていません。


<template>
  <h1>Hello Eslint</h1>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
    name: 'App',
    components: {
        HelloWorld
    },
}
</script>

templateタグのインデントを変更するためにvue/html-indentのルールを別に設定する必要があります。


rules: {
  'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  'vue/no-unused-components': 'off',
  "indent": ["error", 4],
  "vue/html-indent": ["error", 4]
}

vue/html-indentを設定後に再度npm run lintを実行するとtemplateのタグの中もインデントが4になっていることが確認できます。


<template>
    <h1>Hello Eslint</h1>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
    name: 'App',
    components: {
        HelloWorld
    },
}
</script>

インデントだけではなく各行に必ずコロンを必ずつけたい場合、シングルクオテーションに統一したい場合は以下のようにルールを追加することができます。semiのルールはalwaysとneverがあり、neverを設定するとセミコロンをつけるとエラーになります。


rules: {
  'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  'vue/no-unused-components': 'off',
  'quotes': [1, 'single'],
  'semi': ['error', 'always'],
  'indent': ['error', 2],
  'vue/html-indent': ['error', 2]
}

npm run lintで自動修正させない

npm run lintを実行するとルールに従ってコードの整形が自動で行われることが確認できました。自動修正を行わず問題の箇所だけ確認したい場合はpackage.jsonファイルに–no-fixを設定します。これで自動修正を行わずメッセージのみが表示されます。


"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "lint": "vue-cli-service lint --no-fix"
},

ここまでの説明でESLintが何をしてくれるかとどのようなルールが存在してどのように適用するのかが理解できたかと思います。

ESLint + Prettierを選択した場合

ここまでは”ESLint with error prevention only”を選択した環境で動作確認を行ってきました。次はESLint + Prettierを選択した時の動作を確認していきます。

package.jsonファイル見ると”ESLint with error prevention only”と比較して”@vue/eslint-config-prettier”, “eslint-plugin-prettier”, “prettier”の3つのパッケージが追加させれています。すべて名前からもわかる通りprettierに関連するパッケージです。


"devDependencies": {
  "@vue/cli-plugin-babel": "~4.5.0",
  "@vue/cli-plugin-eslint": "~4.5.0",
  "@vue/cli-service": "~4.5.0",
  "@vue/compiler-sfc": "^3.0.0",
  "@vue/eslint-config-prettier": "^6.0.0",
  "babel-eslint": "^10.1.0",
  "eslint": "^6.7.2",
  "eslint-plugin-prettier": "^3.3.1",
  "eslint-plugin-vue": "^7.0.0",
  "prettier": "^2.2.1"
}

ESLintの設定ファイルである.eslintrcを確認するとextendsに”@vue/prettier”が追加されています。


extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],

Prettierはフォーマッターでコードの整形のみを行ってくれるツールです。デフォルトのままでも自動修正が行われるのか確認するためにApp.vueファイルを以下のように更新します。HelloWorldタグのインデントを4に変更し、importのコードの後ろにある”;”コロンを削除し、APPのダブルクオテーションをシングルクオテーションに変更しています。


<template>
  <img alt="Vue logo" src="./assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js App" />
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue"

export default {
  name:'App',
  components: {
    HelloWorld,
  },
};
</script>
//略

npm run lintコマンドを実行します。


 % npm run lint

> eslint_prettier@0.1.0 lint
> vue-cli-service lint

The following files have been auto-fixed:

  src/App.vue

 DONE  All lint errors auto-fixed.

実行するとデフォルトで設定された整形ルールに従って自動修正が行われます。ESLintのフォーマッター機能でもコード整形を行うことができましたがPrettierでも同様にコード整形が行われることが確認できます。Prettierではデフォルトから何も変更しなくてもデフォルトのルールに沿って自動修正が行われます。


<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Welcome to Your Vue.js App" />
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
};
</script>

.prettierrcファイルの作成

デフォルトではインデントは2, 行末にはセミコロンが入り、ダブルクオテーションが設定されました。デフォルト値を変更するためにVueプロジェクトのインストールフォルダに.prettierrcファイルを作成します。.prettierrcファイルを使ってデフォルト値を変更します。インデントを4, セミコロンをなし、シングルクオテーションに設定します。


{
  "tabWidth": 4,
  "semi": false,
  "singleQuote": true
}

npm run lintファイルを実行すると複数のファイルで自動修正が行われます。


 % npm run lint

> eslint_prettier@0.1.0 lint
> vue-cli-service lint

The following files have been auto-fixed:

  src/App.vue
  src/components/HelloWorld.vue
  src/main.js
  .eslintrc.js
  babel.config.js

 DONE  All lint errors auto-fixed.

App.vueファイルを確認すると.prettirrcで設定した内容に修正されています。ファイル全体でインデントが4になっていることが確認できます。scriptタグの中ではコードの後ろのセミコロンがなくなっていますが、styleタグの中ではセミコロンはそのままの状態になっていることも確認できます。


<template>
    <img alt="Vue logo" src="./assets/logo.png" />
    <HelloWorld msg="Welcome to Your Vue.js App" />
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
    name: 'App',
    components: {
        HelloWorld,
    },
}
</script>

<style>
#app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
}
</style>

.prettirrcファイルを削除して再度実行するとprettierのデフォルト値が設定された元の状態に自動修正されます。

.eslintrc.jsファイルでの設定

.eslintrc.jsファイルのrulesにprettierの設定を追加することも可能です。npm run lintを実行すると.eslintrc.jsファイルに追加したルールの設定で自動修正が行われます。


rules: {
  "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
  "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
  "prettier/prettier": [
    "error",
    {
      tabWidth: 2,
      singleQuote: false,
      semi: true,
    },
  ],
},

ESLint + airbnb or standardを選択した場合

“ESLint with error prevention only”と”ESLint Prettier”ではどちらもextendsのESLintの設定ではeslint:recommendedが設定されていました。eslint:reccomendedも利用することができますがその他にもstandardやairbnbといったスタイルガイドを利用することができます。

これまでにいくつかのルールの説明をしてきましたが自分でカスタマイズして1つ1つルールを設定することも可能です。しかしルールの数は膨大なのですべてのルールを理解することは非常に困難です。そのため自分でカスタマイズするのではなくベストプラクティスのスタイルガイドを利用することが推奨されています。主にstandardとairbnbのスタイルガイドが世界中が利用されておりルールはコミュニティによって管理されているので安心して利用することができます。

もしこれまでコードのスタイルを気にせずairbnbなどのスタイルガイドを利用したことがない人であれば記述したコードの各所でエラーが発生する可能性があります。airbnbなどを使ってもらいどのようなルールにひっかかるのか確認してみてください。ESLintのルールもさらに深まるはずです。

主なルールの違い

2つのデザインスタイルの違いはたくさんありますが入門者でもわかりやすい大きな違いがいくつかあります。

インデントは2、クオテーションはシングルクオテーションと共通する設定もありますが、standardでは行の最後にセミコロンがつかないのに対してairbnbではセミコロンがつくといった違いがあります。

.eslintrc.jsファイルの違い

.eslintrc.jsファイルのextendsの違いは下記の通りです。


//standardの場合
extends: [
  'plugin:vue/vue3-essential',
  '@vue/standard'
],

//airbnbの場合
extends: [
  'plugin:vue/vue3-essential',
  '@vue/airbnb',
],

パッケージの違い

インストールされてるパッケージもstandardとairbnbでは異なります。


//standardの場合
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-standard": "^5.1.2",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-import": "^2.20.2",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.0",
    "eslint-plugin-vue": "^7.0.0"
  }

//airbnbの場合
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-airbnb": "^5.0.2",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-import": "^2.20.2",
    "eslint-plugin-vue": "^7.0.0"
  }

本文書を読んだだけではVue CLIの実行時のlinter / formatterの選択でどれを選択すればいいの決めるは難しいと思いますがESLintの基本的な理解はできたと思うので各linter / formaterを使って実際にコードを記述しプロジェクトにあったコードスタイルを決めてください。