
1. Vue 3 新项目为什么需要 Prettier ESLint VS Code 三件套刚拉起来的 Vue 3 项目最容易出现的问题不是功能写不出来而是三个人提交的代码像三种风格有人用双引号有人用单引号有人每行 80 字符就换行有人一行写 200 字符有人保存时自动格式化有人手动改缩进。等到 code review 的时候diff 里一半是空格和引号的变化真正的逻辑改动反而被淹没。Prettier 解决的是「风格」问题它不关心你的代码写得对不对只关心长什么样缩进、引号、分号、换行、属性顺序。ESLint 解决的是「质量」问题它关心你有没有用未定义的变量、有没有漏掉key、v-for里有没有写:key、ref有没有被意外解构。VS Code 负责把这两件事串起来让你按一次Ctrl S格式化自动跑、lint 问题自动修不用记命令。这套链路适合谁适合刚用npm create vuelatest或 Vite 拉起 Vue 3 项目、准备拉人一起写的前端。也适合从 Vue 2 迁过来、发现原来那套.eslintrc.js在新版 ESLint 里报FlatCompat错误的同学。我试过在一个 5 人小组里统一这套配置第一周就少了大概 70% 的格式类 review 评论。需要提前说清楚一个坑ESLint 从 v9 开始默认用扁平配置eslint.config.js不再默认读.eslintrc.*。很多老教程还在写.eslintrc.js你照着配会发现 ESLint 根本不生效或者报ESLint couldnt find an eslint.config.(js|mjs|cjs) file。这篇按新版扁平配置来写同时给出 Prettier 与 ESLint 不打架的关键设置。另外格式化链路和 AI 辅助编码其实可以配合。你在 VS Code 里让模型补全代码时补出来的片段风格未必和项目一致但只要保存时 Prettier 接管风格就会被拉回统一。如果你在用 Claude Code 这类命令行 Agent 写 Vue 组件也可以让它走统一的模型入口配置方式我在第 2 节给出和格式化链路互不干扰。2. 前置准备Node 版本、依赖安装与模型入口配置先把环境对齐。Vue 3 Vite 项目建议 Node 18 以上ESLint 9 和 Prettier 3 都要求 Node 18.18。用node -v确认一下低于 18 先升级否则装依赖时会遇到engine不匹配的警告严重时npm install直接失败。依赖分三组装。第一组是 Prettier 本体和它与 ESLint 的桥接npm install -D prettier eslint-config-prettiereslint-config-prettier的作用是关掉 ESLint 里所有和格式相关的规则避免 ESLint 说「这里要加分号」而 Prettier 说「这里不要分号」两边互相覆盖。第二组是 ESLint 本体和 Vue 插件npm install -D eslint eslint-plugin-vue vue-eslint-parservue-eslint-parser是解析.vue单文件组件的关键没有它 ESLint 读不懂template和script setup。第三组是 TypeScript 项目才需要的npm install -D vue/eslint-config-typescript typescript-eslint如果你项目里用了typescript-eslint/parser注意它和vue-eslint-parser的嵌套关系外层用vue-eslint-parser解析.vue内层parserOptions.parser指向 TS 解析器这样script langts里的类型语法才不会报解析错误。接下来是模型入口。如果你打算在写 Vue 组件时用 Claude Code 或类似命令行 Agent 做补全和重构可以把它指向统一的 API 地址这样不用在多个工具里重复填 Key。配置方式是设置环境变量export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKEN你的 API KeyKey 在控制台的 API Keys 页面创建https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentclaude_code_setup如果你用的是 Codex 这类读auth.json的工具配置写在~/.codex/auth.json字段是base_url和api_keyBase URL 同样填https://taotoken.net/api。模型 ID 按你实际要用的填比如claude-sonnet-4-5这类。三件套Base URL Key Model ID缺一不可只填两个最常见的报错就是 401。想先验证模型通不通不用写代码直接在模型对话页面发一句话测试https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel_chat_test这一步和格式化链路是并行的你可以先跳过等第 3 节配置写完再回来补。但如果你团队里有人用 Agent 写代码建议现在就配好避免后面风格不统一时找不到原因。3. 可复制配置.prettierrc、eslint.config.js、settings.json 与 scripts这一节是全文的核心四个文件直接复制到项目根目录对应位置即可。先建.prettierrc放在项目根目录{ $schema: https://json.schemastore.org/prettierrc, printWidth: 120, tabWidth: 2, useTabs: false, semi: false, singleQuote: true, quoteProps: as-needed, jsxSingleQuote: true, trailingComma: none, bracketSpacing: true, bracketSameLine: false, arrowParens: avoid, proseWrap: preserve, htmlWhitespaceSensitivity: css, vueIndentScriptAndStyle: false, endOfLine: auto, embeddedLanguageFormatting: auto, singleAttributePerLine: false }几个容易踩坑的项单独说。endOfLine: auto是为了跨平台Windows 用 CRLF、Mac 用 LF设成auto后 Prettier 保留文件原有换行符不会因为一个人提交就把整个文件标成改动。vueIndentScriptAndStyle: false表示script和style里的内容不额外缩进一层这是 Vue 社区比较主流的写法。arrowParens: avoid让单参数箭头函数不写括号x x * 2而不是(x) x * 2如果你团队习惯带括号改成always即可。然后是eslint.config.js这是 ESLint 9 的扁平配置放在项目根目录import js from eslint/js import pluginVue from eslint-plugin-vue import prettierConfig from eslint-config-prettier export default [ js.configs.recommended, ...pluginVue.configs[flat/recommended], prettierConfig, { files: [**/*.{js,mjs,cjs,vue}], languageOptions: { ecmaVersion: latest, sourceType: module, globals: { window: readonly, document: readonly, console: readonly } }, rules: { vue/multi-word-component-names: off, vue/no-unused-vars: error, no-unused-vars: [error, { argsIgnorePattern: ^_ }] } }, { ignores: [dist/**, node_modules/**, *.min.js] } ]注意prettierConfig必须放在 Vue 插件配置之后否则它关不掉 Vue 插件里那些格式规则。vue/multi-word-component-names关掉是因为很多项目里index.vue、Home.vue这种单词组件名很常见开着会一直报错。argsIgnorePattern: ^_让你用下划线开头的参数表示「故意不用」避免 lint 误报。TypeScript 项目在files里加上**/*.ts并在languageOptions.parserOptions里指定parser: tseslint.parser同时把typescript-eslint的 recommended 配置展开进来。第三个文件是.vscode/settings.json放在.vscode目录下{ editor.formatOnSave: true, editor.codeActionsOnSave: { source.fixAll.eslint: explicit }, editor.defaultFormatter: esbenp.prettier-vscode, [vue]: { editor.defaultFormatter: esbenp.prettier-vscode }, [javascript]: { editor.defaultFormatter: esbenp.prettier-vscode }, [typescript]: { editor.defaultFormatter: esbenp.prettier-vscode }, [json]: { editor.defaultFormatter: esbenp.prettier-vscode }, [jsonc]: { editor.defaultFormatter: esbenp.prettier-vscode }, [html]: { editor.defaultFormatter: esbenp.prettier-vscode }, [css]: { editor.defaultFormatter: esbenp.prettier-vscode }, files.associations: { *.vue: vue }, emmet.includeLanguages: { vue: html }, search.exclude: { **/node_modules: true, **/dist: true, **/pnpm-lock.yaml: true } }editor.codeActionsOnSave里source.fixAll.eslint的值在新版 VS Code 里要写explicit写true会提示已废弃。formatOnSave和fixAll.eslint同时开保存时先跑 ESLint 修复再跑 Prettier 格式化顺序由 VS Code 内部协调实测不会冲突。第四个是.vscode/extensions.json让队友打开项目时收到插件推荐{ recommendations: [ Vue.volar, esbenp.prettier-vscode, dbaeumer.vscode-eslint ] }最后在package.json的scripts里加两条命令方便 CI 和本地批量检查{ scripts: { lint: eslint . --fix, format: prettier --write \src/**/*.{js,ts,vue,json,css}\ } }lint带--fix会自动修能修的format只格式化src下的文件避免误改dist和锁文件。团队里有人不装 VS Code 插件时跑这两条命令也能对齐风格。4. 验证请求保存触发格式化与 lint 修复的完整过程配置写完不验证等于没配。这一节用一个真实的.vue文件走一遍看保存时到底发生了什么。在src/components下新建DemoCard.vue故意写成不规范的样子script setup import { ref } from vue const countref(0) const unusedVar 123 function add(){count.value} /script template div classcard p当前计数{{count}}/p button clickadd加一/button /div /template style scoped .card{padding:16px;border:1px solid #ddd} /style这段代码有三个问题const countref(0)等号两边没空格、function add(){...}大括号没空格、unusedVar声明了没用。按Ctrl S保存观察 VS Code 的行为。保存后第一件事是 ESLint 的source.fixAll.eslint触发它会报unusedVar未使用这个属于逻辑问题ESLint 不会自动删删了可能改变你的意图会在问题面板标红。同时 Prettier 接管格式化把const countref(0)改成const count ref(0)function add(){改成function add() {style里的.card{padding:16px;...}展开成多行。保存后的文件变成script setup import { ref } from vue const count ref(0) const unusedVar 123 function add() { count.value } /script template div classcard p当前计数{{ count }}/p button clickadd加一/button /div /template style scoped .card { padding: 16px; border: 1px solid #ddd; } /style注意import { ref } from vue的双引号变成了单引号{{count}}变成了{{ count }}这些都是 Prettier 按.prettierrc里singleQuote: true和 Vue 模板规则做的。unusedVar还在因为 ESLint 只标记不自动删你需要手动处理或改成_unusedVar让它被argsIgnorePattern忽略。再验证一次命令行。在终端跑npm run lint如果unusedVar还在会看到类似输出/path/src/components/DemoCard.vue 4:7 error unusedVar is assigned a value but never used no-unused-vars把unusedVar删掉或改名_unusedVar再跑一次输出为空说明 lint 通过。接着跑npm run format终端会列出被格式化的文件比如src/components/DemoCard.vue 30ms。如果文件已经符合规范Prettier 会跳过不输出这是正常行为。到这里保存即格式化、保存即修 lint 的链路就通了。你可以故意把.prettierrc里的semi改成true保存后看分号是否加上再改回false确认配置真的在生效而不是 VS Code 用了某个全局默认值。5. 常见报错排查401、local proxy failed、reading choices 与 OAuth配置过程中最容易卡住的不是 Prettier 本身而是模型入口和 ESLint 版本问题。这一节按真实报错逐条对照。报错一401 Unauthorized。出现在你用 Claude Code 或 Codex 调模型时。原因通常是三件套没配全只填了 Base URL 没填 Key或者 Key 填错、过期。检查ANTHROPIC_AUTH_TOKEN是否和 API Keys 页面创建的一致注意不要有多余空格。Codex 用户检查~/.codex/auth.json里api_key字段Base URL 必须是https://taotoken.net/api结尾不要多加/v1加了会 404 而不是 401但表现类似。报错二local proxy failed。这个报错一般出现在工具尝试走本地端口转发时。检查你的环境变量里有没有残留的HTTP_PROXY、HTTPS_PROXY指向一个没启动的本地端口。清掉这些变量再试unset HTTP_PROXY HTTPS_PROXY ALL_PROXY然后重新执行命令。如果你在 CI 里跑检查 CI 的环境变量配置很多 CI 默认注入了代理变量。报错三reading choices of undefined。这是 OpenAI 兼容接口的典型报错出现在返回体结构和代码预期不一致时。常见原因是模型 ID 填错服务端返回了错误对象而不是正常的choices数组。检查你填的 Model ID 是否在可用列表里比如claude-sonnet-4-5这类拼写错误会直接导致这个报错。另一个原因是请求体里stream参数和客户端处理逻辑不匹配关掉流式再试一次能定位。报错四OAuth 相关报错。如果你用的工具默认走 OAuth 登录而不是 API Key会提示需要授权。这类工具要切换到 API Key 模式在配置里找auth_type或类似字段改成api_key然后填 Base URL 和 Key。Claude Code 用环境变量方式就不会触发 OAuth。报错五ESLint 报couldnt find eslint.config.js。说明你项目里还是老配置或者 ESLint 版本低于 9。确认package.json里eslint版本是^9.x并且根目录有eslint.config.js。如果同时存在.eslintrc.js删掉它否则 ESLint 9 会忽略扁平配置。报错六Prettier 和 ESLint 互相覆盖。表现是保存后格式对了但 ESLint 又报格式错误。检查eslint.config.js里prettierConfig是否在数组最后。如果用了eslint-plugin-prettier把 Prettier 当 ESLint 规则跑建议去掉改用eslint-config-prettier分离方案性能更好也不容易冲突。排查完这些你的格式化链路基本就稳了。如果团队里有人用 Cursor.vscode/settings.json同样生效因为 Cursor 基于 VS Code 构建配置目录兼容。Cursor 专属的 AI 规则放.cursor/rules/和格式化配置互不干扰。6. 长期编码与团队协作把格式化链路接进 Agent 工作流单机配好只是第一步团队协作里真正省时间的是把格式化链路和 AI 编码工具接起来。当你在 VS Code 里用 Agent 补全一个 Vue 组件补出来的代码可能用双引号、可能缩进 4 空格但只要保存时 Prettier 接管风格立刻统一。ESLint 则负责拦住 Agent 可能引入的未使用变量、缺失:key这类问题。如果你团队用 Claude Code 做长期编码建议把模型入口固定下来避免每个人各配一套。环境变量方式最简单export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKEN你的 API Key需要长期跑 Agent 任务、频繁调用的场景可以看 Coding Plan 的额度方案https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding_plan接入文档里有各工具的完整配置示例包括 Claude Code、Codex、Cline 这些https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc_integration一个实用技巧把npm run lint挂到 Git 的 pre-commit 钩子上用huskylint-staged只检查暂存区的文件。这样即使有人没装 VS Code 插件提交前也会被拦一道。配置大概是这样{ lint-staged: { *.{js,ts,vue}: [eslint --fix, prettier --write] } }顺序是先 ESLint 修逻辑问题再 Prettier 统一风格。注意lint-staged里不要对dist和锁文件生效否则提交会变慢。最后说一个我踩过的坑.prettierrc里的endOfLine如果设成lfWindows 队友保存后整个文件会被标成改动因为 Git 默认core.autocrlf会把 LF 转 CRLF。设成auto能避免这个问题但更彻底的做法是在项目根目录加.gitattributes* textauto eollf这样无论谁在什么系统上提交仓库里存的都是 LFPrettier 的endOfLine: auto也不会再产生意外 diff。这两处配合跨平台团队的格式问题基本就清零了。