我发现一个很有意思的现象不少开发者私下里写代码干净利落、命名讲究、缩进舒服可一旦进了团队项目代码就“随波逐流”了。有人用 4 空格有人用 Tab有人喜欢单引号有人偏爱双引号还有人提交代码从不跑 lint直接一把梭推到远端。此时你说他有代码洁癖他还不承认但看到别人的代码又忍不住皱眉——这种“间歇性洁癖”的尴尬每个团队都有过。治愈这种“洁癖”靠自觉没用靠文档约束也没用真正管用的是一套自动化工具链ESLint Prettier Husky。它们三个的分工很简单ESLint 负责找出代码里潜在的错误和反模式Prettier 负责把代码格式统一成一种风格Husky 则把前两者的检查卡在 Git 提交之前让不合格的代码根本进不了仓库。这篇文章我从为什么必须有这三个工具讲起再讲怎么把它们的组合拳打到团队项目里每条配置、每个参数背后我都会说清楚当时是怎么想的、踩过什么坑、后来又怎么改的。无论你是刚带团队的技术组长还是想给个人项目建立规范的独立开发者这篇都能直接照着落地。1. 为什么团队代码规范永远不该靠“人治”先说个我早期带项目时的教训。当时团队五六个人开发前我们专门花半天时间整理了一份《编码规范文档》里面写了命名规则、缩进、引号风格、组件命名、文件组织方式甚至连注释怎么写都规定了。文档做得漂漂亮亮评审时所有人都点头第二天照常开发。结果一周后 review 代码我打开某个同事的提交记录几十个文件里至少有四种风格混在一起有的模块用单引号有的用双引号有的解构写了属性名折行有的写在一行里还有一个文件里既有 function 声明又有箭头函数。问为什么没按规范走他说“后来忘了有文档这回事”。这就是问题的本质靠人记住规则、靠人逐行检查是在跟人性作对。代码规范最大的需求时点是 review 那一刻而不是写代码那一刻。等到评审时再纠正风格、挑错漏其实已经晚了——上下文早切换走了看几十个文件的差异化需求本来就烦再揪着换行、空格这种鸡毛蒜皮说事评审变成互相消耗。规范的真正价值应该是让工具在写代码的过程中自动修正让评审只关注设计逻辑和业务实现。最早我只上了 Prettier因为它“少废话”save 之后自动格式化缩进引号分号统统搞定。但后来发现不够Prettier 只管排版和格式它不管const被重新赋值这种逻辑隐患不管函数里是不是有声明了却没用的变量更不管你是不是误用了而不是。这些典型错误恰恰是最容易在代码评审里抓耳挠腮的。于是才出现那个经典组合ESLint 管代码质量Prettier 管代码格式Husky 管时机。你可能会问ESLint 不是也可以分号缩进这些吗它们没有重叠吗有重叠而且特别容易打架。但恰恰是这种重叠促成了现在成熟的技术方案——用 ESLint 做规则判断、Prettier 做风格美化再通过工具让它们各管一段互不抢活。这个我们放到第 3 节详细说这里先记住一个核心判断你缺的从来不是“一套规则”而是“自动落实规则”的机制。2. 三者职责边界一句话讲清谁干什么很多新人第一次接触这套东西时最容易问的问题是“ESLint 不是也能报缩进不对吗Prettier 不是也能去掉分号吗为什么两个都要装”这个问题的背后是不理解三者的职责边界。我尽量用一句话概括ESLint 管的是“代码写错了没有”有没有定义不用的变量、有没有不经判断就访问深层属性、有没有在循环里给条件变量赋值、有没有用。它能发现逻辑层面的隐患也能通过规则约束你写出更规范的代码。Prettier 管的是“代码看着顺不顺眼”字符串用单引号还是双引号、缩进是 2 还是 4、对象换行时要不要尾逗号、单行超过多少个字符自动折行。它是一门纯纯的美容课几乎不碰逻辑。Husky 管的是“时机”把上面两个检查挂到 Git 的 hook 上比如pre-commit、pre-push让你的代码在提交之前先过一遍安检过不了就不许上车。为了更好理解你可以把这三样代入到一个现实场景假设你们团队是合租的室友厨房就是公共仓库。ESLint 是“食品安全员”看食材是不是过期了、会不会让人吃坏肚子Prettier 是“收纳师”规定碗筷怎么摆、调料怎么排Husky 是“门禁大爷”每次都卡在门口你还没收拾完就不准出去。这不是三选一而是三个不同层的东西叠加在一起才是完整的递进检查。有人会反驳“那我只用 Prettier 不行吗代码整洁不也挺好看的”当然行但你只能解决“眼睛受不受得了”的问题解决不了“跑起来会不会炸”的问题。代码风格是感官问题而逻辑隐患是运行期问题后者远比前者严重。这里也有个很多人忽视的点ESLint 虽然能力大但它也能干一部分格式的事比如indent规则、quotes规则它就管得了。而 Prettier 干不了逻辑检查它只做纯输出格式化。所以就出现了老生常谈的建议——让 ESLint 和 Prettier 各司其职把 ESLint 里跟“风格美观”相关的规则关掉或者统一交给 Prettier 去管。这样你的团队规则才有一个主心骨不会一会儿听 ESLint 的一会儿被 Prettier 改回去。3. 实操配置从零开始搭一套能直接用的工程化规范体系下面我们进入实操环节。为了不让大家看了一堆概念但不知道怎么落地我直接带你从零搭建一个前端项目的基础规范体系。使用的技术栈不绑定特定框架以 JavaScript 项目为例稍加改动就能适配 Vue / React / TypeScript。3.1 初始化项目与核心依赖首先创建一个新的项目目录或者直接在现有项目里操作。如果你是从零开始mkdir eslint-prettier-husky-demo cd eslint-prettier-husky-demo npm init -y然后安装核心依赖包。这里我按角色的不同把依赖分开方便你理解每个包的作用# ESLint 本体 npm install eslint --save-dev # Prettier 本体 npm install prettier --save-dev # Husky 本体用于挂 Git hooks npm install husky --save-dev # lint-staged让检查只跑暂存区的文件不浪费全量时间 npm install lint-staged --save-dev如果你的项目使用了 TypeScript还要额外装 TypeScript 解析器ESLint 官方现在推荐用typescript-eslint这个包npm install typescript typescript-eslint --save-dev别小看lint-staged这个包后面你会发现它才是保证整套方案“不卡速度”的关键。没有它每次提交前都 lint 全仓库的文件项目一大一次提交等个十几秒甚至半分钟同事早就把 Husky 卸载了。3.2 ESLint 配置规则怎么选才贴合团队现状说完安装重点说配置。ESLint 的配置文件承载了规则体系它决定了什么样的代码会被提示什么样的模式会被放行。不同时期 ESLint 的配置风格有点不一样老项目用.eslintrc.jsESLint 9 之后官方推荐eslint.config.jsFlat Config新项目建议直接用新的。这里我以常见的 JavaScript 项目为例用新版 Flat Config 写法// eslint.config.js import js from eslint/js; import prettier from eslint-config-prettier; export default [ { ignores: [dist/**, node_modules/**], }, js.configs.recommended, { files: [**/*.js], languageOptions: { ecmaVersion: latest, sourceType: module, globals: { window: readonly, document: readonly, console: readonly, }, }, rules: { no-unused-vars: [warn, { argsIgnorePattern: ^_ }], eqeqeq: [error, always], curly: [error, all], semi: off, }, }, prettier, ];这几个规则背后是有讲究的我挨个说说no-unused-vars声明了却没用的变量多数是重构残留或者手误。这里我没有设成 error而是 warn。原因是在开发过程中临时注释掉一段代码变量暂时用不上很常见如果直接 error编辑器直接标红脑内会形成一种“我非得停下手来改”的压迫感。对新手团队先从 warn 开始更容易接受对成熟团队可以改 error。eqeqeq强制全等比较那必须是用和!。本身是历史包袱它会做隐式类型转换比如1 1是 true容易埋雷。curly强制 if 和循环都要带花括号。不然你会看到if (x) doSomething()这种写法后续加代码很容易踩坑。semi这里设成 off是因为分号这活儿我全交给 Prettier 管了ESLint 不掺和。重要的是prettier这个配置它来自eslint-config-prettier包作用是禁用掉那些跟 Prettier 冲突的 ESLint 规则——比如quotes、indent这类。否则可能发生这样的事Prettier 刚把单引号改成双引号ESLint 又报“应该用双引号”两个工具来回拉扯最后只能注释禁用 ESLint 规则丧失质量检查能力。注意早期版本的配置里还要手动把prettier/react、prettier/typescript加上现在eslint-config-prettier已经合并成一层直接加一个prettier就行。3.3 Prettier 配置风格统一的关键参数Prettier 的配置相对简单因为它没那么多规则主要就是几个风格选项。我在.prettierrc文件里只挑必要几项写其余用默认值这也是我的一个经验——Prettier 配置写太多反而会让团队争论不休少即是多。{ printWidth: 100, tabWidth: 2, useTabs: false, semi: true, singleQuote: true, trailingComma: all, arrowParens: always, endOfLine: lf }解释一下这几个参数printWidth单行最大长度。默认 80 对现代显示器来说太窄100 比较均衡既不会频繁折行也不会因为太宽导致侧向滚动。useTabs和tabWidth我用空格宽度 2。这个其实团队里常吵有人觉得 Tab 好有人觉得空格好但作为默认方案空格 2 是社区接受度最高的组合。semi跟 ESLint 配置里那条semi: off对照看。这里我设成了 true即要分号。如果你团队都喜欢无分号风格可以改 false但要记住 ESCLint 那条semi必须保持 off因为 Prettier 会自己处理。singleQuote单引号。在 JS 社区里已经形成主流偏好字符串里碰到也可以自动转义问题不大。trailingComma尾逗号。all 表示多行结构末尾加逗号好处是 git diff 时只新增一行不会连带上一行一起被标记为变更。arrowParens箭头函数参数是否加括号。always代表(x) {}avoid则单参数时不加括号。我选 always因为加括号后更利于后续补参数且与 TypeScript 代码风格统一。3.4 Husky 挂载与 lint-staged 配置让检查发生在正确时机工具装好配置写好剩下的问题是怎么让它们在提交前自动触发。如果你直接把npm run lint挂到pre-commithook 上在小型项目里可行但项目稍大就会遇到性能问题每次提交只改了两三个文件却要全量检查上百个文件的 lint白白等待不说还会因为历史遗留代码里没有修掉的 lint 报错导致新手根本无法提交代码。这时候lint-staged登场了。它的逻辑很简单只处理git add暂存区的那些文件。先建.lintstagedrc文件{ *.js: [eslint --fix, prettier --write], *.jsx: [eslint --fix, prettier --write], *.ts: [eslint --fix, prettier --write], *.tsx: [eslint --fix, prettier --write] }这样当你提交时它会抓出暂存区里的 js / jsx / ts / tsx 文件先把 ESLint 的自动修复跑一遍再用 Prettier 排版一遍两轮下来等 check 通过这些文件已经是干净、统一、无逻辑错误的版本。然后是 Husky 挂载脚本。安装 Husky 后先初始化npx husky init这个命令会在.husky/目录下生成一个pre-commit示例文件。打开后修改为# .husky/pre-commit npx lint-staged如果你想在git push之前也做一次全量检查可以再加一个pre-pushhook但根据我的实测经验如果团队已经有 CI 跑单测和 lintpre-push 再全量跑一遍会拖慢提交流程体验不算好这个看团队取舍。注意Husky 8 以前的版本要求先配置husky install但新版本的husky init一步到位同时会自动改package.json里的scripts把prepare脚本加进去。如果你用旧教程操作经常会漏掉这步导致新同事npm install后 hooks 没生效。3.5 package.json 脚本全流程跑通所有配置完成后别忘了在package.json里加几条顺手好用的脚本{ scripts: { lint: eslint ., lint:fix: eslint . --fix, format: prettier --write . } }安装完成后你可以试一下效果npm run lint:fix npm run format正常的情况下代码里格式问题自动修复逻辑问题按照规则报错或告警。接着git add .再git commit预提交检查自动跑起来。如果 lint 没通过提交会被堵住除非你去掉暂存或手动跳过 hook。这里要特别提醒尽量让提交前那步有“仪式感”。新手第一次被 Husky 拦截时可能会有情绪但你要解释清楚——它挡住的不是“你”而是“有问题的代码”。没有这个机制就等于把质量防线全部寄托在人的自觉上迟早有一天会出乱子。4. 解决 ESLint 与 Prettier 的冲突核心认知与常见坑我第一次把 ESLint 和 Prettier 同时配置好的时候最直观的感受是“怎么老是来回打架”。比如 Prettier 默认会去掉分号但我把 eslintsemi设成 error那 Prettier 刚格式化完ESLint 立刻报“缺少分号”。这种体验极差团队里反应最快的人立马说“这两个工具有冲突别都装了。”这种冲突属实但早有成熟解法关键在于理解各自的职责和控制层级。先说说为什么会有冲突。ESLint 原生包含两套规则逻辑规则和格式规则。逻辑规则负责找 bug格式规则负责规范排版。而 Prettier 是一个“单输出”的格式化器它不管你以前的代码习惯只要你指定了某个风格它就把该风格贯彻到底。两者都想管格式规则细节却不一致自然就打起来了。行业里通行的解决方案是三层配置叠加让 Prettier 成为唯一的格式标准。用eslint-config-prettier关闭所有与 Prettier 冲突的 ESLint 规则。ESLint 聚焦于代码质量规则比如no-unused-vars、eqeqeq、no-else-return等。我在实际过程中还踩过一个更隐蔽的坑有些同事在编辑器里装了 ESLint 插件和 Prettier 插件且两个插件都开了“保存时自动修复”。结果一按 CmdSPrettier 刚把引号统一ESLint 又把它改回去再保存一下ESLint 改完Prettier 又不同意见。整个编辑过程像弹钢琴光标疯狂跳动。这块的修复方案是在编辑器里只让 Prettier 承担格式化让 ESLint 承担代码校验不要两边抢同一个活。具体在 VS Code 里settings.json的配置应该是{ editor.defaultFormatter: esbenp.prettier-vscode, editor.formatOnSave: true, editor.codeActionsOnSave: { source.fixAll.eslint: true } }这样设置的意思是保存的时候先用 Prettier 把格式统一然后再用 ESLint 的--fix规则修逻辑问题。两者分工明确不会互相覆盖。如果你在配置后运行eslint .还遇到报错比如“Delete␍”或者“Replacewith”多半是endOfLine和quotes这两类配置没有完全交给 Prettier要么是eslint-config-prettier没有正确加载要么是你上了额外的plugin:prettier但又没统一好。遇到这类情况优先检查配置文件的依赖顺序。还有一个大坑是很多人把 Prettier 的规则写进 ESLint 的rules里用eslint-plugin-prettier让 ESLint 直接运行 Prettier 并报错。这种方案看着简单但它让 ESLint 每个文件都先解析再格式化性能开销大而且 ESLint 很多代码修复是基于文本补丁的在它里面嵌一个格式化器编辑器里容易闪烁。我个人的建议是如果你追求性能稳定就别用eslint-plugin-prettier直接分两个工具跑。让 Prettier 输出格式化结果ESLint 独立检查格式化后的代码两者通过eslint-config-prettier关掉冲突规则即可。这已经成为近两年社区里大部分团队的做法实战验证过问题很少。5. Husky 失效排查八成是安装方式或权限问题Husky 在整个组合里属于“卡口”角色它失效了前置检查就成了空话。很多同事反馈“我配了 Husky怎么提交时没反应”经过排查大多数情况不出这三个原因。第一.git目录在项目根目录之外。Husky 通过 Git 的core.hooksPath来指定 hooks 目录位置它默认指向.husky/_。如果你把.git放在外层比如 monorepo 的某个子包安装时没在 Git 根目录执行Husky 找不到 Git 上下文自然挂不上。解法是执行git rev-parse --git-dir确认目录再在正确的 Git 根目录重跑npx husky init。第二package.json里的prepare脚本缺失。Husky 的自动关联依赖 npm 的prepare脚本prepare: husky。当某个同事从 Git 拉取项目后执行npm installprepare就会跑一遍并完成 hooks 的本地安装映射。一旦这个脚本缺失新同事的机器上 hooks 就不会生效但他自己毫不知情。早期的教程往往不会特意强调这步我在这里多说一句后面能省很多排查时间。第三hook 脚本本身没有执行权限。少数情况下.husky/pre-commit文件是存在的但ls -l看权限位没有x权限。这在跨平台同步或者文件复制时容易发生直接在.husky目录下执行chmod x .husky/pre-commit .husky/pre-push第四Windows 环境下用某些编辑器保存 hook 文件时文件编码被改成了带 BOM 的 UTF-8或者换行符变成了 CRLF这会让 bash 解析出错。最好的排查方式是直接在命令行里手动执行sh .husky/pre-commit看报什么错大多能一眼定位。还有一个隐藏问题如果你把npx lint-staged写进了 pre-commit但它本身没有安装那每次提交都会卡在npx交互式询问“是否安装包?”这一步。经验是在项目里把lint-staged安装到 devDependencies确保npx能在本地找到而不是临时下载。最后提一个团队协作上的注意事项不要让新人自己摸索这套工具的配置。我给团队做 Onboarding 时通常会在 README 里直接写明“提交前自动检查已配置不要跳过 hooks”。因为有些人第一次提交被拦截后第一反应是git commit --no-verify跳过后面每次都顺手跳过等于整套机制形同虚设。这属于流程问题不是技术问题可以在团队规范里从约定层面解决。6. 规则落地与团队推广如何让“工具强约束”不招人反感一套配置搭好只是工程化规范开始的第一步。很多团队最终没坚持下来不是因为工具本身不好用而是在推广和执行上出了问题。我曾经在一个团队里强行把no-console设为 error结果同事们在很多需要调试日志的场景下只能写// eslint-disable-line no-console代码里充斥着禁用的注释review 时更难读。后来我反思规则的价值在于服务团队不是服务规则本身。对no-console这种规则更合理的做法是设成 warn或者直接允许console.warn/console.error只要禁止console.info/console.debug这种滥用即可。所以关于如何让工具不被反噬我自己的经验是渐进式引入不搞“一刀切”。如果仓库里有大量历史代码是旧的风格直接一刀切把规则全部打开全仓库飘红同事会崩溃。做法是先用ignorePatterns把老代码目录排掉或者规则先从warn开始跑一段时间等大家消化掉再切error。规则数量宁少勿多。一个刚引入工具链的团队最忌讳堆几百条规则每写一行代码都被规则挑刺。先把最核心的 bug 潜在项和风格统一项配上跑一个月后再慢慢迭代。尽量避免在代码里频繁写 eslint-disable 注释。一旦发现先反思是不是规则本身不合理。如果合理要不要调整逻辑结构合理的规则应该让你写不出坏代码而不是让你对着报错写屏蔽注释。重大规则变更先去群里同步不要悄悄改配置。我曾经在周四下午加了一条no-param-reassign结果同事周五提交时十几个文件被断住气氛一度很紧张。后来我改到规则变更前先在群里发个通知说明从哪个时间点开始生效给同事留出预留时间。另外关于editorconfig我建议顺手也加一份。虽然它跟 ESLint / Prettier 不是一回事但它能统一编辑器的基础行为比如缩进、换行符、自动插入末行空行对跨操作系统开发尤其重要。否则你在 Mac 上开发的代码到了 Windows 同事那边可能每行末尾的 CRLF 差异就够 Prettier 喝一壶了。这里放一个基础.editorconfig示例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我说过这事很多次再重复一遍配置规范的工具真正的敌人不是工具太复杂而是团队对“约束”的天然抵触。ESLint 和 Prettier 只是把“规则”从文档里搬到代码里、从人的记忆里搬到自动检查里它改变的是执行机制不是团队自由。少了机制代码质量全靠自觉有了机制瑕疵在提交前就被拦截大家反而省心。7. 各类型项目适配技巧React / Vue / Node哪里要改哪里要加到这里你已经知道怎么配置一套基础方案。但现实中的项目不全是纯 JavaScript不同技术栈有各自的规则和插件下面我给几种常见场景列一下适配要点。7.1 React 项目React 项目里最常出问题的点是 hooks 依赖数组、未解构的 props、key 缺失、aria 无障碍属性缺失。你可以安装 React 官方的 hooks 插件npm install eslint-plugin-react-hooks --save-dev然后在eslint.config.js加import reactHooks from eslint-plugin-react-hooks; // 在配置数组里新增 { plugins: { react-hooks: reactHooks }, rules: { react-hooks/rules-of-hooks: error, react-hooks/exhaustive-deps: warn } }这里exhaustive-deps我故意用 warn 而不是 error原因在于它经常会因为某些闭包场景误报或者要求补依赖真实业务里有些“效应”不需要每次依赖变化都触发。设成 warn 不至于卡提交流程但能留个提示。7.2 Vue 项目Vue 项目需要用到eslint-plugin-vue它给 Vue 单文件组件里的模板部分也提供了规则支持。安装后配置里加npm install eslint-plugin-vue --save-devimport vue from eslint-plugin-vue; export default [ ...vue.configs[flat/recommended], { rules: { vue/multi-word-component-names: off, vue/max-attributes-per-line: off } }, prettier ]我关掉vue/multi-word-component-names的原因很实际——业务项目里大家常用Home.vue、About.vue这种单文件命名强制多单词反而会逼出无意义的命名。而vue/max-attributes-per-line这种纯格式规则交给 Prettier 管就好。7.3 Node.js / 后端服务Node 项目的特点是不涉及 DOM不需要window/document之类的全局变量。如果你的目标是 Express 或 Koa 项目通常需要额外的eslint-config-airbnb-base里的一些逻辑规则但那个包越来越厚重。我更推荐自己按需从 recommended 里扩展只在需要时添加globals: { process: readonly, Buffer: readonly, __dirname: readonly, }如果你用的是 Node 内置的fetch或者某些新特性也要在globals里补否则 ESLint 会报“xxx is not defined”。这类报错看起来很冤枉要留意。7.4 TypeScript 项目TS 项目的配置最容易被文章带偏。很多老教程让你把typescript-eslint/no-explicit-any设为 error这在纯内聚的 TS 项目里合理但在快速迭代的业务项目里会频繁“打扰”。我的做法是warn除非你团队有充足人力去处理 everyany。另一个容易踩点的是 TS 跟 ESLint 的 parser 配置。ESLint 8 之后的配置写法比较灵活但核心是把parser换成tsParser。在新版 Flat Config 里用typescript-eslint提供的配置即可不用自己再拼 parser 了。import tseslint from typescript-eslint; export default [ ...tseslint.configs.recommended, { rules: { typescript-eslint/no-explicit-any: warn, typescript-eslint/no-unused-vars: [error, { argsIgnorePattern: ^_ }] } } ]我第一次在 TS 项目里配置这套时由于没有按 Flat Config 新方式组织费了不少时间在parserOptions和project上做文章。新版工具链让这一切简单很多如果你不是维护老项目尽量直接用新版推荐方式。8. 从“能跑”到“好用”几个提升体验的细节配置很多人按照教程配置完工具能用但用起来还是不够顺手这里再分享几个提升日常体验的细节。一是把 lint 结果集成到编辑器。VS Code 里装 ESLint 和 Prettier 两个插件这条前面讲过不再展开。再补充一个细节如果你团队有人用 JetBrains 系 IDE比如 WebStorm / IntelliJ IDEA需要在 Settings 里开启Run eslint --fix on save跟 VS Code 的 codeActionsOnSave 对应上。二是设置lint-staged命令时不要漏掉配置文件自身。比如你的 skeletion 里还加了.prettierrc、eslint.config.js、.editorconfig这些文件建议把*.json、*.config.js也纳入 Prettier 的格式化范围{ *.{js,jsx,ts,tsx,json,css,md}: [prettier --write] }否则 review 时常常看到配置文件缩进乱七八糟虽然不影响运行但很影响观感。三是一些项目用到了自定义的目录别名比如/utilsESLint 解析 import 路径时可能报“unresolved import”。这是一个特别常见的误报场景。你可以安装eslint-import-resolver-alias或者在配置里设置解析器让 ESLint 理解别名而不是用 disable 注释压掉。四是在 CI 流程里也跑一次 lint。Husky 能拦住绝大多数提交但总有绕过 hooks 的可能。在流水线里加一步npm run lint让服务端也检查一遍才算双保险。注意这一步建议只做质量规则检查不要带--fix因为 CI 环境里改了文件也没法提交。9. 当代码洁癖遇上工具我的真实体会回到开头那个“代码洁癖”的话题。我以前以为自己洁癖是因为看不惯乱代码后来接触的人多了才明白大多数人不是真的洁癖只是缺少一套“让人很放心”的自动化机制。你让工具替你盯住没用的变量、替你把引号统一、替你在提交前卡住不合格代码心里那块最焦虑的地方反而松弛了。我见过有些开发者抗拒这套工具链理由是“这么多工具会不会限制我写代码的自由”。实际用下来这种担忧是不必要的。ESLint 规则里所有不合理的项都可以配置成 offPrettier 风格也可以按团队习惯改。真正的自由来自稳定的基线——当你不用再为了争论缩进和引号消耗精力你才有更多时间放在设计模式、业务抽象和代码优化上。关于“团队标准化”这件事我有几个最后想叮嘱的配置规则的时候记得先问“这个规则能拦住怎么样的 bug”而不是“这个规则看起来炫酷”。如果一条规则在团队里三个月都没有触发过考虑把它关掉减少噪音。提交提示信息很重要。在.husky/pre-commit里增加一段简单提示让被拦截的同事知道为什么被拦、下一步去哪里看。比如# .husky/pre-commit echo Running lint-staged... npx lint-staged不用追求一次把 ESLint、Prettier、Husky、EditorConfig、lint-staged 全部配置到完美。这个组合里最核心的三角是 ESLint Prettier Husky先让它跑稳再慢慢加别的。我自己在多个团队里过手这套配置体会最深一点是工具本质上是团队的一次自我约束。它不解决所有代码质量问题也替代不了 code review但它能把低级问题挡在门外让 review 少做“垃圾清理”专心做“价值判断”。这一条就值回所有学习成本了。