- 2020/09/30 eslint-plugin-vue 7.0.0 リリースに伴う追記・編集
eslint-plugin-vueはVue.jsバージョン3.x(いわゆるvue-next)のサポートを始めました。
eslint-plugin-vueバージョン7.0.0以降で利用できます。
インストール or アップデート
npmなどを使用してインストール or アップデートしてください。
npm install -D eslint-plugin-vue@latest
使い方
( 詳細はこちらを参照してください。 https://eslint.vuejs.org/user-guide/ )
ESLint設定
ESLint設定ファイル.eslintrc.*
のextends
に下記の設定を追加します。
( 詳細はこちらを参照してください。 https://eslint.vuejs.org/user-guide/#usage )
.eslintrc.js
の場合:
module.exports = {
extends: [
// ...
// ↓追加
'plugin:vue/vue3-recommended',
// または、
'plugin:vue/vue3-strongly-recommended',
// または
'plugin:vue/vue3-essential',
],
// ...
}
すでに利用していて、extends
にVue.js 2.x用の設定を入れている場合は、Vue.js 3.x用の設定に置き換えてください。
module.exports = {
extends: [
// ...
- 'plugin:vue/recommended',
+ 'plugin:vue/vue3-recommended', // <- 'vue3-'ってつけてください。
],
// ...
}
Vue.js 3.x用に追加されたルールセット
(上でも書きましたが)Vue.js 3.x用に下記のルールセットが利用できるようになりました。
下のルールセットの方が有効になるルールが多いです。
Vue.js 3.x用に追加された検証ルール
詳細はリリースノートを参照してください。
vue/no-deprecated-filter
このルールはフィルターの使用を禁止します。
Vue.js 2.xまで使用できたフィルターですが、Vue.js 3.xでは廃止されます。(詳細はRFC0015を参照してください。)
このルールでVue.js 2.xの癖でうっかりフィルター書いてしまった場合や、Vue.js 3.xに移行する際に書き換えないといけない箇所として、検出できます。
この制限として、逆に<template>
内でビット演算のOR|
もレポートされてしまいますし、そもそもうまく解析できない場合があります。
vue/no-deprecated-v-bind-sync
このルールはv-bind:foo.sync
の.sync
修飾子の使用を禁止します。
そもそも.sync
修飾子が何なのか(何だったのか)はこちらの公式ドキュメントを参照してください。
この構文は、Vue.js 3.xでv-model:foo
のような書き方に置き換えられます。(詳細はRFC0005を参照してください。)
なので、古い書き方は利用できなくなります。このルールは自動修正をサポートしているので、Vue.js 3.xへの移行で利用できると思います。
vue/no-deprecated-v-on-number-modifiers
このルールはv-on
のkeydown
などで使用できていた、数字の修飾子によるキー指定を禁止します。
Vue.js 2.xまで使用できたキーコードを利用したキー修飾子ですが、Vue.js 3.xでは廃止されます。(詳細はRFC0014を参照してください。)
Vue.js 3.xに移行する際に書き換えないといけない箇所として検出できます。
ただし、9
などの一桁の数字は、Vue.js 2.xではTabコードのリスナーを目的として利用していたかもしれませんが、Vue.js 3.xでは数字キーの9
のリスナーかもしれないのでこのルールで検出することはできません。
<!-- ✓ GOOD -->
<input v-on:keydown.enter="submit">
<!-- ✗ BAD -->
<input v-on:keydown.13="submit">
vue/no-deprecated-data-object-declaration
このルールはdata
オプションをオブジェクトで定義している箇所を検出します。
Vue.js 2.xでも通常のコンポーネントではdata
オプションはfunctionで定義することが推奨されていましたが、Vue.js 3.xでは全てのdata
オプションでfunctionでの定義しか受け入れなくなります。(Vue.js 2.xで利用できていたObjectによる定義は廃止されます)
(詳細はRFC0019を参照してください。)
/* ✗ BAD */
createApp({
data: {
foo: null
}
}).mount('#app')
/* ✓ GOOD */
createApp({
data () {
return {
foo: null
}
}
}).mount('#app')
<script>
/* ✗ BAD */
export default {
data: {
foo: null
}
}
/* ✓ GOOD */
export default {
data () {
return {
foo: null
}
}
}
</script>
vue/no-deprecated-events-api
このルールは$on
、$off
、$once
メソッドを使用している箇所を検出します。
これらのメソッドはVue.js 3.xで廃止されます。(詳細はRFC0020を参照してください。)
vue/no-deprecated-inline-template
このルールはインラインテンプレートの使用を禁止します。
そもそも僕はこのインラインテンプレート機能知らなかったですし、誰かSFCで使ってる人いるの?という感想しかないですが、Vue.js 3.xで廃止されます。(詳細はRFC0016を参照してください。)
vue/no-deprecated-functional-template
このルールは<template functional>
の使用を禁止します。
functional テンプレートはVue.js 3.xで廃止されます。(詳細はRFC0007を参照してください。)
vue/no-deprecated-html-element-is
このルールはHTML要素へのis
属性の使用を禁止します。
is
属性は普通、<component>
タグで使うと思うのですが、HTMLタグでも使用できていました。
しかしVue.js 3.xでは<component>
タグでのみ使用でき、HTMLタグでは使用できなくなります。(詳細はRFC0027を参照してください。)
vue/no-deprecated-vue-config-keycodes
このルールはVue.config.keyCodes
を使用している箇所を検出します。
vue/no-deprecated-v-on-number-modifiersルールの説明でも書いたように、Vue.js 3.xではキーコードを利用したキー修飾子は廃止されます。
これに伴って、キーコードを文字列修飾子として使うためのコンフィグがありましたが、こちらもVue.js 3.xで廃止されます。(詳細はRFC0014を参照してください。)
vue/no-deprecated-dollar-listeners-api
このルールは$listeners
を使用している箇所を検出します。
$listeners
はv-on
で登録された全てのイベントにアクセスできるAPIですが、Vue.js 3.xで廃止されます。(詳細はRFC0031を参照してください。)
vue/no-deprecated-v-on-native-modifier
このルールはv-on
の.native
修飾子を使用している箇所を検出します。
v-on
の.native
はコンポーネントのルート要素にネイティブイベントを登録できるAPIです。
ですが、Vue.js 3.xで廃止されます。(詳細はRFC0031を参照してください。)
vue/no-deprecated-dollar-scopedslots-api
このルールは$scopedSlots
を使用している箇所を検出します。
$scopedSlots
はVue.js 3.xで廃止され、同等機能が$slots
に実装されます。(詳細はRFC0006を参照してください。)
vue/no-deprecated-destroyed-lifecycle
このルールはdestroyed
,beforeDestroy
のライフサイクルフックを検出します。
Vue.js 3.xではunmounted
,beforeUnmount
を使用しましょう。
vue/no-deprecated-props-default-this
このルールはprops
のdefault
関数内でthis
を使用している箇所を検出します。
props
オプションは、デフォルト値を生成する関数を定義できます。このデフォルト値を生成する関数内では、this
を使用して、自身のインスタンスにアクセスできていましたが、Vue.js 3.xではthis
が使用できなくなりました。
次のコードはこのルールで報告されます。
<script>
export default {
props: {
foo: String,
bar: {
type: String,
default () {
// ✗ BAD
return this.foo;
}
}
}
}
</script>
このコードは次のように変更する必要があります。
<script>
export default {
props: {
foo: String,
bar: {
type: String,
default (props) {
// ✓ GOOD
return props.foo;
}
}
}
}
</script>
詳細は 移行ガイド - Props Default Function this
Accessを参照してください。
vue/no-lifecycle-after-await
RFC0013のComposition APIのonMounted
などのライフサイクルフックは非同期でコールしても登録されない制限があるそうです。
そのため明らかに非同期であるとわかるawait
の後のライフサイクルフックをエラーとして検出します。
async setup() {
/* ✓ GOOD */
onMounted(() => { /* ... */ })
await doSomething()
/* ✗ BAD */
onMounted(() => { /* ... */ })
}
vue/no-watch-after-await
RFC0013のComposition APIのwatch
、watchEffect
は非同期でコールして登録するとインスタンスと一緒に破棄されなかったりと問題がある利用方法があります。
そのため明らかに非同期であるとわかるawait
の後のwatch
、watchEffect
で、かつ、自力で破棄を管理しない利用をエラーとして検出します。
async setup() {
/* ✓ GOOD */
watchEffect(() => { /* ... */ })
await doSomething()
/* ✗ BAD */
watchEffect(() => { /* ... */ })
/* ✓ GOOD */
// 自力で破棄までするならOK
const stopHandle = watchEffect(() => { /* ... */ })
}
// ...
// 破棄
stopHandle()
vue/no-ref-as-operand
RFC0013のComposition APIのref
でラップされた値は.value
を経由して値を扱います。TypeScriptを使っていれば概ねエラー検出されるような気もしますが、このルールでもいくつかの間違ったパターンをエラーとして検出します。
const count = ref(0)
const ok = ref(true)
/* ✓ GOOD */
count.value++
count.value + 1
1 + count.value
var msg = ok.value ? 'yes' : 'no'
/* ✗ BAD */
count++
count + 1
1 + count
var msg = ok ? 'yes' : 'no'
vue/no-setup-props-destructure
RFC0013のComposition APIのprops
はsetup
の引数で与えられます。しかし、この値の取り出し方を間違えるとリアクティブに動作しなくなってしまうため、そのパターンをいくつかエラーとして検出します。
常に、propsからメンバーを取り出すように記述すると問題ありません。
/* ✓ GOOD */
setup(props) {
watch(() => {
console.log(props.count)
})
return () => {
return h('div', props.count)
}
}
次のように引数を分割代入にしたりするとリアクティブに動作しません。このルールではこのパターンをエラーとして検出します。
/* ✗ BAD */
setup({ count }) {
watch(() => {
console.log(count) // countの変更は検知されません。
})
return () => {
return h('div', count) // countが変更されても更新されません。
}
}
また次のようにトップレベルで値を取り出して利用する場合もリアクティブに動作しません。このルールではこのパターンもエラーとして検出します。
setup(props) {
/* ✗ BAD */
const { count } = props
watch(() => {
console.log(count) // countの変更は検知されません。
})
return () => {
return h('div', count) // countが変更されても更新されません。
}
}
vue/require-toggle-inside-transition
このルールは<transition>
要素の子要素が(Vue.js 3.x観点で)明らかv-if
等の表示のコントロールをしていない箇所を検出します。
Vue.js 2.xでも利用できそうなルールですが、Vue.js 2.xではVue.js作者の意図していなかった操作による<transition>
を動作させる方法があるようです。
Vue.js 3.xではその意図していなかった方法は利用できなくなります。(詳細はRFC0017を参照してください。)
vue/require-explicit-emits
Vue.js 3.xで追加されるemitsオプション関連のルールです。emitsオプションの詳細はRFC0030を確認してください。
このルールは、コンポーネントが、$emit
や、setup
のcontext.emit
を利用して、イベントをトリガーしているのに、emitsオプションに定義されていないイベント名を報告します。
報告されたエラーはESLintのSuggestions APIを使用して修正候補を提供します。
このルールを使用して、VSCodeで修正候補をポチポチ押して修正していくことで、Vue.js 2.xからの移行作業の助けになるかもしれません。
vue/return-in-emits-validator
Vue.js 3.xで追加されるemitsオプション関連のルールです。
emitsはfunction
を定義してイベントの引数を検証することができます。
このルールでは、イベント引数の検証function
が結果の返り値を返しているかどうかを確認して誤った利用を報告します。
vue/require-slots-as-functions
このルールは$slots
のプロパティを(明らかに)functionとして使用してない箇所を検出します。
$slots.foo
はVue.js 2.xではvnode配列を保持していましたが、Vue.js 3.xではvnode配列を返すfunctionとなります。つまりVue.js 2.xの$scopedSlots
相当の機能がVue.js 3.xでは$slots
に実装されます。(詳細はRFC0006を参照してください。)
このルールを使うと、間違ってVue.js 2.xのノリでvnode配列を返すと思い込んで実装してしまったであろう箇所をいくつか検出することができます。
vue/valid-v-is
このルールはv-is
の間違った使用をしている箇所を検出します。
Vue.js 2.xからis
属性という特別な属性がありますが、ネイティブのHTML要素にこれは使用できなくなりました。(詳細はRFC0027を参照してください。)
よほどのことがない限り使いことはないと思いますが、Vue.js 3.xではv-is
を使用します。
このルールはv-is
の間違った使用を検出します。(valueが無い!とか)
vue/no-v-for-template-key-on-child
このルールは
<template v-for="x in list">
<div :key="x.key"/>
</template>
というように、<template v-for>
のkey
を子要素に配置している箇所を報告します。これは、
<template v-for="x in list" :key="x.key">
<div />
</template>
としてください。
この書き方は、Vue.js 2.xでは不正な記述でしたが、Vue.js 3.xでは推奨されます。(とういうか前者の書き方ではVue.js 3.xコンパイラがエラーを報告します。(vue-next 3.0.0-rc.6時点))
Vue.js 3.xのFragment関連の変更によって、<template v-for>
のkey
を<template>
要素に配置できるようになました。このルールは古い書き方を報告して、新しい書き方を促します。
Vue.js 2.xでは<template>
の子要素が複数ある場合、:key
を使用して最適化したい場合、
<template v-for="x in list">
<div :key="x.key+'_1'"/>
<div :key="x.key+'_2'"/>
<div :key="x.key+'_3'"/>
<div :key="x.key+'_4'"/>
</template>
のように、全ての要素に:key
を書かなければなりませんでしたが、Vue.js 3.xでは
<template v-for="x in list" :key="x.key">
<div />
<div />
<div />
<div />
</template>
で、十分です。(<transition>
目的でkey
を使用している場合はその限りではないかもしれません。)
とてもスッキリしますね!
vue/experimental-script-setup-vars
このルールはエラーを報告しません。
<script setup>
で定義した、props
などの変数(引数)を使用した箇所で、変数が未定義であると警告されるのを防ぐルールです。
具体的にはESLintコアルールno-undefによって、props
変数を使用した箇所で警告になるのを防ぎます。
勘違いされる前にお伝えしておくと、eslint-plugin-vueはまだ
<script setup>
をサポートしていません。#1248で作業を開始しようというお気持ちを見せていますが、全然進めていませんテヘペロ(・ω<)
サポートする作業を手伝ってくれる方は、是非、必要な作業をリストアップしたり、プルリクしてくださいmm
vue/experimental-script-setup-varsルールを使用しない場合、次のソースコードはno-undefルールによって警告されます。
<script setup="props, { emit }">
import { watchEffect } from 'vue'
watchEffect(() => console.log(props.msg)) // "'props' is not defined." のエラー
emit('foo') // "'emit' is not defined." のエラー
</script>
これは、props
とemit
の変数がJavaScript上で定義されていないため、未定義の変数が使用されているとして警告されます。
しかしこれらの変数は<script setup="props, { emit }">
のsetup
部分に定義されており、Vue.jsの構文としては有効な変数です。
vue/experimental-script-setup-varsルールは<script setup="props, { emit }">
を解析し、Hackじみたことをして、ESLintに定義済みの変数であることを伝えます。
おそらく正攻法で対応するにはパーサーを修正(作成)し、@typescript-eslint/parser
のバージョン4と同じように新しいScopeManagerを提供するようにすべきだと思いますが、今後大きく変わるかもしれない実験的機能の対応のために、正直そこまでやっていられないので、vue/experimental-script-setup-varsルールで暫定的に対応しました。なのでこちらのルールも実験的機能として位置付けています。
Vue.js 3.x用に変更された検証ルール
vue/valid-template-root
Vue.js 2.xではテンプレートのトップレベルの要素は一つまででしたが、Vue.js 3.xではこの制限が無くなり、複数要素やテキストノードをルートに設定することができるようです。
このルールは今まで、「トップレベルの要素は一つ」というのをチェックしていましたが、このロジックはvue/no-multiple-template-rootという別のルールに切り出されvue/valid-template-rootではチェックしなくなりました。
vue/valid-v-model
RFC0005とRFC0011でv-model
APIの動作が変更され、引数とカスタム修飾子が受け入れられるようになります。
vue/valid-v-modelではVue.js 2.xまで受け入れられなかった引数とカスタム修飾子をエラーとして報告していましたが、Vue.js 3.xでエラーにならないパターンは別のルールに切り出され、vue/valid-v-modelでは検出しないように変更されました。
vue/no-template-key
<template v-for"..." :key="...">
のような記述は、Vue.js 2.xでは不正でしたが、
vue/no-v-for-template-key-on-childの説明で書いたように、Vue.js 3.xでは<template v-for>
のkey
を<template>
要素に配置できるようになりました。
これに対応するために、このルールは、v-for
を持つ<template>
に配置されたkey
を報告しなくなりました。
ただし、Vue.js 2.xでは不正なので、別のルールでv-for
を持つ<template>
に配置されたkey
をチェックします。
vue/valid-v-for, vue/require-v-for-key
上でも書いたように、Vue.js 3.xでは<template v-for>
のkey
を<template>
要素に配置できるようになりました。
これに対応するために、これらのルールは、<template>
にkey
が配置された場合にエラーを報告しなくなりました。
Vue.js 3.x用に変更されたその他
あとは細かいことなのでリリースノートを参照してください。
最後に
Vue.js 3.x使っていてこんなルールも必要だ!というアイディアがある方
ぜひissueの投稿をお願いします!
あと、どなたか手伝ってくれる方がいればプルリクもお願いします!
なんなら僕のプルリクにレビューコメント書いてくれるだけでも嬉しいです!本当にお願いします!