eslint-plugin-vue icon indicating copy to clipboard operation
eslint-plugin-vue copied to clipboard

The plugin does not function properly when `languageOptions.projectService` is enabled

Open A-kirami opened this issue 1 year ago • 8 comments

Checklist

  • [x] I have tried restarting my IDE and the issue persists.
  • [x] I have read the FAQ and my problem is not listed.

Tell us about your environment

  • ESLint version: 9.16.0
  • eslint-plugin-vue version: 9.32.0
  • Vue version: 3.5.13
  • Node version: 22.11.0
  • Operating System: Windows11

Please show your full configuration:

// @ts-check

import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.recommended,
  ...pluginVue.configs["flat/recommended"],
  {
    files: ["*.vue", "**/*.vue"],
    languageOptions: {
      parserOptions: {
        parser: tseslint.parser,
        ecmaFeatures: {
          jsx: true,
        },
        extraFileExtensions: [".vue"],
        projectService: true, // If you comment out this line, it will work.
        tsconfigRootDir: import.meta.dirname,
      },
    },
  }
);

What did you do?

When languageOptions.projectService is set to true, it reports errors for JSX but does not report errors for Vue.

<script setup lang="tsx">
const jsxComponent = <div>This is a jsx component</div>
</script>

<template>
  <jsxComponent></jsxComponent>
  <div></div>
</template>

What did you expect to happen?

The errors related to JSX should not be reported, and errors related to Vue should be reported.

/project/workspace/src/App.vue
  6:3  warning  Require self-closing on Vue.js custom components (<jsxComponent>)  vue/html-self-closing
  7:3  warning  Require self-closing on HTML elements (<div>)                      vue/html-self-closing

✖ 2 problems (0 errors, 2 warnings)
  0 errors and 2 warnings potentially fixable with the `--fix` option.

What actually happened?

/project/workspace/src/App.vue
  2:31  error  Parsing error: ',' expected

✖ 1 problem (1 error, 0 warnings)

Repository to reproduce this issue

https://codesandbox.io/p/devbox/cvwhrs

A-kirami avatar Dec 01 '24 11:12 A-kirami

This has nothing to do with projectService. It's that you tell ESLint to parse Vue files with typescript-eslint's parser. Instead, you have to use eslint-parser-vue, which in turn you can tell to use typescript-eslint's parser for the JavaScript/TypeScript parts of Vue components. See e.g. https://eslint.vuejs.org/user-guide/#example-configuration-with-typescript-eslint-and-prettier.

FloEdelmann avatar Dec 01 '24 11:12 FloEdelmann

This has nothing to do with projectService. It's that you tell ESLint to parse Vue files with typescript-eslint's parser. Instead, you have to use eslint-parser-vue, which in turn you can tell to use typescript-eslint's parser for the JavaScript/TypeScript parts of Vue components. See e.g. eslint.vuejs.org/user-guide#example-configuration-with-typescript-eslint-and-prettier.

I need to enable Linting with Type Information for typescript-eslint. According to its documentation, I need to set up the following:

  {
    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
  },

I updated my ESLint configuration based on the documentation you provided:

// @ts-check

import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";
import globals from "globals";

export default tseslint.config(
  {
    extends: [
      eslint.configs.recommended,
      ...tseslint.configs.recommended,
      ...pluginVue.configs["flat/recommended"],
    ],
    files: ["**/*.{ts,vue}"],
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      globals: globals.browser,
      parserOptions: {
        parser: tseslint.parser,
        ecmaFeatures: {
          jsx: true,
        },
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
    rules: {
      // your rules
    },
  }
);

However, it resulted in an error:

/project/workspace/src/App.vue
  0:0  error  Parsing error: /project/workspace/src/App.vue was not found by the project service because the extension for the file (`.vue`) is non-standard. You should add `parserOptions.extraFileExtensions` to your config

✖ 1 problem (1 error, 0 warnings)

After configuring parserOptions.extraFileExtensions as suggested by the error message:

/project/workspace/src/App.vue
  2:31  error  Parsing error: ',' expected

✖ 1 problem (1 error, 0 warnings)

The previous issue still persists.

Is there an incorrect configuration somewhere? How should it be set up to work seamlessly with Typed Linting?

A-kirami avatar Dec 01 '24 13:12 A-kirami

~~You need to add "./**/*.vue" to the "include" option in your tsconfig.json.~~ EDIT: "src/**/*.vue" was already included in the reproduction.

FloEdelmann avatar Dec 01 '24 13:12 FloEdelmann

You need to add "./**/*.vue" to the "include" option in your tsconfig.json.

You can see the reproduction link I submitted in the issue, where the tsconfig.json configuration is as follows:

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "jsxImportSource": "vue",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

"src/**/*.vue" should already be included.

Even if I add "./**/*.vue" to "include":

/project/workspace/src/App.vue
  0:0  error  Parsing error: /project/workspace/src/App.vue was not found by the project service because the extension for the file (`.vue`) is non-standard. You should add `parserOptions.extraFileExtensions` to your config

✖ 1 problem (1 error, 0 warnings)

A-kirami avatar Dec 01 '24 13:12 A-kirami

"src/**/*.vue" should already be included.

Oh right.

I have a pretty similar setup (but still on ESLint v8 with .eslintrc.js config format, and without JSX) and it works fine with:

  parserOptions: {
    parser: {
      js: '@typescript-eslint/parser',
      ts: '@typescript-eslint/parser',
      '<template>': '@typescript-eslint/parser',
    },
    projectService: {
      allowDefaultProject: ['.eslintrc.js', '*.js'],
    },
    tsconfigRootDir: __dirname,
    extraFileExtensions: ['.vue'],
    ecmaVersion: 2021,
    sourceType: 'module',
  },

Maybe it is the JSX that is throwing either parser off somehow?

FloEdelmann avatar Dec 01 '24 13:12 FloEdelmann

"src/**/*.vue" should already be included.

Oh right.

I have a pretty similar setup (but still on ESLint v8 with .eslintrc.js config format, and without JSX) and it works fine with:

  parserOptions: {
    parser: {
      js: '@typescript-eslint/parser',
      ts: '@typescript-eslint/parser',
      '<template>': '@typescript-eslint/parser',
    },
    projectService: {
      allowDefaultProject: ['.eslintrc.js', '*.js'],
    },
    tsconfigRootDir: __dirname,
    extraFileExtensions: ['.vue'],
    ecmaVersion: 2021,
    sourceType: 'module',
  },

Maybe it is the JSX that is throwing either parser off somehow?

I haven't encountered this issue on ESLint 8; everything works fine, even with JSX. However, after upgrading to ESLint 9, the problem emerged.

Here is my ESLint 8 configuration, which didn't encounter any issues:

"plugins": ["vue", "@typescript-eslint"],
"parser": "vue-eslint-parser",
"parserOptions": {
    "ecmaVersion": 13,
    "parser": "@typescript-eslint/parser",
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
  }
},

ESLint 9 works fine if I don't configure TypeScript ESLint's Typed Linting. To be honest, I'm not sure where the issue lies.

A-kirami avatar Dec 01 '24 13:12 A-kirami

So you don't have typed linting with ESLint 8? Could you try whether that works?

FloEdelmann avatar Dec 01 '24 14:12 FloEdelmann

So you don't have typed linting with ESLint 8? Could you try whether that works?

No, this is the configuration I'm currently using. I'm in the process of migrating from ESLint 8 to ESLint 9, and with ESLint 8, everything was working fine.

A-kirami avatar Dec 01 '24 14:12 A-kirami