导致“保存→格式化→再次保存”死循环的插件主要有Prettier、ESLint(尤其启用eslint.codeAction.onSave)、TypeScript(node_modules巨大时)、Vetur/Volar及Python扩展(如black未安装),它们在onWillSaveTextDocument钩子中隐含二次写入或事件重发,配合缺失配置(如缺.eslintrc)会触发静默循环。

哪些插件会触发保存时的无限循环
真正导致“保存→格式化→触发代码操作→再次保存→再格式化”死循环的,基本就集中在几类注册了 onWillSaveTextDocument 或 onDidSaveTextDocument 钩子的插件:Prettier、ESLint(尤其启用了 eslint.codeAction.onSave)、TypeScript(当 js/ts.preferences.includePackageJsonAutoImports 开启且 node_modules 巨大时)、Vetur/Volar(Vue 文件中 template/script/style 交叉解析失败)、Python 扩展(python.formatting.provider 设为 black 但 CLI 未安装或返回非标准输出)。它们不是单纯“慢”,而是响应逻辑里隐含了二次写入或事件重发。
用开发者工具一眼锁定循环源头
别靠猜,VSCode 控制台能直接暴露循环调用栈:
- 按
Ctrl+Shift+P→ 运行Developer: Toggle Developer Tools,切到Console标签页 - 清空日志,再按
Ctrl+S保存一次 - 重点盯住重复出现的
onWillSaveTextDocument日志,尤其是同一扩展名(如vscode-eslint)连续打出 3 次以上 - 若看到
Promise never resolved或Maximum call stack size exceeded,基本就是某插件在钩子里又调了editor.edit()或触发了自身监听器
注意:eslint.format.enable 和 prettier.requireConfig 同时开启但项目缺配置文件时,ESLint 插件可能 fallback 到内部默认规则并反复尝试加载,形成静默循环。
绕过循环但保留关键功能的配置组合
关掉所有自动操作太粗暴;精准降级才是稳定解法:
- 把
editor.codeActionsOnSave改成{"source.fixAll": "explicit"}:只在手动触发 Source Action 时修复,保存时不跑 - 禁用
editor.formatOnSave,改用editor.formatOnType+ 手动Shift+Alt+F:避开保存钩子链,又能保格式化体验 - 对 Vue/TSX 等易出问题的文件类型单独设配置:
"[vue]": { "editor.codeActionsOnSave": {} },避免 Volar 把<template></template>解析结果误当 JS 再送进 Prettier - 确认
typescript.tsserver.experimental.enableProjectDiagnostics为false:防止语言服务在保存瞬间扫描整个node_modules并触发重载循环
为什么禁用插件后仍可能循环
即使你已禁用 Prettier 和 ESLint,循环仍存在,大概率是以下两个隐藏路径在作祟:
- 工作区
.vscode/settings.json里残留了"editor.codeActionsOnSave"的全局启用项,它会覆盖用户设置,且不随插件禁用而失效 - 某些插件(如 GitLens)虽不主职格式化,但注册了
onDidSaveTextDocument并在回调里调用了git.add()→ 触发 VSCode 内置 Git 扩展的保存监听 → 再次进入钩子链
最稳妥的做法:打开命令面板 → Preferences: Open Workspace Settings (JSON),删掉所有 codeActionsOnSave、formatOnSave 相关字段,再重启窗口。循环是否消失,就看这一行干不干净。


















