Eslint-plugin-vue: Supports for Vue.js 3.x

Created on 15 Jan 2020  路  30Comments  路  Source: vuejs/eslint-plugin-vue

In this issue, I will list the Vue.js 3.x changes that need to be supported by eslint-plugin-vue.


  • [x] Support for Fragments. Plans for the Next Iteration of Vue.js

    • [x] #1038 Change vue/valid-template-root to allow multiple root nodes.

    • [x] #1038 Add vue/no-multiple-template-root rule that disallows multiple root nodes (for Vue 2).

  • [x] Removing v-bind's .sync modifier and replacing it with an argument on v-model. RFC0005

    • [x] #1039 Change vue/valid-v-model to allows argument (component only).

    • [x] #1039 Add vue/no-v-model-argument rule that disallows argument (for Vue 2).

    • [x] #1039 Add vue/no-deprecated-v-bind-sync rule that disallows v-bind.sync.

  • [x] Functional API Change. RFC0007

    • [x] #1119 Add vue/no-deprecated-functional-template rule that disallows <template functional>.

  • [x] Global API changes. RFC0009

    • [x] #1073 Add the CallExpression of app.component and app.mixin to utils/index.isVueComponent.

  • [x] v-model API changes RFC0011
  • [ ] Composition API. RFC0013
  • [x] Drop support for using numbers (keyCodes) as v-on modifiers. RFC0014

    • [x] #1079 Add vue/no-deprecated-v-on-number-modifiers rule that disallows numbers as v-on modifiers.

    • [x] #1118 Add vue/no-deprecated-vue-config-keycodes rule that disallows Vue.config.keyCodes.

  • [x] Remove support for filters. RFC0015

    • [x] #1043 Add vue/no-deprecated-filter rule that disallows Vue2 filter.

  • [x] Remove inline-template. RFC0016

    • [x] #1100 Add vue/no-deprecated-inline-template rule that disallow inline-template attributtes.

  • [x] Using <transition> as component's root will no longer trigger transitions when the component is toggled from the outside.. RFC0017
  • [x] Removing object declaration for data RFC0019

    • [x] #1083 Add vue/no-deprecated-data-object-declaration rule

  • [x] Remove $on, $off and $once instance methods RFC0020

    • [x] #1097 Add vue/no-deprecated-events-api rule

  • [x] Custom Elements Interop Improvements RFC0027

    • [x] #1117 Add vue/no-deprecated-html-element-is rule that disallow the is attribute on HTML elements.

  • [ ] "emits" component option RFC0030

    • [ ] Add the setting of the emits property to vue/order-in-components rule.

    • [x] #1124 Add vue/require-explicit-emits rule that requires the emits option to have a name called by $emit().

    • [x] #1129 Add vue/return-in-emits-validator rule enforces that a return statement is present in emits validator.

  • [x] Attribute Fallthrough Updates.RFC0031

    • [x] #1130 Add vue/no-deprecated-v-on-native-modifier rule that disallow .native modifier on v-on.

    • [x] #1133 Add vue/no-deprecated-dollar-listeners-api rule that disallow $listeners.

  • TODO I need to check if any RFCs after RFC0033 are added.

List the changes after #1036 was merged.

  • [x] Add categories for Vue 3

    • [x] essential for Vue 3



      • [x] Add vue/no-deprecated-filter rule.


      • [x] Add vue/no-deprecated-v-bind-sync rule.


      • [x] #1079 Add vue/no-deprecated-v-on-number-modifiers rule.


      • [x] #1083 Add vue/no-deprecated-data-object-declaration rule


      • [x] #1097 Add vue/no-deprecated-events-api rule


      • [x] #1100 Add vue/no-deprecated-inline-template rule


      • [x] #1099 Add vue/require-v-if-inside-transition rule.


      • [x] Add vue/no-ref-as-operand rule.


      • [x] #1068 Add vue/no-watch-after-await rule.


      • [x] Add vue/no-lifecycle-after-await rule.


      • [x] Add vue/no-setup-props-destructure rule.


      • [x] #1061 Add vue/no-deprecated-scope-attribute rule.


      • [x] #1061 Add vue/no-deprecated-slot-attribute rule.


      • [x] #1061 Add vue/no-deprecated-slot-scope-attribute rule.


      • [x] Remove vue/valid-v-bind-sync rule.


      • [x] #1119 Add vue/no-deprecated-functional-template rule.


      • [x] #1117 Add vue/no-deprecated-html-element-is rule.


      • [x] #1118 Add vue/no-deprecated-vue-config-keycodes rule.


      • [x] #1130 Add vue/no-deprecated-v-on-native-modifier rule.


      • [x] #1133 Add vue/no-deprecated-dollar-listeners rule.


      • [x] #1129 Add vue/return-in-emits-validator rule.



    • [x] strongly-recommended for Vue 3

    • [x] recommended for Vue 3

  • [x] Change categories for Vue 2

    • [x] essential for Vue 2



      • [x] Add vue/no-multiple-template-root rule.


      • [x] Add vue/no-v-model-argument rule.


      • [x] Add vue/no-custom-modifiers-on-v-model rule.



    • [x] strongly-recommended for Vue 2

    • [x] recommended for Vue 2


refs

https://medium.com/the-vue-point/plans-for-the-next-iteration-of-vue-js-777ffea6fabf
https://github.com/vuejs/rfcs/pulls?utf8=%E2%9C%93&q=is%3Apr+label%3A3.x+
https://vueschool.io/articles/vuejs-tutorials/exciting-new-features-in-vue-3/
https://vue-composition-api-rfc.netlify.com/

Vue.js 3.x semver-major

Most helpful comment

Some rules I had in mind:

  • no-ref-as-operand:

    Detect cases where a ref is used incorrectly as an operand in binary operations. + is probably the most common case for such errors. For example:

    const count = ref(0)
    
    count++ // error
    count + 1 // error
    1 + count // error
    

    A ref used as the condition in a ternary is probably also an error:

    const ok = ref(true)
    
    const msg = ok ? 'yes' : 'no' // error
    
  • no-watch-after-await & no-lifecycle-after-await:

    In setup(), watch and onXXX lifecycle hooks should be registered synchronously. So their usage should be prohibited in async setup() after await statements:

    async setup() {
      watch(() => { /* ... */ }) // ok
      onMounted(() => { /* ... */ }) // ok
    
      await doSomething()
    
      watch(() => { /* ... */ }) // error
      onMounted(() => { /* ... */ }) // error
    }
    
  • no-setup-props-destructure

    Destructuring the props passed to setup will cause the value to lose reactivity.

    // Do
    setup(props) {
      watch(() => {
        console.log(props.count) // ok
      })
    
      return () => {
        return h('div', props.count) // ok
      }
    }
    
    // Don't
    setup({ count }) { // error
      watch(() => {
        console.log(count) // not going to detect changes
      })
    
      return () => {
        return h('div', count) // not going to update
      }
    }
    

    Also, destructuring in root scope of setup() should error, but ok inside nested callbacks or returned render functions:

    setup(props) {
      const { count } = props // error
    
      watch(() => {
        const { count } = props // ok
        console.log(count)
      })
    
      return () => {
        const { count } = props // ok
        return h('div', count)
      }
    }
    

All 30 comments

/cc @vuejs/docs

I think these changes are also to be addressed in the new style guide.
Any thoughts?

I think a require-v-if-inside-transition rule can be added for RFC0017

Some rules I had in mind:

  • no-ref-as-operand:

    Detect cases where a ref is used incorrectly as an operand in binary operations. + is probably the most common case for such errors. For example:

    const count = ref(0)
    
    count++ // error
    count + 1 // error
    1 + count // error
    

    A ref used as the condition in a ternary is probably also an error:

    const ok = ref(true)
    
    const msg = ok ? 'yes' : 'no' // error
    
  • no-watch-after-await & no-lifecycle-after-await:

    In setup(), watch and onXXX lifecycle hooks should be registered synchronously. So their usage should be prohibited in async setup() after await statements:

    async setup() {
      watch(() => { /* ... */ }) // ok
      onMounted(() => { /* ... */ }) // ok
    
      await doSomething()
    
      watch(() => { /* ... */ }) // error
      onMounted(() => { /* ... */ }) // error
    }
    
  • no-setup-props-destructure

    Destructuring the props passed to setup will cause the value to lose reactivity.

    // Do
    setup(props) {
      watch(() => {
        console.log(props.count) // ok
      })
    
      return () => {
        return h('div', props.count) // ok
      }
    }
    
    // Don't
    setup({ count }) { // error
      watch(() => {
        console.log(count) // not going to detect changes
      })
    
      return () => {
        return h('div', count) // not going to update
      }
    }
    

    Also, destructuring in root scope of setup() should error, but ok inside nested callbacks or returned render functions:

    setup(props) {
      const { count } = props // error
    
      watch(() => {
        const { count } = props // ok
        console.log(count)
      })
    
      return () => {
        const { count } = props // ok
        return h('div', count)
      }
    }
    

@sodatea @yyx990803 Thank you for your comments!

I have added new rules to the list.

@michalsnik @mysticatea Could you comment on this issue if you have any feedback?

Hi! Thanks @ota-meshi @sodatea @yyx990803 for the work done with this plugin.

Will we be adding any rules for when consumers try to access refs in the template through .value? I feel like some people would try to do this, yet based on the RFC docs, Vue internally does this for you.

@codebender828 that's a good one, although a user may very well have an object with .value so we will need the component's type information to be able to warn without false positives.

I have a question about v-model changes. 馃檪
If i understood RFC 0011 right, v-model api will provide also support for custom modifiers.
Adding that feature wouldn't require also some changes to vue/valid-v-model rule?
Ex.:

  • Modify vue/valid-v-model rule to provide support for custom modifiers.
  • Add vue/no-custom-modifiers-on-v-model rule to checks if v-model does not contain custom modifiers (Vue 2 backward compatibility)

Note that custom modifiers are only supported for v-model on custom components. Usage on native <input>, <select> and <textarea> still only support the built-in modifiers.

@przemkow Thank you for your comment. And thank you for your contribution.
I overlooked the custom modifiers change.
I think we need to change the valid-v-model rule and add new rule as you say.

Thank you for the clarification @yyx990803 馃檪
No problem @ota-meshi 馃槈 I hope this contribution will be helpful for the whole community.

I updated previously created PR ( #1039 ) so now it handles both RFC0005 and RFC0011.

@ota-meshi setup function should be added to vue/no-dupe-keys rule as well isn't it?

@przemkow I think it needs to be added as you say.

what about no this in setup function? I really miss that in eslint on vue2

I was thinking of adding something similar to react-hooks/exhaustive-deps that autofix in the return statement all the reactive and ref variables present in the setup function

Hi @chiptus @victorgarciaesgi. Sorry for the late reply.
Could you open a new issue and include sample code?
Because I don't understand your proposed rule correctly.

@ota-meshi Sure!

Consider this code in React

export function Component() {
  const isMobile = useMedia({ maxWidth: '768px' })

  useEffect(() => {
    if (isMobile) {
      console.log(isMobile)
    }
  })
  return <div>{isMobile}</div>
}

With the rule react-hooks/exhaustive-deps, eslint will autofix the code to add missing deps to useEffect, resulting in:

useEffect(() => {
    if (isMobile) {
      console.log(isMobile)
    }
  }, [isMobile])

In Vue3 we can have the same thing but for the return statement in setup
Exemple:

export default defineComponent({
 setup(props, ctx) {
  const search = ref('')
 } 
})

Will become:

export default defineComponent({
 setup(props, ctx) {
  const search = ref('')
  return {search}
 } 
})

I'm not too sure about this. I'm pretty sure we will rather often have state in setup that doesn't have to be exposed to the template.

@LinusBorg Yeah i thought of that too, maybe complete the return statement with only values present in the template?

Does we need about no-this-in-setup rule?

We also need a vue/no-inline-template for RFC0016: Remove inline-template

Hi @sodatea. I haven't used the inline-template and I'm not familiar with it.
Can the inline-template be used in SFC?

Yeah, it can be used in SFC.

I did not know that. Thank you!

Per RFC0007, I think a no-functional-template rule is needed. I'm not sure if it's auto-fixable though.


I just found out that the no-reserved-component-names rule does not throw on Vue's own built-in component names like transition, transition-group, keep-alive and component. As of Vue.js 3.x, teleport should be added to the list too.


Per RFC0027, we need a new rule to restrict the is prop usage to the reserved <component> tag only.

The vue/no-deprecated-v-on-number-modifiers rule needs to also detect the usage of Vue.config.keyCodes and warn the deprecation.

@sodatea Thank you for suggesting the rules and changes.
I will make those changes.

Thanks!

Currently this plugin has finished implementing most of the rules defined in this issue.

Open the remaining issue with another and close this issue.

  • #1134

If you would like to propose a new rule, please open a new issue.

@ota-meshi thanks for the hard work!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

prograhammer picture prograhammer  路  3Comments

soullivaneuh picture soullivaneuh  路  3Comments

lichnow picture lichnow  路  3Comments

chrisvfritz picture chrisvfritz  路  3Comments

KristofMorva picture KristofMorva  路  4Comments