深入剖析 Vue 项目中 ESLint 与 Volar/Vetur 的常见冲突及解决方案

15 阅读26分钟

在 Vue.js 项目开发中,我们通常会使用 ESLint 来进行代码规范检查,同时借助 Volar(Vue3 官方语言工具)或 Vetur(Vue2 官方扩展)来提供编辑器内的类型提示和模板校验。然而,这两类工具有各自的职责范围,当配置不当或用法混杂时,往往会出现令人困惑的冲突提示。本文将深入浅出地分析 ESLint 与 Volar/Vetur 常见冲突的类型、原因,并提供相应的解决办法,帮助开发者让两者在项目中“和平共处”。

ESLint 与 Volar/Vetur:作用与职责区别

ESLint 是一款静态代码分析工具,通过预定义的规则来检查代码风格和潜在错误。在 Vue 项目中,我们通常使用由 Vue 官方团队维护的 eslint-plugin-vue 插件,该插件提供了对单文件组件 (.vue 文件) 的一系列规则检查。ESLint 的运行基于代码文本和 AST 分析,关注的是代码是否符合既定规范(如变量命名、缩进、引号、模板语法正确性等),而不是代码运行时的类型正确性。

VolarVetur 则是 VSCode 等编辑器中的 Vue 语言服务扩展。二者职责侧重于开发体验:提供语法高亮、代码补全、错误提示等。其中 Vetur 是 Vue2 时代的官方扩展,而 Volar(也称“Vue Language Features”) 是 Vue3 时代新的官方扩展。Volar 基于 TypeScript 语言服务器架构,能够对 .vue 模板中的表达式和组件 Prop 进行类型检查和智能提示。相比之下,Vetur 提供的检查和提示相对有限(主要针对 Vue2 选项式 API),但内置了一些格式化和校验功能,比如模板语法检查、代码片段、以及默认的代码格式化等。

简而言之:ESLint 更关注代码规范的静态检查,通过配置规则来提示不符合规范的代码;Volar/Vetur 则作为编辑器插件,提供实时的模板解析和类型提示。由于功能上有所重叠(例如模板语法校验),当两者配置不协调时,就会出现冲突。

常见冲突类型

下面列举 Vue 项目中经常遇到的 ESLint 与 Volar/Vetur 冲突情况,并通过 Vue2 和 Vue3 的示例代码来说明发生原因。

1. <template v-for> 上 key 属性的规则冲突

在 Vue2 和 Vue3 中,v-for 列表渲染对 key 属性的位置有不同的规范要求。如果使用不当,ESLint 和编辑器插件会给出相互矛盾的报错提示。

**Vue2 情况:**在 Vue2 中,我们通常这样使用列表渲染的模板:

<!-- Vue 2.x 列表渲染示例 -->
<template v-for="item in items">
  <div :key="item.id">{{ item.name }}</div>
</template>

在 Vue2 中,不允许key 写在 <template> 标签上,而是要求将 :key 放在内部直接渲染的元素上(如上述示例中的 <div>)。Vue2 的 ESLint 规则(如 vue/no-template-key)会禁止在 <template> 上使用 key

Vue3 情况:Vue3 支持模板的多根节点片段,允许在 <template v-for> 本身加 key 来标识整个片段。Vue3 的 ESLint 规则(如 vue/no-v-for-template-key-on-child)恰恰要求key 放在 <template> 上,而不要放在内部子元素上。也就是说,在 Vue3 中,上述代码会被认为不规范,正确的写法是:

<!-- Vue 3.x 列表渲染示例 -->
<template v-for="item in items" :key="item.id">
  <div>{{ item.name }}</div>
</template>

冲突现象:如果在 Vue2 项目 中使用了 Volar 插件(默认按 Vue3 规则校验模板)且未做兼容配置,就可能遇到这样的提示错误:<template v-for> key should be placed on the <template> tag.。这是 Vue3 的规则在 Vue2 模板上产生的误报。换句话说,Volar 没有识别当前是 Vue2 项目,错误地按 Vue3 规范要求将 key 移到 <template> 上。而 ESLint(若仍按 Vue2 配置)可能同时提示相反的规则违背。这种矛盾会让人无所适从。

产生原因:Volar 默认优先支持 Vue3 模板规则,当在 Vue2 项目中未设置兼容模式时,模板被当作 Vue3 来解析,触发了 ESLint 插件 7.x 版本才有的规则校验。同时,本地 ESLint 插件若版本较旧(如 eslint-plugin-vue 4.x),并不认识 Vue3 新规则,会对不同位置的 key 给出不同建议,导致两边冲突。

2. 插槽语法版本差异(slot vs v-slot vs #

Vue 插槽的语法在版本迭代中发生了变化,也可能引发 ESLint 与编辑器提示的不一致。

Vue2 语法:在 Vue2.5 之前,命名插槽使用 slot 属性指定插槽名,作用域插槽则使用 slot-scope 属性定义插槽 Prop。例如一个子组件 <Child> 在父组件中提供内容:

<!-- Vue 2.x 父组件中使用旧插槽语法 -->
<Child>
  <template slot="header">
    <h3>标题</h3>
  </template>
  <template slot-scope="slotProps">
    <p>{{ slotProps.text }}</p>
  </template>
</Child>

上例中,<template slot="header"> 为名为 "header" 的具名插槽提供内容,<template slot-scope="slotProps"> 表示默认插槽的作用域插槽语法(在 Vue2.6 中也可写作 slot="default" 明示默认插槽)。这些语法在 Vue2 中是合法的,但在 Vue3 中已经被废弃。

Vue3 语法:Vue3 中统一了插槽语法,只保留了 v-slot 指令(以及缩写 #)。上面的内容在 Vue3 中应改写为:

<!-- Vue 3.x 父组件中使用新插槽语法 -->
<Child>
  <template #header>
    <h3>标题</h3>
  </template>
  <template #default="slotProps">
    <p>{{ slotProps.text }}</p>
  </template>
</Child>

也可以将默认插槽直接写成简写,如 <template v-slot:default="slotProps"> 或进一步简写为上面的 #default。Vue3 不再支持旧的 slotslot-scope 属性语法——这些在 Vue2.6 就已标记为废弃,并最终在 Vue3 移除。因此,在 Vue3 项目 中如果仍使用旧语法,ESLint(开启 Vue3 规则)会报 slot 属性已废弃的错误(对应规则 vue/no-deprecated-slot-attribute 等),Volar 也可能无法识别正确的插槽内容。这类错误信息通常类似: slot attributes are deprecated” ,提示开发者改用新语法。

冲突现象:如果是 Vue2 项目 使用 Volar(Vue3 扩展)但没有开启兼容,可能出现 Volar 提示不认识 slot-scope 或要求使用 v-slot 的情况,和实际 Vue2 代码需求不符。相反,在 Vue3 项目 若 ESLint 配置沿用了 Vue2 规则(或 Vetur 插件仍在工作),可能没有对旧插槽用法给出警告,从而遗漏了应该升级的语法。

产生原因:插槽语法冲突源于 Vue 不同版本的语法变动lint 规则差异。Vue2.6 起官方就不推荐使用 slot 属性,转而引入了统一的 v-slot。Vue3 强制移除了旧语法支持,因此新版的 eslint-plugin-vue 会检测并报废弃警告。而 Vetur 作为 Vue2 插件,默认接受老语法,不会报错;Volar 面向 Vue3,则倾向于新语法。如果项目的 Vue 版本和所用插件规则/配置不匹配,就会出现一边警告、一边静默的不一致现象。

3. 格式化规则冲突(缩进、引号、空格风格)

代码格式方面,ESLint/PrettierVolar/Vetur 也可能产生“斗法”,表现为保存时代码反复在两种风格之间来回切换,或 ESLint 报告大量格式错误。常见冲突包括缩进层级、引号类型、属性换行等。

场景举例:开发者使用 Prettier 来统一格式化,但同时 Vetur 也默认启用了自己的格式化器,对 .vue 文件进行处理。比如一个组件标签:

<MyComponent propA="foo" propB="bar" propC="baz" />

Prettier 默认在属性不多且行宽允许时,会将上述标签格式化为单行。而 eslint-plugin-vue 可能有规则要求多属性时每个属性独占一行(如 vue/max-attributes-per-line),或者 Vetur 默认设置下会将超过一定数量的属性自动换行格式化。结果就是:保存文件时,Prettier 插件将代码整理成某种风格,紧接着 ESLint/Vetur 又尝试按另一个风格调整,互相覆盖,导致代码格式在两种风格之间“来回抖动”。典型的症状包括:引号在单引号和双引号之间来回转换,缩进有时2空格有时4空格,HTML 属性有时被拆成多行有时又合并回一行等等。

冲突现象:这种格式冲突往往会体现在控制台或编辑器报大量 ESLint 错误,提示诸如 引号风格不符缩进级别不对多余空格属性换行不符合规则 等等。如果同时开启了 Prettier 和 Vetur 的格式化,保存时可能看到代码被格式化两次,或者第一次保存做了调整,紧接着又被另一套规则改回去。

产生原因:格式冲突的根源是多套格式化工具同时作用规则不一致。Vetur 内置绑定了一系列格式化程序(其中包括 Prettier)用于 .vue 文件格式化。如果 VSCode 配置中没有明确指定,Vetur默认配置的格式化选项会覆盖掉用户在 Settings.json 里针对 Prettier 的设置。另外,ESLint 若启用了风格类规则(如关于空格、引号、换行的规则)而这些规则与 Prettier 的风格不同步,就会在保存时对 Prettier 已经格式化的结果再次给出警告。例如,Prettier 默认 HTML 属性使用双引号且一行容纳尽可能多属性,但 ESLint 插件可能规定了每行只允许一个属性,这时保存后 ESLint 会报错要求换行。综上,没有统一格式化单一来源就会导致工具互相“打架”。

4. 类型提示 VS ESLint 静态检查结果不一致

由于 Volar (TypeScript) 提供了代码的类型检查能力,而 ESLint 仍以静态规则为主,有时候二者对同一代码的反馈不一致,甚至互相矛盾。

场景举例1:在 Vue3 + TypeScript 项目中,假设我们有一个子组件要求 number 类型的 prop:

<!-- ChildComp.vue -->
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  props: {
    count: Number  // count: { type: Number }
  }
})
</script>

在父组件中却这样使用它:

<!-- Parent.vue -->
<template>
  <!-- 将字符串传给 count prop -->
  <ChildComp :count="'5'" />
</template>

Volar 的类型检查会立即在编辑器中报错,指出字符串不能赋给 count(数值)属性,类似提示: “Type 'string' is not assignable to type 'number'.” 。这是运行时类型层面的错误。然而,ESLint 并不会对此有任何意见——因为 ESLint 默认并不了解组件属性的实际类型,它只是静态地检查模板和脚本结构。所以我们会看到 Volar 红线报错,但 npm run lint 却通过无误。这种不一致需要开发者意识到:类型错误需通过编译器/类型检查工具解决,而非指望 ESLint

场景举例2:在 Vue3 <script setup> 语法中,使用了 Composition API 的宏方法,例如:

<script setup lang="ts">
const props = defineProps<{ msg: string }>()
</script>
<template>
  {{ props.msg }}
</template>

对于上述代码,Volar 会正确地识别 defineProps 提供的类型,并且知道模板中 props.msg 是一个字符串类型,无任何错误。但是如果 ESLint 配置不当(例如没有使用 vue-eslint-parser 或最新的 eslint-plugin-vue),可能会错误地报出 “defineProps is not defined” 或 “props 未使用” 等静态分析错误。这并不是真正的代码错误,而是 ESLint 无法理解 Vue3 特殊语法所致。

冲突现象:类型相关的冲突更多表现为某些工具报错而另一些不报错。开发者可能疑惑:“编辑器红线报错,但项目仍然可以编译通过” 或 “ESLint 报的问题,但类型提示明明是好的”。这种不一致可能导致误判,甚至在 CI 中遗漏真正的问题。例如,如果没有运行类型检查就通过了 ESLint,实际构建时可能仍会因为类型不匹配而失败。

产生原因:类型提示与静态检查不一致主要是因为两者检查维度不同:Volar 利用 TypeScript 编译器对代码进行完整的类型分析,能发现类型错误、不存在的属性、无效的 emit 等,而 ESLint 的大多数规则不执行类型推断,只根据语法模式检查(除非使用了专门的 ESLint TypeScript 规则)。另一方面,ESLint 关注的某些代码模式(如未使用的变量、定义但未使用的组件等)是语义层面的,它不关心类型是否正确。例如未使用的变量在类型检查看来无碍运行,但在代码规范上是不被允许的。这样就可能出现:一个变量类型上没问题,但 ESLint 觉得没被用就是问题;反之,类型错误在 ESLint 看来不算违反规范,但在编译运行时会导致 bug。所以我们需要结合两方面反馈来改进代码,而当反馈不一致时,要清楚是类型层面还是规范层面的差异。

冲突背后的原因分析

通过以上实例可以看出,ESLint 与 Volar/Vetur 冲突往往源于它们工作方式和作用范围的差异

  • 规则来源不同:ESLint 对 Vue 的检查基于 eslint-plugin-vue 提供的规则集。这些规则是静态预先定义的,并且跟 Vue 版本强相关(不同版本插件针对 Vue2/Vue3 有不同规则集合)。如果 ESLint 插件版本或配置和实际项目 Vue 版本不一致,就会产生似是而非的报错提示。例如 Vue3 项目若仍使用 Vue2 的规则集,会漏掉对新语法的检查;Vue2 项目误用了 Vue3 规则,则会得到不适用的报错(如前述 key 属性位置问题)。Volar/Vetur直接基于 Vue 模板编译器和 TypeScript 语言服务进行分析,它更关注代码实际的可运行和类型正确性。当 Volar 未正确识别项目Vue版本时,可能会用错误的编译模式来检查模板(默认按Vue3处理),从而导致与真实框架不符的提示。
  • 功能重叠与重复校验:Vetur 插件在 Vue2 时代承担了许多基础校验功能,如模板语法是否正确、是否缺少必需的 key、插槽用法是否正确等。这些检查有些在 ESLint 规则中也覆盖了。结果是ESLint 和 Vetur 可能对同一问题各报一遍,甚至各自的错误消息描述不同,让人难以分辨。例如 Vetur 提示 “v-for 列表缺少 key”,而 ESLint 也警告 “每个 v-for 元素需要 key”,开发者可能需要分别处理。这种重复源于当时 ESLint 还不完善,Vetur 才添加额外检查。但随着 eslint-plugin-vue 规则完善,现在应避免让两者同时启用重复检查。官方也建议在使用 Vue3 时禁用 Vetur,改用 Volar 以减少冲突。对于仍在用 Vetur 的情况,也可以在设置中关闭其校验功能,只保留 ESLint 提示。
  • 格式化职责没有单一化:正如上文所述,如果同时启用了 ESLint 的格式规则、 Prettier 格式化、以及 Vetur/Volar 自带的格式化,而这些工具默认配置未对齐,就会互相干扰。根源在于缺乏统一的格式化配置源。理想情况下,应选定一种格式化方案(例如 Prettier),让其它工具配合它运作。具体做法是在 ESLint 中关闭所有与格式相关的规则,由 Prettier 全权格式化代码;同时在编辑器中禁用 Vetur/Volar 自带的格式化功能或将其指向 Prettier。如果没有这样做,不同格式器就会按照各自标准“各行其是”,导致冲突。
  • 类型 vs 静态的固有区别:类型检查与静态规则检查是两个维度,不可能保证完全一致。类型检查依赖于正确的类型声明和推断,能捕获许多动态错误,但 ESLint 规则更关注代码风格和可读性。一些 Volar 提供的错误(例如模板里使用了不存在的组件属性)是编译层面的,ESLint 压根无从发现;反之,一些 ESLint 规则(例如限制组件名风格或阻止使用特定语法)是团队规范,类型检查不会给出意见。因此出现不一致是正常的。关键在于配置好两者共同作用:例如使用 @vue/eslint-config-typescript 之类的配置让 ESLint 也能利用 TypeScript 信息,从而减少与 Volar 的差异;或者在特殊场景下屏蔽 Volar 的类型提示(如之前提到的在 Vue2 中关闭模板的 TS 校验),以避免干扰日常开发。

理解了上述原因,我们就能有针对性地解决这些冲突。在下一节,我们将给出完整的解决方案和配置建议。

解决方案

针对以上分析的冲突类型,这里提供一套完整的解决思路,包括配置调整和工具选择,以便让 ESLint 和 Volar/Vetur 各司其职、互不干扰。

禁用或调整部分 Volar/Vetur 校验

1. 避免 Vetur 与 Volar 双重运行:如果你的 VSCode 同时安装了 Vetur 和 Volar,两者都会尝试接管 .vue 文件的语言服务,可能引发重复的警告甚至性能问题。官方建议是在使用 Vue3 项目时禁用 Vetur扩展,确保只启用 Volar。如果你需要在同一编辑器中兼顾 Vue2 和 Vue3 项目,有两种选择:一是手动切换启用/禁用对应扩展;二是在工作区设置里禁用 Vetur 的特定功能。例如,可在当前项目下的 .vscode/settings.json 中加入如下配置,只关闭 Vetur 的校验功能,而保留 Volar 提供服务:

{
  "vetur.validation.template": false,
  "vetur.validation.script": false,
  "vetur.validation.style": false
}

上述设置将让 Vetur 不再对模板、脚本、样式做检查,把这部分工作交给 ESLint 和 Volar。同时也可以设置 "vetur.format.enable": false 以禁用 Vetur 的格式化功能。总之,确保同一时间只有一个来源在检查 .vue 文件,避免多头管理。

2. Volar 与 Vue2 兼容配置:如果你的项目仍是 Vue2,但决定使用 Volar 扩展(例如为了使用其更强的类型提示),务必进行兼容模式配置。具体做法是:在项目根目录新增一个 tsconfig.jsonjsconfig.json 文件(如果尚未存在),并加入 Vue Compiler 的选项。例如:

{
  "vueCompilerOptions": {
    "experimentalCompatMode": 2
  }
}

该配置启用了 Volar 的 Vue2 模板兼容模式。experimentalCompatMode: 2 表示让 Volar 按照 Vue2 的语法规则来解析 .vue 模板,从而避免先前提到的 <template v-for> 等检查冲突。对于 Vue2.7(带有组合式API)的项目,还可以在此配置里设置 "vueCompilerOptions": { "target": 2.7 },以匹配 Vue2.7 特性,并通过 "experimentalDisableTemplateSupport": true关闭模板内的严格 TS 校验,避免像 (item) => ... 这类模板内箭头函数因类型不明确而报错。总之,根据项目 Vue 版本正确配置 Volar,有助于减少很多不必要的冲突提示。

3. 筛选关闭特定规则:无论 Vetur 还是 Volar,可能都有一些检查跟 ESLint 重复或者不需要。在 Vetur 中,你可以通过设置来选择性关闭部分校验(例如只关闭模板校验但保留拼写检查等)。在 Volar 中,大部分校验紧密结合 TS 类型系统,不建议全部关闭,但你可以忽略特定文件的类型错误(例如在一些第三方库的 .d.ts 报错时),或者在极端情况下通过 VSCode 的 "typescript.validate.enable": false 设置来避免重复的 TS 错误显示。另外,对于 ESLint 已覆盖的检查,也可考虑在编辑器中隐藏对应的 Volar 提示。例如 ESLint 已经检查组件命名了,则 Volar 那里的提示可以忽略。核心原则是明确哪一类问题应由谁来提示,然后在另一方那里将其关闭,以减少噪音。

配置 ESLint + Prettier 统一代码风格

1. 统一格式化工具:建议在团队项目中统一采用 Prettier 作为代码格式化的核心工具,然后让 ESLint 配合它运作。实践步骤如下:

  • 安装相关依赖:npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier 等。并在 .eslintrc.js 中的 extends 数组加入 plugin:prettier/recommended。这条配置将自动关闭 ESLint 中所有和 Prettier 相冲突的规则,例如有关缩进、引号、分号等样式类检查。如此一来,ESLint 将不再对格式问题报错,把选择权交给 Prettier。

  • 在项目根目录添加 Prettier 配置文件(如 .prettierrc),确定团队约定的风格(2空格缩进、单引号/双引号、分号是否保留等)。也可以在 package.json"prettier" 字段里配置。确保每个人使用相同的 Prettier 设置,以避免因为本地配置不一致导致提交代码格式变化。

  • 配置 VSCode 等编辑器使用 Prettier 来格式化 .vue 文件。方法是在设置中指定 [vue] 文件的默认格式化器为 Prettier(安装 VSCode 的 Prettier 插件),或者禁用 Vetur/Volar 的格式化功能。正如之前提到的,Vetur 默认会用它内置的格式化器处理 .vue,需要显式设置让 Vetur 也调用 Prettier。例如在 VSCode settings.json 中:

    "vetur.format.defaultFormatter.html": "prettier",
    "vetur.format.defaultFormatter.js": "prettier-eslint" 
    

    如此配置后,Vetur 就不会再用自带规则强制格式化,而是把任务交给 Prettier。对于 Volar,则通常直接使用 Prettier 插件即可,它不会干预格式化。

2. 处理特殊格式冲突:有了上述统一方案,大部分格式冲突会消除。但若仍有 ESLint 提示与 Prettier 不符的情况,可以手动调整对应规则。例如,Prettier 默认不强制单行/多行属性,但若 ESLint 仍报 vue/max-attributes-per-line 警告,可在 .eslintrc 中将其关闭或调低级别。如果某些非常规风格(比如模板内换行策略)Prettier 无法满足团队要求,可以考虑引入 prettier-plugin-vue 或调整 Prettier printWidth 等参数,再配合 eslint-plugin-vue 的规则设置,找到一个平衡。重点是避免两个工具对同一格式细节各执一词。一旦决定由 Prettier主导格式,就尽量让 ESLint 不再“插手”格式问题。这方面 eslint-config-prettier 已经做了大量工作,我们遵循其推荐即可。

3. 校验与格式分离:最后,建议将 “保存时自动修复” 功能限定为格式化操作,而非 ESLint 自动修复。也就是在 VSCode 中设置 "editor.formatOnSave": true(由 Prettier 接管),而关闭 "eslint.autoFixOnSave"。这样每次保存只触发一次 Prettier 格式化,不会再有 ESLint 的第二次改动,避免冲突。另外,可以在 Git 提交时使用 lint-staged + eslint --fix + prettier --write,在保证格式正确的同时,ESLint 修复一些简单代码问题,二者顺序执行井然有序,各司其职。

Vue 2 项目:使用 Vetur 还是迁移 Volar?

对于仍在使用 Vue2 的项目,关于编辑器插件的选择需要考虑现状和未来升级计划:

  • 继续使用 Vetur:如果你的项目基于 Vue2 选项式 API,技术栈相对稳定,团队对 TypeScript 支持要求不高,那么 Vetur 依然是合适且简便的选择。Vetur 是为 Vue2 量身打造的官方插件,开箱即用地提供了模板高亮、代码片段、基本校验和格式化等功能。对于典型的 Vue2 项目,Vetur 的提示与规则与框架高度吻合,一般不会有上文提到的 key、slot 等误报问题。同时,Vetur 经过多年的迭代,比较稳定,且很多老项目默认配套它。如果短期没有升级 Vue3 的打算,维持现状用 Vetur 并结合 ESLint 4.x/5.x 版本规则是最省事的方案。当然,需要注意禁用 Vetur 与 ESLint 重复的检查或格式化,按照前文方法调整设置,以减少冲突。
  • 迁移至 Volar:如果你的 Vue2 项目已经开始使用 Class API、TypeScript 或计划将来升级到 Vue3,那么可以考虑提前迁移到 Volar。Volar 官方已经提供对 Vue2 模板的兼容支持,只需在项目配置中开启兼容模式(前文提到的 experimentalCompatMode 等设置)。使用 Volar 的好处是:当你将来升级到 Vue3 时,无需更换编辑器插件,而且可以提前体验更完善的类型提示(例如 Volar 能识别 .vue 组件导出的 TS 类型,支持 Vue2.7 Composition API 等)。实际上,Vue3 官方文档已经推荐使用新版 “Vue 官方扩展 (Volar)” 来取代 Vetur。一些团队在维护 Vue2 项目时也选择 Volar 以统一开发环境。这种做法需要做一些配置工作,但长远来看减少了迁移成本。
  • 混合使用的权衡:还有一种折中方案是Vue2 项目同时安装 Vetur 和 Volar,并根据需要启用。比如大部分时间用 Vetur,但在需要 TS 强类型支持的部分组件上暂时启用 Volar。不过这种方式复杂且可能产生不可预期的问题,不太推荐。更好的做法是基于项目实际情况二选一,然后在团队内统一规范。对于多数经典 Vue2 项目,除非遇到 Vetur 无法解决的问题,否则没必要强行切换。若切换,则务必让开发环境中的每个人都应用相同的 Volar 配置,并移除/禁用 Vetur 以避免冲突。

小结:Vue2 项目选用哪种插件,取决于稳定需求升级规划。保守路线选择 Vetur,前瞻路线选择 Volar+兼容模式。无论哪种,都要确保 ESLint 的规则和所用插件匹配对应的 Vue 版本,避免规则错用。

Vue 3 项目:推荐的组合与配置

对于 Vue3 项目,我们有相对明确的最佳实践组合:

  • VSCode 插件:使用官方推出的 Vue Language Features (Volar) 扩展。这是 Vue3 的官方推荐插件,提供一站式的 Vue3 支持,包括 <script setup>、TypeScript 类型检查、模板补全等。不要同时启用旧的 Vetur,以免冲突。安装 Volar 后,如果 VSCode 尚有 Vetur,可以在扩展设置里为你的 Vue3 项目工作区禁用 Vetur。Volar 默认即可良好运行,无需复杂配置;如果你使用 TypeScript,还可以安装 TypeScript Vue Plugin (Volar) 插件来增强 TS 服务(某些情况下已经集成)。
  • ESLint 配置:使用 eslint-plugin-vue 8.x 或以上版本,并选择 Vue3 风格指南的预设。在 .eslintrc 中这是通过扩展 'plugin:vue/vue3-recommended''plugin:vue/vue3-essential' 来实现的(具体取决于你想应用的规则严格程度)。另外搭配使用 @vue/eslint-config-typescript(如果用TS)来使 ESLint 识别 .vue 组件内的类型。确保你的 ESLint 版本、插件版本都支持 Vue3 特性,比如对 <script setup> 和 JSX 等的解析支持。通常最新的 Vue CLI 或 Vite 脚手架会附带合适的 ESLint配置,你可以在此基础上调整。
  • Prettier 与格式:建议同样引入 Prettier 来处理格式问题,并使用 eslint-config-prettier 关掉冲突规则(如上一节所述)。这样你的代码格式将主要由 Prettier决定,而 ESLint 只关注代码质量和错误检查。这种组合在 Vue3 项目中已经相当普遍,也有大量现成模版可参考。设置好 Prettier 后,记得在 Volar 中关闭格式化或设置默认格式化器为 Prettier,以免 Volar 的格式化和 Prettier 冲突(Volar 本身不像 Vetur那样自带格式化,但保险起见可以在 VSCode 设置 "editor.defaultFormatter": "esbenp.prettier-vscode" 针对 .vue)。
  • TypeScript 类型检查:如果你的 Vue3 项目使用 TypeScript,除了依赖 Volar 实时检查外,建议在项目构建流程中加入 vue-tsc --noEmit(Vue官方的单文件组件类型检查工具)作为额外的检查步骤。这可确保即使某些类型错误未在编辑器中引起注意(例如编辑器未加载、或多人协作有人没装Volar),CI 构建时也能发现。eslint 和 vue-tsc 可互补——前者管风格和规范,后者保驾代码的类型安全。

总的来说,Vue3 项目的配置核心是:Volar + ESLint(Vue3 规则) + Prettier。这一组合基本涵盖了代码质量的各个方面,并最大程度地减少了彼此冲突。

最佳实践总结:让 ESLint 和 Volar/Vetur 和平共处

  • 明确分工,避免重复:尽量让 “一件事由一个工具来做” 。例如代码格式化只交给 Prettier,一个规范检查点只由 ESLint 或 Volar/Vetur 其中之一提示。避免两边同时启用相同功能的校验,以减少重复警告和冲突。
  • 配置匹配项目技术栈:确保 ESLint 的规则集、Volar/Vetur 的模式与项目 Vue 版本对应。如果升级了 Vue 版本,也要同步更新 ESLint 插件配置(Vue3 项目务必使用 Vue3 规则)。相应地,编辑器插件也选择正确:Vue3 用 Volar、Vue2 则用 Vetur 或配置好的 Volar 兼容模式。
  • 不要同时启用多个 Vue 插件:在 VSCode 中请禁用掉未使用的那个(Volar 和 Vetur 只能二选一)。若因特殊原因共存,也务必在项目配置里关闭一个的校验功能,防止它们抢占对 .vue 文件的解析权。
  • 统一代码风格源:选择 Prettier 等工具统一格式后,在 ESLint 中关闭所有冲突规则,使 ESLint 与其一致。同时关闭 Vetur 自带的格式化或指定其使用 Prettier,以免覆盖 Prettier 设置。确保团队所有成员的编辑器保存行为一致,避免“忽左忽右”的格式改动。
  • 充分利用类型检查:对类型相关的问题,多依赖 Volar/TS 提示,但也可以让 ESLint 辅助发现一些逻辑错误和不规范用法。对于 Volar 提示的类型问题,不要简单地用 ESLint 规则屏蔽(例如不要因为 Volar 报 any 类型错误就想着关掉 eslint 的 no-explicit-any 规则,正确做法是修正类型)。相反,对于 ESLint 才报出的模式问题(如禁用特定 API),也不应通过关闭 Volar 来规避。各司其职,各尽其用才能保证代码既健壮又整洁。
  • 勤于升级和调整:随着 Vue 生态的发展,ESLint 规则和编辑器插件也在更新。保持依赖包和配置的及时升级,可以享受到更好的兼容性和更少的冲突。例如 eslint-plugin-vue 新版本修复了很多与 Vue3 的兼容问题,Volar 也在不断改进对 Vue2 的支持。所以定期检查这些工具的更新日志,适当调整配置,是维持和平共处的长久之道。