1. 先把三个插件的关系理清楚
很多人一上手 Vue 项目,第一件事就是去装 Vetur,再装个 ESLint,最后发现还要装 Prettier。然后呢?格式化一会儿正常一会儿打架,今天代码是单引号,明天自动变双引号,后天又全挂红灯。我见过太多同事在这种配置泥潭里挣扎一整天的了。
先搞清楚一个底层问题:这三样东西到底分别负责什么?
1.1 Vetur / Volar:Vue 文件的“母语翻译”
Vetur 是 Vue 2 时代官方力推的 VS Code 插件,核心能力是让 VS Code“看得懂”.vue单文件组件。没有它,你在.vue文件里写<template>、<script>、<style>三块内容,编辑器基本是半瞎状态:语法高亮靠猜、补全靠运气、格式全靠手动。
Vetur 之所以一度是标配,是因为它确实做到了“开箱即用”:装完就能高亮、能补全、能格式化。但它的底层架构是“套壳”各路语言服务(对 template 部分调用 HTML 语言服务,对 script 部分调用 JS/TS 语言服务),一旦 Vue 组件的写法复杂起来,比如 script setup 语法、TS 泛型组件、模板复杂表达式,Vetur 的解析就会变得非常吃力,甚至直接摆烂。
所以 Vue 官方后来彻底转向了 Volar(Vue Language Features),也就是 Vue 3 项目里推荐的那套语言服务插件。Volar 的架构完全不同,它自己实现了 Vue 文件的完整解析链,能精准识别<script setup>、模板中的类型检查、对编辑器指令提供更细粒度的支持。说人话就是:Volar 才是 Vue 3 时代的“本地人”,Vetur 已经属于“外来移民”了。
这里有个很容易被忽视的认知:Vetur、Volar 这类插件管的是“Vue 文件的解析和编辑体验”,它们不负责“代码长什么样”,也不负责“代码写得好不好”。长得帅不帅归 Prettier 管,写得好不好归 ESLint 管,分工不一样,谁也替代不了谁。
1.2 Prettier:统一代码长相
Prettier 解决的问题非常纯粹:代码风格。单引号还是双引号、行宽多少、分号加不加、缩进用两个空格还是四个空格、换行怎么换。它就是那个“独裁者”,不给你太多选项,选项就那几个,选完以后全项目一个长相,谁也不用和谁吵。
为什么要专门引入一个格式工具?因为个人风格这东西,人和人真的不一样。我就见过有人 Firefox 风格(else单独一行)和 Allman 风格(大括号独占一行)在同一个 PR 里互相“谦让”了四个回合。Prettier 的价值就是终结这类争论:大家都不用选,代码怎么样,它说了算。
Prettier 的哲学是“opinionated”,它有自己的一套审美,而且选项极其克制。你在 Prettier 里能配置的东西,相比 ESLint 的 rules 少得可怜。但它有一个其他工具比不了的优势:稳定。同一个文件,100 台机器、100 个版本跑出来的结果必须完全一致,这是它的底线承诺。所以 Prettier 从来不会“差不多就行”,它会反复计算到最终稳定格式才输出。
1.3 ESLint:拦住脑残代码
ESLint 的定位完全不同。它不仅仅是“排版”问题,更重要的是代码质量。比如:你声明了一个变量但从来没用到,它有意见;你 if 语句里忘了处理 else 分支,它有意见;你用了==而不是===,它有强烈意见;甚至你的函数太长了,它也能给你整一条“圈复杂度超限”的警告。
换句话说,Prettier 管“长得帅不帅”,ESLint 管“脑子好不好使”。这两者有部分重叠(都对引号、分号、空格提出过要求),但在职责上是能区分开的。这也是为什么现代项目里,ESLint 和 Prettier 必须同时存在,而且还要进行特殊配置,否则它们俩会在引号、分号这种事情上互相顶牛。
所以,这节的核心结论是:
- Volar(Vetur 的替代者)负责看懂 Vue 文件;
- Prettier 负责统一格式;
- ESLint 负责代码质量把关。
三者各管各的,配合好了就是一个顺滑的开发环境;配合不好,那就是你工位上最磨人的小妖精。
2. 为什么 Vetur 突然“不能装了”
很多朋友最近发现:在 VS Code 扩展市场里搜 Vetur,要么搜不到,要么显示“预发布”或“不再维护”,要么装上了但 VS Code 提示“这个扩展已弃用,请使用 Volar”。这不是你网络的问题,也不是 VS Code 抽风,而是历史进程真的走到这一步了。
2.1 官方弃坑背景
Vue 官方在 2021 年就开始在文档中把 Volar 作为 Vue 3 的推荐扩展,到 2022 年、2023 年之后,Volar 已经是 Vue 官方语言支持的唯一指定扩展。Vetur 的 GitHub 仓库基本处于冻结状态,官方长期不更新。VS Code 市场后来干脆对 Vetur 进行下架或者标记为不可用,所以你现在搜不到真的不奇怪——不是被“屏蔽”了,而是它确实进入了生命周期尾声。
这里我多说一句,很多人以为“Vue 2 项目就应该用 Vetur,Vue 3 项目才用 Volar”,这是过时的理解。现在的 Volar 插件本身对 Vue 2 也有一定的兼容支持,而且如果配合 Volar 的 takeover mode 或者新版 Volar 的自动模式,它已经能覆盖 Vue 2.7 和部分老项目的场景。所以哪怕是老项目,也不建议再费劲去折腾 Vetur 了。
2.2 老项目与 Vetur 的处理方式
如果你的机器上已经装了 Vetur,但它明明没有“假死”,甚至还能工作,你可以先不着急卸载。但有两点必须注意:
同一工作区内Vetur 和 Volar 不要同时启用。这两个插件会同时抢占
.vue文件的解析权,结果就是百叶窗式的高亮、飘忽不定的补全、莫名其妙的类型报错。实测下来最典型的症状是:模板里v-if下的变量跳转偶尔不识别,代码补全时灵时不灵,格式化结果时好时坏。如果你想切到 Volar,干净的做法是:在扩展面板里禁用 Vetur(不是卸载也行,但建议直接卸载),然后安装 Vue Language Features (Volar)。装完之后重新加载窗口,让 VS Code 重新初始化语言服务。
如果你因为历史原因必须在一个老项目里继续用 Vetur,那我给你一个折中方案:用 Volar 打开新项目,老项目保留一个专门的 VS Code Profile,只在那个 Profile 里启用 Vetur。VS Code 的 Profile 功能是官方提供的,可以封存一套扩展集合和设置,互不干扰。这是我给很多从 Vue 2 迁移到 Vue 3 团队的建议,实测能减少大量“为什么我打开这个项目就报错”的类型问题。
3. 一套能落地的格式化配置方案
说再多理论不如给一套能抄的作业。下面这套是我在多台电脑、多个项目里反复验证过的配置,覆盖了 Vue 3 + TypeScript + ESLint + Prettier 的常见组合。
3.1 需要安装的插件清单
以下是推荐安装的扩展(按优先级排列):
| 插件名称 | 作用 | 是否必须 |
|---|---|---|
| Vue Language Features (Volar) | .vue文件语法高亮、补全、跳转 | 必须 |
| Prettier - Code formatter | 代码格式化统一 | 必须 |
| ESLint | 代码质量检查 | 必须 |
| TypeScript Vue Plugin (Volar) | 配合 Volar 处理.vue内的 TS 类型检查(如果是 Vue 3 + TS 项目,建议装) | 推荐 |
| Path Intellisense | 路径补全,辅助小功能 | 选装 |
注意,如果项目里用的是 Vue 3 + Vite,那么这个组合基本是无脑配置:Volar 负责 Vue 解析,ESLint 负责质量检查,Prettier 负责格式化。而 Vetur 确实可以彻底说再见了。
3.2 关键配置项与逐行说明
安装完插件后,打开 VS Code 的用户设置(Ctrl + ,),或者更好的是在项目根目录建一个.vscode/settings.json进行项目级配置。我强烈建议用项目级配置,因为团队协作时,每个人机器环境不同,用户级配置很难拉齐。项目级配置提交到 Git 仓库,所有人统一规则,这才是正道。
下面是我常用的.vscode/settings.json配置:
{ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "editor.tabSize": 2, "editor.detectIndentation": false, "files.eol": "\n", "[vue]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "eslint.validate": [ "vue", "javascript", "typescript", "html" ], "eslint.codeAction.showDocumentation": { "enable": true }, "prettier.semi": false, "prettier.singleQuote": true, "prettier.tabWidth": 2, "prettier.trailingComma": "all", "prettier.printWidth": 100 }我逐项说下为什么这么配:
editor.formatOnSave: true:保存时自动格式化。这是提升开发体验最关键的一步,不再需要手动Shift + Alt + F去格式化,省心太多。它的副作用是:如果格式化和 ESLint 规则冲突,会在保存瞬间看到代码被“拉皮条”式地反复横跳,这个我们稍后在常见问题里专门说。editor.defaultFormatter:设置默认格式化器。这里明确指定为 Prettier,防止和其他格式化器(比如 VS Code 自带的 TypeScript 格式化器)抢活。editor.codeActionsOnSave["source.fixAll.eslint"]:保存时自动执行 ESLint 的修复命令。这句是很多项目一开始没配的,结果 ESLint 只报错、不自修,体验极差。配置后,保存时 ESLint 会自动修复可以自动修的问题(比如去掉未使用的变量、补上缺失的分号等)。files.eol: "\n":强制统一换行符为 LF。这一点在 Windows 和 macOS 混合开发的团队里特别重要,否则 Git 经常提示整文件变更,因为你文件里所有行尾都被改了。[vue]、[javascript]、[typescript]的editor.defaultFormatter:按文件类型指定格式化器。为什么这里要单独给 vue 设?因为 Volar 自己带了一个内置格式化器,如果你不指定,VS Code 可能会用小锤子去格式化 vue 文件,结果就是v-if和模板语法被“格式化”得乱七八糟。现在这里强制指定为 Prettier,就能保证.vue文件的格式化归 Prettier 管。eslint.validate:告诉 ESLint 需要检查哪些文件类型。默认情况下 ESLint 对.js和.ts比较积极,但对.vue和.html可能不闻不问。我在这里把vue、html加进去,确保template部分的语法也能被覆盖。
3.3 ESLint 与 Prettier 的冲突处理
配置到这一步,很多人会遇到一个经典问题:ESLint 说要用双引号,Prettier 说要用单引号,俩人在保存的瞬间互相打架,最终代码忽而单引号、忽而双引号,像精神分裂现场。这就是 3.2 节里那个“拉皮条”死循环的来源。
解决方案是安装两个穿梭机包:
npm install -D eslint-config-prettier eslint-plugin-prettiereslint-config-prettier的作用是:自动关闭 ESLint 中所有与 Prettier 冲突的规则。言外之意是:ESLint,你只管代码质量,排版那些破事先靠边站,交给 Prettier。eslint-plugin-prettier的作用是:把 Prettier 当作一条 ESLint 规则来跑。这样 ESLint 的报错列表里能直接显示 Prettier 的格式问题,相当于在 ESLint 区域里又包了一层 Prettier 检查。
然后在.eslintrc或eslint.config.js里做如下配置(以比较通用的.eslintrc为例):
{ "extends": [ "vue-global", "plugin:vue/vue3-recommended", "prettier" ], "plugins": ["vue", "prettier"], "rules": { "prettier/prettier": "error" } }核心就是两条:extends里把prettier放最后(注意:一定要放最后,这样它才能关闭前面规则和它冲突的部分);rules里打开prettier/prettier: error,让 Prettier 的问题在 ESLint 里直接以错误形式暴露出来。
这里有个细节特别容易踩:如果是 Vue 2 项目,extends里用的可能是plugin:vue/vue2-recommended,别搞混了。Vue 3 用vue3-recommended,Vue 2 用vue2-recommended,两者语义完全不同,选错了规则集,模板里的 ESLint 校验就会错得离谱。
4. 常见报错与排查经验
配置这种东西,不跑是不知道有没有问题的。这一节我把自己在实际项目里遇到的一些典型问题整理成速查表,附带解决方案,你直接对照排查就行。
| 问题现象 | 根因 | 解决方案 |
|---|---|---|
| 保存后代码疯狂在单引号/双引号之间横跳 | ESLint 与 Prettier 规则冲突 | 安装eslint-config-prettier和eslint-plugin-prettier,确认.eslintrc中prettier在extends最后 |
vue文件不格式化,但js文件正常 | Volar 内置格式化器抢占了 Prettier 的位置 | 在[vue]文件类型下明确设置editor.defaultFormatter为esbenp.prettier-vscode |
保存时报Cannot find module 'prettier' | 项目本地没安装 Prettier,VS Code 插件找不到执行文件 | 在项目里执行npm install -D prettier,全局安装也行,但团队项目强烈建议本地安装 |
ESLint 检查不到.vue文件 | eslint.validate里没加vue | 在settings.json中增加"eslint.validate": ["vue"] |
Volar 已安装但.vue文件无高亮 | Vetur 和 Volar 同时在启用状态 | 禁用或卸载 Vetur,然后重新加载 VS Code 窗口 |
格式化后v-if缩进混乱 | 模板部分被 HTML 语言服务格式化,而非 Vue 专用格式化器 | 确认[vue]默认格式化器为 Prettier,而非内置 HTML 格式化器 |
保存时eslint只报错不自动修复 | codeActionsOnSave未配置或配置写法不对 | 确认editor.codeActionsOnSave中包含"source.fixAll.eslint": true |
除了这张表,我再补充三个实操心得,这些是文档里通常不会细写的:
第一,ESLint 执行器的选择。VS Code 插件默认会优先使用项目本地的 ESLint,如果本地没有就回退到全局。这个设计很合理,但有时候会造成“本地装了新版本,全局还是老版本”的混乱。排查啥也不生效的问题时,先在终端手动跑一次npx eslint src/App.vue(或你测试的文件),如果命令行能正确报错,但编辑器里不显示红块,那就是 VS Code 插件与本地 ESLint 版本不匹配。新版 VS Code ESLint 插件对 8.x 和 9.x 的 ESLint 要求不同,8.x 走.eslintrc,9.x 支持eslint.config.js,混合着配最容易出事。
第二,格式化生效顺序。如果你配完保存格式化不生效,先打开命令面板(Ctrl + Shift + P),搜“Format Document”,手动格式化一次看编辑器提示用哪个格式化器。有时候 VS Code 会脑洞大开地选一个你都没注意的扩展作为默认格式化器,手动改一次就会弹出“你是否要设置为默认格式化器”,点同意就完事了。
第三,团队协作时的配置统一。光有.vscode/settings.json还不够,建议项目中放一个.editorconfig文件,它不属于任何插件,是跨编辑器规范(VS Code 内置支持)。这个文件专门定义缩进、编码、行尾等基础格式。我再贴一个常见配置供参考:
root = true [*] charset = utf-8 indent_style = space indent_size = 2 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false用 EditorConfig 的意义在于:它连没有装 Prettier 的人也能保证基础的缩进和换行统一,是团队协作的第一道防线。
5. 针对具体项目的实战调整
配置不是一锤子买卖,不同项目的基础设施不一样,实际要处理的问题也不一样。我见过太多人把一套配置从 Vue 2 的 Webpack 项目原封不动搬到 Vue 3 + Vite 项目,然后被各种报错折磨。
5.1 Vue 3 + Vite 项目
Vite 项目通常不会安装@vue/cli-plugin-babel/eslint那套东西,而是 require 最新的eslint-plugin-vue和@vue/eslint-config-typescript(如果用了 TS)。这种情况下,ESLint 的配置文件和上面给出的样子基本一致,但 eslint 版本最好升级到 8.x 或 9.x。如果用的还是老版本的plugin:vue/vue3-essential,很难发挥 Vite 项目的全部功力。
Vite 项目一个特殊点是模板表达式里的“未使用变量”检查在 ESLint 9 + Volar 组合下会变得异常严格。比如你在<template>里用了v-for="(item, index) in list",但index没有实际使用,eslint 会报 unused var。从语法上来说它确实是未使用变量,但这个报错本身在某些业务场景下有些“矫枉过正”。如果团队觉得这种检查太烦,可以在 eslint 规则里对vue/multi-word-component-names等规则做适当放宽,否则新项目的文件名稍微不规范一点,立刻满屏红灯。
5.2 Vue 2 + Webpack 项目
如果你的项目还是 Vue 2,那 P 个前缀提醒:先把 eslint-plugin-vue 版本锁在 9.x 或更早版本,然后把extends改成plugin:vue/vue2-recommended。Vue 2 项目里,Volar 的支持相对弱一些,但这不代表你就应该退回到 Vetur。Volar 的兼容模式能处理大部分 Vue 2.7 的语法,只是老项目里的 Options API 加上各种 mixin,类型推断确实不可能做到 100% 完美。
这种情况下我的建议是:保守使用 Volar,但把 Volar 的检查级别调到 warning 级别,避免干扰日常开发。具体配置可以在 Volar 插件设置里找到validation相关选项,把 template 与 script 的检查都从 error 改为 warning。说白了,老项目首要目标是别让工具把你劝退,能把代码写顺、格式化统一,就已经是胜利。
5.3 纯 JavaScript 项目 vs TypeScript 项目
纯 JS 项目配置最轻,上面方案完全适用。但 TS 项目要额外注意@typescript-eslint/parser的引入,否则 ESLint 对 TS 语法会一片茫然。正确的是在.eslintrc中设置:
{ "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 2020, "sourceType": "module" }, "plugins": ["vue", "@typescript-eslint", "prettier"] }注意顺序:@typescript-eslint/parser是解析器,它必须能正确理解 TypeScript 语法;ESLint + Prettier 才能愉快地在 TS 环境里继续工作。
如果你是 Vite 创建的 TS 项目,官方脚手架npm create vite@latest生成的模板已经内置了 ESLint 的完整配置链,你只需要把 Volar 打开即可。唯一要留神的是把@typescript-eslint/*插件升级到 7.x 以上版本,老版本和 ESLint 9 会有兼容问题。
6. 我的个人经验与建议
在你踩进插件配置这个坑之前,我想先分享几个真实的体会。
第一个体会是:格式化这件事,一定要在项目创建的第一天就定好规则。我接手过一个从 2019 年开始的项目,中间换了四五个人,代码里既有单引号又有双引号,既有分号又没有分号,缩进既有两个空格又有四个空格。后来我花了整整一个下午加了 Prettier 并且跑了一整遍prettier --write,结果改动了上千个文件,连代码 review 都变得艰难,因为 diff 里全是格式化变更,真实改动被淹没在其中。所以,如果你的团队还没有统一的格式配置,越早统一,成本越低。
第二个体会是:ESLint 和 Prettier 是两套工具,不要混为一谈。我见过有人写规则时在 ESLint 的rules里手动配置semi: ["error", "never"],然后再装 Prettier,结果俩工具为了分号问题天天打架。正确做法是:如果用了 Prettier,ESLint 里和排版相关的规则就尽量关掉,让 Prettier 一家独大,ESLint 专注代码逻辑和规范问题。这套分工模式说了很多年,但是真到配置层面,很多人还是hold不住,屡错屡犯。
第三个体会是:Volar 上来了之后,请忘掉 Vetur 的用法。Volar 的架构和 Vetur 完全不同,它不像 Vetur 那样把.vue切成三段交给各自的宿主语言去处理,而是自己维护了一个针对 Vue 文件的解析器和语言服务。这带来了一个好处:模板里定义的变量,在脚本里的类型提示也能联动。比如你在script setup里定义了const activeId = ref(1),模板里使用时,Volar 能给出确切的类型推断。这在 Vetur 时代是做不到的。所以如果有人和你说“Vetur 挺好的”或者“Vetur 能格式化那个文件”,多半只是他在舒适区里待久了,并没有真正感受到新工具链带来的效率提升。
最后一次,我给还没动手的你一句实在话:配置这些东西,最大的成本其实就是第一次动手那半小时。一旦你把这套配置通过.vscode/settings.json和.eslintrc沉淀到项目仓库里,之后每个新人克隆下来就直接跑起来,问题少一大半。这会是你这辈子做得最值的一次环境搭建投资。