JavaScript
vue.js
スタイルガイド
ESLint
eslint-plugin-vue
Vue.jsDay 5

Vue.jsスタイルガイドとeslint-plugin-vue検証ルールのマッピング

この記事は Vue.js Advent Calendar 2018 5日目の記事です。
気まぐれに覗いたら空いてたのでいただきました。

去年のAdvent Calendar@mysticateaさんの記事「eslint-plugin-vue を作っている話」を見て、すごいなeslint-plugin-vue!と思って使い始め、ついでにいくつかPRしてたらeslint-plugin-vueのコラボレーターになりました:raised_hands:
なのでeslint-plugin-vueネタで記事書こうと思います。

この記事について

記事の内容

eslint-plugin-vueにはVue.jsの公式のスタイルガイドを守るためのLintルール(静的検証ルール)がいくつか存在しています。
つまりeslint-plugin-vueを使えば自動的にスタイルガイドのいくつかの項目を守れるわけです。

しかし、どれがそのLintルールなの?というのをスタイルガイドから探そうとすると結構辛いので、
今回はそれをまとめてみようと思います。

(Qiitaだしスタイルガイドは日本語:flag_jp:のスタイルガイド使います。
 この記事には出てこないですが、英語のスタイルガイドはこちらです。)

こんな使い方できるかも

eslint-plugin-vueスタイルガイド全ての項目をサポートできているわけではありません。
しかし、一見しても何がサポートされていないのかわからないので、
無駄に人力で、"dataが関数で定義されているか見直す" なんてことをしてしまうかもしれません。

この記事で、スタイルガイドのどの項目が自動(eslint-plugin-vue)でチェックされないかわかれば、レビューで必要なチェックは何なのか?を考える材料になるかもしれません。というかなったらいいな。

調査時点のバージョン

eslint-plugin-vue@5.0.0
スタイルガイド 最終更新日: 2018年10月15日

スタイルガイドの各項目と各Lintルール

スタイルガイドの各項目をベースに、その項目についてをチェックできるeslint-plugin-vueのルールを書いていきます。
(ここにあるLintルールがeslint-plugin-vueのルールの全量ではありません。念のため。)

eslint-plugin-vueに対応するルールが存在しないものは、できる限りissueやプルリクエストのリンクを書いておきます。
(実装できそうなのがあればプルリクエストくれたら嬉しいです。)

スタイルガイドの各項目も抜粋なので詳細はリンク先を見てください。

優先度 A ルール: 必須 (エラー防止)

次のeslintの設定でeslint-plugin-vueに含まれる「優先度 A」関連のルールを全て有効にできます。

{
  "extends": "plugin:vue/essential"
}

複数単語コンポーネント名

ルートの App コンポーネントを除き、コンポーネント名は常に複数単語とするべきです。

(早速であれですが、)現在1Lintルールは存在しません。
issueが開かれています。
:exclamation:Rule proposal: `multi-word-component-names`

コンポーネントのデータ

コンポーネントの data は関数でなければなりません。

対応するLintルール::white_check_mark: vue/no-shared-component-data

プロパティの定義

プロパティの定義はできる限り詳細とするべきです。

間接的にLintルールでチェックできます。

対応するLintルール:

(そもそも無効なpropsの記述もチェックできますがスタイルガイドとは関係無いので今回は書きません)

キー付き v-for

常に v-for に対しては key を使用してください。

対応するLintルール::white_check_mark: vue/require-v-for-key

v-for と一緒に v-if を使うのを避ける

v-for と同じ要素に v-if を使わないでください。

対応するLintルール::white_check_mark: vue/no-use-v-if-with-v-for

コンポーネントスタイルのスコープ

アプリケーションにとって、トップレベルの App コンポーネントとレイアウトコンポーネント内のスタイルはグローバルかもしれませんが、他のすべてのコンポーネントは常にスコープされているべきです。

現在1Lintルールは存在しません。
scoped属性についてはissueがいましたが現時点1ではいろいろ問題があるようでcloseされています。
:grey_exclamation:Rule proposal: `require-scoped-style-tag`

プライベートなプロパティ名

プラグインやミックスイン、その他におけるプライベートなカスタムプロパティには常に $_ プレフィックスを使用してください。さらに、他の著者によるコードとの衝突を避けるため、名前付きのスコープを含めてください (例 $_yourPluginName_ )、。

現在1Lintルールは存在しません。
issueが開かれています。
:exclamation:Rule proposal: `private-property-names`

優先度B のルール: 強く推奨 (読みやすさの向上)

次のeslintの設定でeslint-plugin-vueに含まれる「優先度 A・B」関連のルールを全て有効にできます。

{
  "extends": "plugin:vue/strongly-recommended"
}

コンポーネントのファイル

ファイルを結合してくれるビルドシステムがあるときは必ず、各コンポーネントはそれぞれ別のファイルに書くべきです。

現在1Lintルールは存在しません。
PRが開かれています。
:arrow_upper_left:New: Add `vue/one-component-per-file` rule

単一ファイルコンポーネントのファイル名の形式

単一ファイルコンポーネント のファイル名は、すべてパスカルケース (PascalCase) にするか、すべてケバブケース (kebab-case) にするべきです。

現在1Lintルールは存在しません。
issueがいましたがcloseされています。
:grey_exclamation:Rule proposal: `component-filename-casing`

基底コンポーネントの名前

アプリケーション特有のスタイルやルールを適用する基底コンポーネント (またはプレゼンテーションコンポーネント: Presentation Components、ダムコンポーネント: Dumb Components、純粋コンポーネント: Pure Components とも) は、すべて BaseAppV などの固有のプレフィックスで始まるべきです。

現在1Lintルールは存在しません。
(自動的に判断するのは難しい気がしますね。いいアイディアがあればissueをお願いします)

単一インスタンスのコンポーネント名

常に 1 つのアクティブなインスタンスしか持たないコンポーネントは、1 つしか存在しえないことを示すために The というプレフィックスで始めるべきです。

現在1Lintルールは存在しません。
(いいアイディアがあればissueをお願いします)

密結合コンポーネントの名前

親コンポーネントと密結合した子コンポーネントには、親コンポーネントの名前をプレフィックスとして含むべきです。

現在1Lintルールは存在しません。
(いいアイディアがあればissueをお願いします)

コンポーネント名における単語の順番

コンポーネント名は、最高レベルの(たいていは最も一般的な)単語から始めて、説明的な修飾語で終わるべきです。

現在1Lintルールは存在しません。
(いいアイディアがあればissueをお願いします)

自己終了形式のコンポーネント

中身を持たないコンポーネントは、 単一ファイルコンポーネント 、文字列テンプレート、および JSX の中では自己終了形式で書くべきです。ただし、DOM テンプレート内ではそうしてはいけません。

対応するLintルール::white_check_mark: vue/html-self-closing

テンプレート内でのコンポーネント名の形式

ほとんどのプロジェクトでは、コンポーネント名は 単一ファイルコンポーネント と文字列テンプレートの中では常にパスカルケース(PascalCase)になるべきです。 - しかし、 DOM テンプレートの中ではケバブケース(kebab-case)です。

対応するLintルール::white_check_mark: vue/component-name-in-template-casing

JS/JSX 内でのコンポーネント名の形式

JS/JSX 内でのコンポーネント名はつねにパスカルケース(PascalCase)にするべきです。ただし、 Vue.component で登録したグローバルコンポーネントしか使わないような単純なアプリケーションでは、ケバブケース(kebab-case)を含む文字列になるかもしれません。

現在1部分的にLintルールでチェックできます。

対応するLintルール:

これを拡張するPRが開かれています。
:arrow_upper_left:New: Add `component-definition-name-casing` rule. #256

完全な単語によるコンポーネント名

コンポーネント名には、略語よりも完全な単語を使うべきです。

現在1Lintルールは存在しません。
(いいアイディアがあればissueをお願いします)

プロパティ名の型式

プロパティ名は、定義の時は常にキャメルケース(camelCase)にするべきですが、テンプレートや JSX ではケバブケース(kebab-case)にするべきです。

対応するLintルール:

複数の属性をもつ要素

複数の属性をもつ要素は、1 行に 1 要素ずつ、複数の行にわたって書くべきです。

対応するLintルール::white_check_mark: vue/max-attributes-per-line

テンプレート内での単純な式

複雑な式は算出プロパティかメソッドにリファクタリングして、コンポーネントのテンプレートには単純な式だけを含むようにするべきです。

現在1Lintルールは存在しません。
issueが開かれています。
:exclamation:Rule proposal: `simple-expressions-in-templates`

単純な算出プロパティ

複雑な算出プロパティは、できる限りたくさんの単純なプロパティに分割するべきです。

現在1Lintルールは存在しません。
issueが開かれています。
:exclamation:Rule proposal: `simple-computed-properties`

引用符付きの属性値

空ではない HTML 属性の値は常に引用符(シングルコーテーションかダブルコーテーション、 JS の中で使われていない方)でくくるべきです。

対応するLintルール::white_check_mark: vue/html-quotes

ディレクティブの短縮記法

ディレクティブの短縮記法 (v-bind: に対する :v-on: に対する @)は、常に使うか、まったく使わないかのどちらかにするべきです。

対応するLintルール:

優先度 C のルール: 推奨 (任意の選択肢と認知上のオーバーヘッドの最小化)

次のeslintの設定でeslint-plugin-vueに含まれる「優先度 A・B・C」関連のルールを全て有効にできます。

{
  "extends": "plugin:vue/recommended"
}

コンポーネント/インスタンス オプション順序

コンポーネント/インスタンス オプションは、一貫した順序になるべきです。

対応するLintルール::white_check_mark: vue/order-in-components

要素の属性の順序

要素の属性 (コンポーネントを含む) は、一貫した順序になるべきです。

対応するLintルール::white_check_mark: vue/attributes-order

コンポーネント/インスタンス オプションの空行

特にオプションがスクロールなしでは画面に収まらなくなった場合、複数行に渡るプロバティの間に空行を追加してみてください。

現在1Lintルールは存在しません。

単一ファイルコンポーネントのトップレベルの属性の順序

単一ファイルコンポーネントでは、 <script><template><style> タグを一貫した順序にするべきです、 <style> は最後です、それは他の2つのうち少なくとも1つが常に必要だからです。

現在1Lintルールは存在しません。
issueが開かれています。
:exclamation:Rule proposal: `vue/component-tags-order`

優先度 D のルール: 使用注意(潜在的に危険なパターン)

key を使わない v-if/v-else-if/v-else

それらが同じ種類の要素の場合、通常は v-if + v-else と一緒に key を使用するのが最善です(例: どちらも <div> 要素).

現在1Lintルールは存在しません。
issueが開かれています。
:exclamation:Rule proposal: `v-if-else-key`

scoped 付きの要素セレクタ

scoped 付きの要素セレクタは避けるべきです。

現在1Lintルールは存在しません。
(CSSの話なのでESLintプラグインでは実現されない可能性が高いです。)

暗黙的な親子間のやりとり

親子間のやりとりは、this.$parent や変化するプロパティよりも、プロパティとイベントが推奨されます。

現在1Lintルールは存在しません。
issueが開かれています。
:exclamation:Rule proposal: `no-implicit-parent-communication`

Flux 以外の状態管理

グローバル状態管理には、this.$root やグローバルイベントバスよりも、Vuex が推奨されます

現在1Lintルールは存在しません。


あとがき

これまとめてて、vue/html-quotesのカテゴリが間違ってる(優先度B扱いじゃなかった)ことに気がついてv5.0.0リリース前に修正できたのはよかった。
まあ僕はほとんどのルールを(vue/script-indent以外)ONで使ってるのでカテゴリなんてどうでもいいんですけど。

Vueのアドベントカレンダー人気な様子ですぐ埋まってましたね。覗いたら1枠解放されてたのでワーイ\(^o^)/と思って取っちゃいましたが、おかげで会社のアドベントカレンダーのネタがなくなった。。。


  1. 現在 2018/12/5 (eslint-plugin-vue @ v5.0.0)