eslint-plugin-vue

repository·master·Indexed 26 days ago

https://github.com/vuejs/eslint-plugin-vue

The official ESLint plugin for Vue.js, providing essential linting rules to enforce best practices and coding standards in Vue Single File Components (SFCs). It enables ESLint to analyze <template> and <script> blocks within .vue files and Vue-specific code in .js files to identify syntax errors, detect incorrect usage of Vue.js Directives, and ensure compliance with the Vue.js Style Guide.

Tokens
127K
Snippets
391
Records
655
Agent score
87%

What's inside eslint-plugin-vue

  1. Understand eslint-plugin-vue rule categories and indicators

    master

    Rules in eslint-plugin-vue are categorized by their purpose and include specific indicators for how they behave:

    Rule Types

    • Possible Problems (:warning:): Rules relating to potential logic errors in your code.
    • Suggestions (:hammer:): Rules that suggest alternative ways of writing code.
    • Layout & Formatting (:lipstick:): Rules focused on code aesthetics and visual consistency.

    Fixability Indicators

    • Fixable (:wrench:): These rules can be automatically corrected using the ESLint --fix command-line option.
    • Manually Fixable (:bulb:): These rules provide editor suggestions that require manual application by the developer.
  2. Identify custom objects as Vue components

    master

    The plugin automatically detects components via standard expressions (e.g., app.component(), defineComponent(), export default {} in .vue files).

    To apply component-related rules to custom objects in non-standard files, use the // @vue/component comment immediately above the object.

    // @vue/component
    const CustomComponent = {
      name: 'custom-component',
      template: '<div></div>'
    }
  3. Use vue/no-deprecated-v-on-number-modifiers to avoid deprecated keycode modifiers

    master

    This rule disallows the use of deprecated KeyboardEvent.keyCode modifiers on the v-on directive in Vue.js 3.0.0+. Instead of using numeric key codes (e.g., .34), you should use the KeyboardEvent.key value (e.g., .page-down) or the specific key string (e.g., .9).

    This rule is included in the following preset configurations:

    • *.configs["flat/essential"]
    • *.configs["flat/strongly-recommended"]
    • *.configs["flat/recommended"]
    • "plugin:vue/essential"
    • "plugin:vue/strongly-recommended"
    • "plugin:vue/recommended"

    You can use the --fix option via the ESLint command line to automatically fix some of the problems reported by this rule.

    <template>
      <!-- ✓ GOOD -->
      <input v-on:keyup.page-down="onArrowUp">
      <input @keyup.page-down="onArrowUp">
      <input @keyup.9="onArrowUp"> <!-- 9 is KeyboardEvent.key -->
    
    
      <!-- ✗ BAD -->
      <input v-on:keyup.34="onArrowUp">
      <input @keyup.34="onArrowUp">
    </template>
  4. Use the vue/no-unused-refs rule to eliminate unused refs

    master

    The vue/no-unused-refs rule disallows defining ref attributes in <template> that are never accessed via $refs within the component's script. This helps clean up unused template references.

    Limitations: This rule cannot detect if a ref is used in other components (e.g., via mixins or nested access like $refs.x.$refs).

    <template>
      <!-- ✓ GOOD -->
      <input ref="foo" />
    
      <!-- ✗ BAD (`bar` is not used) -->
      <input ref="bar" />
    </template>
    <script>
    export default {
      mounted() {
        this.$refs.foo.value = 'foo'
      }
    }
    </script>
  5. Use the vue/no-lifecycle-after-await rule

    master

    The vue/no-lifecycle-after-await rule disallows registering lifecycle hooks (e.g., onMounted, onUpdated) after an await expression within the setup() function. In the Composition API, lifecycle hooks must be registered synchronously during the initial execution of setup() to ensure Vue can correctly track them.

    <script>
    import { onMounted } from 'vue'
    export default {
      async setup() {
        /* ✓ GOOD: Registered before await */
        onMounted(() => { /* ... */ })
    
        await doSomething()
    
        /* ✗ BAD: Registered after await */
        onMounted(() => { /* ... */ })
      }
    }
    </script>
  6. Use the vue/keyword-spacing rule

    master

    The vue/keyword-spacing rule enforces consistent spacing before and after keywords specifically within <template> expressions. It is designed to mirror the behavior of the @stylistic/keyword-spacing rule but targets Vue template syntax.

    Key features:

    • Auto-fixable: You can use the --fix option via the ESLint command line to automatically correct spacing issues.
    • Dependencies: This rule attempts to use @stylistic/eslint-plugin if installed. If not, it falls back to the ESLint core rule. If neither is available, the rule cannot be used.
  7. Configure Visual Studio Code for Vue linting

    master

    To lint .vue files in Visual Studio Code using the official dbaeumer.vscode-eslint extension, you must explicitly add vue to the eslint.validate setting, as the extension only targets *.js or *.jsx by default.

    If you are using the Vetur extension, disable its template validation to prevent duplicate linting warnings by setting vetur.validation.template to false in your settings.

    {
      "eslint.validate": [
        "javascript",
        "javascriptreact",
        "vue"
      ]
    }
  8. Use the vue/valid-define-options rule

    master

    The vue/valid-define-options rule enforces the correct usage of the defineOptions compiler macro in <script setup>. It ensures that the macro is used according to Vue's requirements for compiler-driven options.

    This rule reports the following invalid patterns:

    • Referencing locally declared variables within defineOptions (it must use a literal object or a variable declared in a separate <script> block).
    • Calling defineOptions multiple times.
    • Calling defineOptions() without any options.
    • Using type arguments (e.g., defineOptions<Type>()).
    • Including props, emits, expose, or slots inside defineOptions (these should use their respective dedicated macros instead).

    This rule is included in the following preset configurations:

    • *.configs["flat/essential"]
    • *.configs["flat/strongly-recommended"]
    • *.configs["flat/recommended"]
    • "plugin:vue/essential"
    • "plugin:vue/strongly-recommended"
    • "plugin:vue/recommended"
    <script setup>
    /* ✓ GOOD: Using a literal object */
    defineOptions({ name: 'foo' })
    </script>
    
    <script>
    /* ✓ GOOD: Using a variable from a separate script block */
    const def = { name: 'foo' }
    </script>
    <script setup>
    /* ✓ GOOD: Variable is defined outside of setup scope */
    defineOptions(def)
    </script>
    
    <script setup>
    /* ✗ BAD: Referencing a locally declared variable */
    const def = { name: 'foo' }
    defineOptions(def)
    </script>
    
    <script setup>
    /* ✗ BAD: Multiple calls */
    defineOptions({ name: 'foo' })
    defineOptions({ inheritAttrs: false })
    </script>
    
    <script setup>
    /* ✗ BAD: No options provided */
    defineOptions()
    </script>
    
    <script setup lang="ts">
    /* ✗ BAD: Using type arguments */
    defineOptions<{ name: 'Foo' }>()
    </script>
    
    <script setup>
    /* ✗ BAD: Including props in defineOptions */
    defineOptions({ props: { msg: String } })
    </script>
  9. Use the vue/no-required-prop-with-default rule

    master

    The vue/no-required-prop-with-default rule enforces that any prop declared with a default value must be optional. Since a default value allows a prop to be skipped during use, marking it as required: true is redundant and logically equivalent to an optional prop. This rule applies to both <script setup> with withDefaults and standard Options API props declarations.

    <script setup lang="ts">
    /* ✓ GOOD */
    const props = withDefaults(
      defineProps<{
        name?: string | number
        age?: number
      }>(),
      {
        name: 'Foo',
      }
    );
    
    /* ✗ BAD */
    const props = withDefaults(
      defineProps<{
        name: string | number
        age?: number
      }>(),
      {
        name: 'Foo',
      }
    );
    </script>
  10. Use the vue/valid-v-for rule

    master

    The vue/valid-v-for rule ensures that v-for directives are used correctly. It prevents common mistakes such as using arguments or modifiers on v-for, omitting the attribute value, or failing to provide a proper :key when using custom components.

    The rule reports errors when:

    • The directive has an argument (e.g., v-for:aaa).
    • The directive has a modifier (e.g., v-for.bbb).
    • The directive lacks an attribute value (e.g., v-for).
    • A custom component uses v-for but lacks a v-bind:key directive.
    • The v-bind:key directive does not use variables defined by the v-for directive (e.g., v-for="x in list" :key="foo").

    Note: This rule does not check for syntax errors (like v-for="foo" instead of alias in expr); use vue/no-parsing-error for those.

    <template>
      <!-- ✓ GOOD -->
      <div v-for="todo in todos"/>
      <MyComponent
        v-for="todo in todos"
        :key="todo.id"
      />
      <div
        v-for="todo in todos"
        :is="MyComponent"
        :key="todo.id"
      />
    
      <!-- ✗ BAD -->
      <div v-for/>
      <div v-for:aaa="todo in todos"/>
      <div v-for.bbb="todo in todos"/>
      <div
        v-for="todo in todos"
        is="MyComponent"
      />
      <MyComponent v-for="todo in todos"/>
      <MyComponent
        v-for="todo in todos"
        :key="foo"
      />
    </template>