この記事は Vue.js Advent Calendar 2018 5日目の記事です。
気まぐれに覗いたら空いてたのでいただきました。
去年のAdvent Calendarで@mysticateaさんの記事「eslint-plugin-vue を作っている話」を見て、すごいなeslint-plugin-vue!と思って使い始め、ついでにいくつかPRしてたらeslint-plugin-vueのコラボレーターになりました
(追記:現在2019年はメンバーになりました)
なのでeslint-plugin-vueネタで記事書こうと思います。
この記事について
記事の内容
eslint-plugin-vueにはVue.jsの公式のスタイルガイドを守るためのLintルール(静的検証ルール)がいくつか存在しています。
つまりeslint-plugin-vueを使えば自動的にスタイルガイドのいくつかの項目を守れるわけです。
しかし、どれがそのLintルールなの?というのをスタイルガイドから探そうとすると結構辛いので、
今回はそれをまとめてみようと思います。
(Qiitaだしスタイルガイドは日本語のスタイルガイドを使います。
この記事には出てこないですが、英語のスタイルガイドはこちらです。)
こんな使い方できるかも
eslint-plugin-vueがスタイルガイド全ての項目をサポートできているわけではありません。
しかし、一見しても何がサポートされていないのかわからないので、
無駄に人力で、"data
が関数で定義されているか見直す" なんてことをしてしまうかもしれません。
この記事で、スタイルガイドのどの項目が自動(eslint-plugin-vue)でチェックされないかわかれば、レビューで必要なチェックは何なのか?を考える材料になるかもしれません。というかなったらいいな。
調査時点のバージョン
- eslint-plugin-vue@7.0.0-alpha.4 1
- スタイルガイド 最終更新日: 2020年5月16日 2
スタイルガイドの各項目と各Lintルール
スタイルガイドの各項目をベースに、その項目についてをチェックできるeslint-plugin-vueのルールを書いていきます。
(ここにあるLintルールがeslint-plugin-vueのルールの全量ではありません。念のため。)
eslint-plugin-vueに対応するルールが存在しないものは、できる限りissueやプルリクエストのリンクを書いておきます。
(実装できそうなのがあればプルリクエストくれたら嬉しいです。)
スタイルガイドの各項目も抜粋なので詳細はリンク先を見てください。
優先度 A ルール: 必須 (エラー防止)
次のeslintの設定でeslint-plugin-vueに含まれる「優先度 A」関連のルールを全て有効にできます。
{
"extends": "plugin:vue/essential"
}
複数単語コンポーネント名
ルートの App
コンポーネントや、Vue が提供する <transition>
や <component>
のようなビルトインコンポーネントを除き、コンポーネント名は常に複数単語とするべきです。
(早速であれですが、)現在3Lintルールは存在しません。
issueが開かれています。
Rule proposal: `multi-word-component-names`
コンポーネントのデータ
コンポーネントの data
は関数でなければなりません。
対応するLintルール: vue/no-shared-component-data
プロパティの定義
プロパティの定義はできる限り詳細とするべきです。
間接的にLintルールでチェックできます。
対応するLintルール:
- プロパティの型の記述を強制: vue/require-prop-types
-
default
の記述を強制: vue/require-default-prop
(そもそも無効なprops
の記述もチェックできますがスタイルガイドとは関係無いので今回は書きません)
キー付き v-for
常に v-for
に対しては key
を使用してください。
対応するLintルール: vue/require-v-for-key
v-for
と一緒に v-if
を使うのを避ける
v-for
と同じ要素に v-if
を使わないでください。
対応するLintルール: vue/no-use-v-if-with-v-for
コンポーネントスタイルのスコープ
アプリケーションにとって、トップレベルの App
コンポーネントとレイアウトコンポーネント内のスタイルはグローバルかもしれませんが、他のすべてのコンポーネントは常にスコープされているべきです。
現在3Lintルールは存在しません。
scoped属性についてはissueがいましたが現時点3ではいろいろ問題があるようでcloseされています。
Rule proposal: `require-scoped-style-tag`
eslint-plugin-vue-scoped-cssというプラグインを導入すると、vue-scoped-css/require-scopedというルールでチェックできます。
プライベートなプロパティ名
プライベートな関数に外部からアクセスできないようにするために、モジュールスコープを使用してください。それが難しい場合は、プラグインやミックスインなどのプライベートなカスタムプロパティには常に $_
プレフィックスを使用してください。さらに、他の著者によるコードとの衝突を避けるため、名前付きのスコープを含めてください (例 $_yourPluginName_
)。
現在3Lintルールは存在しません。
issueが開かれています。
Rule proposal: `private-property-names`
優先度B のルール: 強く推奨 (読みやすさの向上)
次のeslintの設定でeslint-plugin-vueに含まれる「優先度 A・B」関連のルールを全て有効にできます。
{
"extends": "plugin:vue/strongly-recommended"
}
コンポーネントのファイル
ファイルを結合してくれるビルドシステムがあるときは必ず、各コンポーネントはそれぞれ別のファイルに書くべきです。
対応するLintルール: vue/one-component-per-file
単一ファイルコンポーネントのファイル名の形式
単一ファイルコンポーネント のファイル名は、すべてパスカルケース (PascalCase) にするか、すべてケバブケース (kebab-case) にするべきです。
現在3Lintルールは存在しません。
issueがいましたがcloseされています。
Rule proposal: `component-filename-casing`
ファイル名とコンポーネント名を検証するルールvue/match-component-file-name
のOptionと、nameプロパティの形式ルール(vue/name-property-casing
)を複合的に使うことで、このスタイルルールを守る事ができるかもしれません。
基底コンポーネントの名前
アプリケーション特有のスタイルやルールを適用する基底コンポーネント (またはプレゼンテーションコンポーネント: Presentation Components、ダムコンポーネント: Dumb Components、純粋コンポーネント: Pure Components とも) は、すべて Base
、 App
、V
などの固有のプレフィックスで始まるべきです。
現在3Lintルールは存在しません。
(自動的に判断するのは難しい気がしますね。いいアイディアがあればissueをお願いします)
単一インスタンスのコンポーネント名
常に 1 つのアクティブなインスタンスしか持たないコンポーネントは、1 つしか存在しえないことを示すために The
というプレフィックスで始めるべきです。
現在3Lintルールは存在しません。
(いいアイディアがあればissueをお願いします)
密結合コンポーネントの名前
親コンポーネントと密結合した子コンポーネントには、親コンポーネントの名前をプレフィックスとして含むべきです。
現在3Lintルールは存在しません。
(いいアイディアがあればissueをお願いします)
コンポーネント名における単語の順番
コンポーネント名は、最高レベルの(たいていは最も一般的な)単語から始めて、説明的な修飾語で終わるべきです。
現在3Lintルールは存在しません。
(いいアイディアがあればissueをお願いします)
自己終了形式のコンポーネント
中身を持たないコンポーネントは、 単一ファイルコンポーネント 、文字列テンプレート、および JSX の中では自己終了形式で書くべきです。ただし、DOM テンプレート内ではそうしてはいけません。
対応するLintルール: vue/html-self-closing
テンプレート内でのコンポーネント名の形式
ほとんどのプロジェクトでは、コンポーネント名は 単一ファイルコンポーネント と文字列テンプレートの中では常にパスカルケース(PascalCase)になるべきです。 - しかし、 DOM テンプレートの中ではケバブケース(kebab-case)です。
対応するLintルール: vue/component-name-in-template-casing
(少し問題があるため"plugin:vue/strongly-recommended"
に含まれていません。)
JS/JSX 内でのコンポーネント名の形式
JS/JSX 内でのコンポーネント名はつねにパスカルケース(PascalCase)にするべきです。ただし、 Vue.component
で登録したグローバルコンポーネントしか使わないような単純なアプリケーションでは、ケバブケース(kebab-case)を含む文字列になるかもしれません。
対応するLintルール: vue/component-definition-name-casing
完全な単語によるコンポーネント名
コンポーネント名には、略語よりも完全な単語を使うべきです。
現在3Lintルールは存在しません。
(いいアイディアがあればissueをお願いします)
プロパティ名の型式
プロパティ名は、定義の時は常にキャメルケース(camelCase)にするべきですが、テンプレートや JSX ではケバブケース(kebab-case)にするべきです。
対応するLintルール:
- 定義側: vue/prop-name-casing
- テンプレート側: vue/attribute-hyphenation
複数の属性をもつ要素
複数の属性をもつ要素は、1 行に 1 要素ずつ、複数の行にわたって書くべきです。
対応するLintルール: vue/max-attributes-per-line
テンプレート内での単純な式
複雑な式は算出プロパティかメソッドにリファクタリングして、コンポーネントのテンプレートには単純な式だけを含むようにするべきです。
現在3Lintルールは存在しません。
issueが開かれています。
Rule proposal: `simple-expressions-in-templates`
単純な算出プロパティ
複雑な算出プロパティは、できる限りたくさんの単純なプロパティに分割するべきです。
現在3Lintルールは存在しません。
issueが開かれています。
Rule proposal: `simple-computed-properties`
引用符付きの属性値
空ではない HTML 属性の値は常に引用符(シングルコーテーションかダブルコーテーション、 JS の中で使われていない方)でくくるべきです。
対応するLintルール: vue/html-quotes
ディレクティブの短縮記法
ディレクティブの短縮記法 (v-bind:
に対する :
、 v-on:
に対する @
、 v-slot:
に対する #
)は、常に使うか、まったく使わないかのどちらかにするべきです。
対応するLintルール:
-
v-bind:
: vue/v-bind-style -
v-on:
: vue/v-on-style -
v-slot:
: vue/v-slot-style
優先度 C のルール: 推奨 (任意の選択肢と認知上のオーバーヘッドの最小化)
次のeslintの設定でeslint-plugin-vueに含まれる「優先度 A・B・C」関連のルールを全て有効にできます。
{
"extends": "plugin:vue/recommended"
}
コンポーネント/インスタンス オプション順序
コンポーネント/インスタンス オプションは、一貫した順序になるべきです。
対応するLintルール: vue/order-in-components
要素の属性の順序
要素の属性 (コンポーネントを含む) は、一貫した順序になるべきです。
対応するLintルール: vue/attributes-order
コンポーネント/インスタンス オプションの空行
特にオプションがスクロールなしでは画面に収まらなくなった場合、複数行に渡るプロパティの間に空行を追加してみてください。
現在3Lintルールは存在しません。
単一ファイルコンポーネントのトップレベルの属性の順序
単一ファイルコンポーネントでは、 <script>
、 <template>
、 <style>
タグを一貫した順序にするべきです、 <style>
は最後です、それは他の2つのうち少なくとも1つが常に必要だからです。
対応するLintルール: vue/component-tags-order
優先度 D のルール: 使用注意(潜在的に危険なパターン)
key
を使わない v-if
/v-else-if
/v-else
それらが同じ種類の要素の場合、通常は v-if
+ v-else
と一緒に key
を使用するのが最善です(例: どちらも <div>
要素).
現在3Lintルールは存在しません。
issueが開かれています。
Rule proposal: `v-if-else-key`
scoped
付きの要素セレクタ
scoped 付きの要素セレクタは避けるべきです。
Lintルールは存在しません。
(CSSの話なのでESLintプラグインでは実現されない可能性が高いです。 なので、stylelintを使用して、selector-max-typeルールのオプション0
にしてやるといいと思います。)
暗黙的な親子間のやりとり
親子間のやりとりは、this.$parent
や変化するプロパティよりも、プロパティとイベントが推奨されます。
現在3Lintルールは存在しません。
issueが開かれています。
Rule proposal: `no-implicit-parent-communication`
一部の問題はvue/no-mutating-propsルールで検出できます。
Flux 以外の状態管理
グローバル状態管理には、this.$root
やグローバルイベントバスよりも、Vuex が推奨されます
現在3Lintルールは存在しません。
あとがき
これまとめてて、vue/html-quotesのカテゴリが間違ってる(優先度B扱いじゃなかった)ことに気がついてv5.0.0リリース前に修正できたのはよかった。
まあ僕はほとんどのルールを(vue/script-indent以外)ONで使ってるのでカテゴリなんてどうでもいいんですけど。
Vueのアドベントカレンダー人気な様子ですぐ埋まってましたね。覗いたら1枠解放されてたのでワーイ\(^o^)/と思って取っちゃいましたが、おかげで会社のアドベントカレンダーのネタがなくなった。。。