根本原因是ESLint与Prettier职责未分离,必须禁用ESLint所有格式规则、关闭其自动修复、显式指定Prettier为默认格式化器,确保仅Prettier执行保存时格式化。

为什么保存后代码反复被改、波浪线闪个不停
根本不是 Prettier 或 ESLint 有 bug,而是两者都在抢着改同一行代码:ESLint 看到 const a = 1 就报 “Missing semicolon”,Prettier 格式化后变成 const a = 1;,ESLint 缓存没刷新,又立刻标红——这不是冲突,是职责没划清。
Node 环境下尤其明显,因为 eslint-plugin-node 和 @typescript-eslint(若用 TS)常自带格式类规则,而 Prettier 默认不读 .eslintrc,只认 .prettierrc 或 package.json 里的 prettier 字段。
- 典型现象:
quotes、semi、comma-dangle报错但格式化后又出现 - Node 项目常见于
require()写法、__dirname使用、CommonJS 模块导入场景,ESLint 的node/no-unsupported-features等规则本身不冲突,但和格式规则混在同一个配置里就容易误触发 - 关键陷阱:很多人以为装了
eslint-config-prettier就万事大吉,结果它被写在extends数组中间,被前面的plugin:node/recommended覆盖掉了
必须把 prettier 放在 extends 最后一行
eslint-config-prettier 不是“加个插件就行”,它是靠顺序覆盖来关规则的——它得在所有其他配置之后执行,才能把前面开的 indent、quotes 等规则真正关掉。
错误写法:["plugin:node/recommended", "prettier", "eslint:recommended"] → eslint:recommended 在最后,又把分号、引号规则打开了
正确写法(Node + Prettier 共存):
module.exports = {
extends: [
"eslint:recommended",
"plugin:node/recommended",
"plugin:prettier/recommended",
"prettier" // 这行必须是最后一个
],
rules: {
"prettier/prettier": "error"
}
};
-
plugin:prettier/recommended是可选但推荐的,它会启用eslint-plugin-prettier并把 Prettier 错误转成 ESLint 提示 - 删掉所有手动写的格式规则,比如
"semi": ["error", "always"]或"quotes": ["error", "single"],留着就是埋雷 - Node 项目如果用了
eslint-plugin-import,也要确认它的import/order规则不和 Prettier 的printWidth打架——后者可能折行,前者却要求按字母序排列,这种属于逻辑+格式混合规则,建议关掉或用eslint-config-prettier的子集eslint-config-prettier/import
VSCode 设置里只留一个格式化入口
VSCode 不会自动协商谁来格式化,它只按设置顺序执行。如果 eslint.autoFixOnSave 和 editor.formatOnSave 同时开,等于让两个人同时拿笔改同一张纸。
必须做的三件事:
- 关掉
eslint.autoFixOnSave(设为false),让 ESLint 只报错、不修 - 开
editor.formatOnSave(设为true) - 明确指定
editor.defaultFormatter为esbenp.prettier-vscode,不能是空,也不能是dbaeumer.vscode-eslint
额外注意:Node 项目常带 .js 和 .cjs 文件,VSCode 默认对 .cjs 不触发 Prettier,需在设置里补上:
"files.associations": {
"*.cjs": "javascript"
}
否则 require('./config.cjs') 这类文件永远不被格式化,ESLint 却照常检查,看起来就像“部分文件不生效”。
.prettierrc 和 .eslintrc 规则对不上怎么办
不是配置文件写错了,而是 VSCode 没读到你写的那个 .prettierrc。Prettier 在 Node 环境下优先级链条是:package.json 中的 prettier 字段 > 项目根目录 .prettierrc > .prettierrc.json > .prettierrc.yml,而 VSCode 插件默认只读第一层。
最稳做法:把 Prettier 配置直接塞进 package.json,避免路径/扩展名歧义:
"prettier": {
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"printWidth": 80,
"endOfLine": "lf"
}
- Node 项目慎用
endOfLine: "crlf",Windows 上 Git 会自动转lf,导致 Prettier 每次保存都报“line endings differ” -
printWidth设太小(如 60)会让 Node 的长路径path.join(__dirname, 'src', 'utils', 'helpers.js')被强行折行,ESLint 的max-len规则又可能报错,干脆关掉或设为 100 - 如果团队用
npm run lint命令校验,确保脚本里调用的是eslint --ext .js,.cjs src/,而不是漏掉.cjs后缀——否则 CLI 和 VSCode 行为不一致,你会觉得“本地好好的,CI 上挂了”
no-unused-vars、no-undef 这类真问题,Prettier 的格式化不再被干扰。真正的难点不在配置本身,而在确认每层配置是否真的被加载——VSCode 设置、项目配置、CLI 命令、Git Hook,四者规则必须完全对齐,缺一不可。


















