资讯详情

前端工程化实战:用husky+lint-staged实现Vue项目提交即合规

📅 2026/10/13 3:15:45 | 华诺云谱 👁 阅读
前端工程化实战:用husky+lint-staged实现Vue项目提交即合规
干过几年前端带过项目的朋友大概率都有过这种体验Code Review 的时候群里热热闹闹结果点开评论区一看一半以上都在说“这里多了个空格”“引号改成单引号”“这个缩进不对”。真正该被盯住的业务逻辑、边界条件、异常处理反而被淹没在格式琐事里。我们项目组前段时间把这个问题彻底解决掉了——用一套自动化前端工程化方案把 ESLint、Prettier、Stylelint、husky、lint-staged、commitlint 串起来从源头拦截不规范代码让 Vue 项目真正实现“提交即合规”。这套东西落地之后CR 的讨论质量肉眼可见地上了一个台阶大家开始认真聊状态管理怎么拆、接口异常怎么兜底、路由权限有没有漏洞。本文就把这套方案的选型思路、配置细节、踩坑记录完整摊开希望能给被 Code Review 格式问题折磨的团队一个可抄的作业。1. 为什么 Code Review 不该管格式以及自动化能带来什么1.1 先算一笔“人盯格式”的成本账很多团队不是不想管格式是真的管不过来。一个 20 人左右的前端组每周 merge request 数量大概在 60 到 100 个之间。假设每个 MR 里有 3 到 5 处格式问题评审人平均要花 5 到 10 分钟去指出这些琐碎错误。算下来每周光浪费在“纠格式”上的人力就是 5 到 15 个小时一年就是几百个小时。这笔时间放在任何业务上都是不小的成本。更麻烦的是人的状态。评审人反复说“这里格式不对”时间长了会形成惯性疲惫看见不规范的代码甚至懒得说了。写代码的人则觉得“能用就行你咋这么较真”两边都不愉快。格式检查这种 100% 可以机器化、确定性的规则压根不应该占用人的注意力。那为什么不干脆只靠 Lint 插件在编辑器里提示因为编辑器提示依赖个人自觉很多同事根本没装插件或者装了也不看黄色波浪线还有一批人用 WebStorm、VS Code 混着来配置都不一样。只要“提交”这个动作不设卡问题代码必然流到 CR 阶段。1.2 自动化检查的三个层次与“提交即合规”的含义所谓“提交即合规”不是口号而是把检查点前移到 Git 提交之前形成三道防线第一道防线是编辑器实时提示这个靠 EditorConfig VS Code 插件体验友好但不是强制手段。第二道防线是 Git 提交钩子用 husky 在 pre-commit 阶段跑 lint-staged只检查本次改动的文件。第三道防线是 CI 流水线里的全量检查防止本地钩子被绕过也保证合并到主干之前代码始终是干净的。这三道防线里最关键的是第二道。它把“提交”这个动作变成了一道闸门代码不合规根本提交不上去自然流不到 CR。第三道是保险CI 里再跑一遍全量检查就能覆盖那些本地跳过钩子的情况以及合并后出现的交叉污染。我个人的体会是“提交即合规”最妙的地方在于它把责任前置了。以前是评审人发现问题打回开发者再改一版一来一回经常隔上一天。现在是写代码的人提交前机器就告诉他哪里不行改完再提交整个过程可能就多花 30 秒。团队的摩擦成本低了一大截。2. 方案选型为什么是 husky lint-staged ESLint Prettier 这套组合2.1 各工具职责边界与组合优势很多人刚开始搞前端工程化的时候容易把 ESLint 和 Prettier 搞混觉得它们都是检查代码格式的随便挑一个就行。这是本方案里最大的认知误区。ESLint 管的是“代码质量规则”比如未使用的变量、隐式类型转换、危险的全局变量、Vue 组件里的命名规范Prettier 管的是“代码排版风格”比如行宽、缩进、分号、引号。二者有重叠但定位完全不同。可以用一个类比来理解ESLint 是交警查的是违章行为Prettier 是洗车行管的是外观整洁。违章和外观都重要但不是一个部门的事。工具链的具体分工如下工具定位负责内容典型规则示例EditorConfig编辑器基础风格缩进、换行符、字符集indent_style spaceESLint代码质量检查语法错误、未使用变量、Vue 规范no-unused-vars, vue/multi-word-component-namesPrettier代码统一排版单双引号、行宽、分号、括号换行semi: false, singleQuote: trueStylelint样式规范检查CSS/SCSS 语法、属性顺序、颜色值color-no-invalid-hexhuskyGit 钩子管理在 commit 前自动触发脚本pre-commit, commit-msglint-staged增量检查工具只对暂存区文件执行命令*.vue, *.js, *.csscommitlint提交信息规范校验 commit message 格式type-enum, subject-min-length这套组合里最难替代的是 lint-staged。如果不用它在 pre-commit 钩子里直接跑全量 ESLint20 人团队的项目光扫描一遍就可能要两三分钟开发者等得不耐烦就会开始想各种办法绕过钩子。lint-staged 只取git diff --name-only列出的暂存文件再按文件名后缀匹配出对应的检查命令整个过程通常在一两秒内完成这是方案能被团队接受的关键。2.2 为什么坚持在本地跑而不是只靠 CI我见过不少团队为了省事不在本地做任何钩子只在 CI 里跑检查。这种方案执行起来确实简单但有个致命问题CI 的反馈周期太长了。一次 pipeline 跑完可能要五到十分钟开发者提交后还得等着看结果不合格就打回重提一个上午可能只能提交两三轮。长期下来团队会形成“先提交再说”的心理所有质量压力全部堆积到 CI 那里反而拖慢了整体节奏。本地钩子的优势在于反馈即时。代码一提交半秒钟内检查结果就出来了有问题当场改当场重提整个闭环非常顺畅。而 CI 检查作为第二道保险覆盖的场景是有人用git commit --no-verify强行跳过钩子或者合并请求把多个分支的代码混在一起产生的组合问题。一道防个人一道防系统两道都不可少。2.3 渐进式落地的策略考量方案落地的顺序也非常重要我们吃过一次亏。最早的时候我把 ESLint 和 Prettier 的规则一次性全部打开结果老项目几百个文件瞬间冒出上千条错误pre-commit 变成了一堵绝望的高墙谁提交谁碰壁最后大家联合起来要求去掉钩子。后来改成渐进式落地才真正跑通。渐进式分三步第一步先跑 Prettier因为排版类的规则可以全量一键格式化改动量大但几乎零风险第二步跑 ESLint但先用--quiet只看 error 级别的严重问题warn 级别的规则等团队习惯了再逐步放开第三步接入 Stylelint 和 commitlint。每个步骤之间留出一到两周的缓冲期让团队把手写的习惯慢慢改过来。3. 配置实操从零搭建 Vue 项目的提交检查链路3.1 初始化工程配置与依赖安装先说明一下我这里的示例基于 Vue 3 Vite JavaScript 技术栈用 npm 做包管理。如果你用的是 pnpm 或 yarn命令上稍微变化但配置思路完全一样。在项目根目录下安装所有依赖npm install -D eslint prettier eslint-plugin-vue eslint-config-prettier stylelint stylelint-config-standard commitlint/cli commitlint/config-conventional husky lint-staged这里有一个比较容易被忽略的依赖eslint-config-prettier。它专门用来关闭 ESLint 中与 Prettier 冲突的代码风格类规则。如果不装这个包ESLint 和 Prettier 会同时管“引号用单引还是双引”这类规则两边配置不一致时 lint-staged 会来回报错出现“eslint --fix 改完prettier --write 又改回去”的死循环。注意Vue 项目里eslint-plugin-vue也有部分格式化规则同样要配合关闭。3.2 配置文件的具体写法在项目根目录创建.eslintrc.cjs内容如下module.exports { root: true, env: { browser: true, es2022: true, node: true }, extends: [ eslint:recommended, plugin:vue/vue3-recommended, prettier ], parserOptions: { ecmaVersion: latest, sourceType: module }, rules: { vue/multi-word-component-names: off, no-console: process.env.NODE_ENV production ? error : warn, no-debugger: process.env.NODE_ENV production ? error : warn } }重点说一下vue/multi-word-component-names这条规则。eslint-plugin-vue 默认要求组件名必须是多单词组合防止和 HTML 原生标签重名。但实际开发中很多页面组件比如Home.vue、About.vue都是单单词命名这条规则会疯狂报警。我们项目里选择关闭它另外用团队的命名约定来管。再创建.prettierrc文件{ semi: false, singleQuote: true, printWidth: 100, trailingComma: none, endOfLine: auto }这是一套非常主流的“无分号 单引号”风格配置如果你团队更喜欢分号风格把semi改成true就行。endOfLine设置成auto是为了避免 Windows 和 macOS 用户之间因为 CRLF/LF 差异产生无尽的文件变更。Stylelint 的配置.stylelintrc.json{ extends: stylelint-config-standard, rules: { declaration-empty-line-before: null, no-descending-specificity: null } }3.3 husky 和 lint-staged 的配置细节husky 的安装方式在版本迭代中变过几次。V8 之前的版本用的是husky installV9 之后推荐直接在package.json中声明prepare脚本。以下是当前比较稳健的做法npm pkg set scripts.preparehusky npx husky init执行完成后项目根目录会自动生成.husky/目录并创建pre-commit文件。接着在package.json中配置 lint-staged{ lint-staged: { *.{js,vue}: [ eslint --fix, prettier --write ], *.{css,scss,vue}: [ stylelint --fix ], *.{json,md}: [ prettier --write ] } }然后在.husky/pre-commit文件里写入npx lint-staged这里有几个关键细节值得展开。第一eslint --fix和prettier --write的顺序有讲究。ESLint 有些规则比如sort-imports会重排 import 顺序Prettier 不干这个事但如果反过来先跑 Prettier 再跑 ESLintESLint 修完后可能引入新的排版问题导致最终输出不一致。我们测试下来先 ESLint 后 Prettier 的组合最稳定最终文件一定是 Prettier 的格式。第二stylelint --fix也带了--fix它不仅能修格式还能自动补全一些标准的属性顺序。接着配置 commit-msg 钩子创建.husky/commit-msgnpx --no -- commitlint --edit $1再创建commitlint.config.cjsmodule.exports { extends: [commitlint/config-conventional], rules: { type-enum: [2, always, [feat, fix, docs, style, refactor, test, chore]], subject-min-length: [2, always, 5], subject-empty: [2, never] } }这套配置强制提交信息遵循 Conventional Commits 规范格式为type(scope): subject比如feat(login): 增加手机号登录。这个规范的好处不只是好看它让后续自动生成 changelog、语义化版本管理、按模块筛选提交记录都变成了可能。3.4 CI 流水线里的全量检查脚本本地钩子配置好之后CI 也不能空着。在项目的根目录增加一个独立脚本文件scripts/ci-check.sh#!/bin/bash echo Running ESLint... npx eslint . --ext .js,.vue echo Running Stylelint... npx stylelint **/*.{css,scss} echo Checking commit messages... npx commitlint --from $CI_MERGE_REQUEST_DIFF_BASE_SHA --to $CI_MERGE_REQUEST_TARGET_BRANCH_SHACI 配置因平台而异核心就是在合并请求流水线里加一个 stage 执行这个脚本。本地钩子是增量的CI 是全量的两者配合下来理论上任何不合规的代码都很难有机会合入主干。4. 常见问题与排查技巧实录4.1 老项目存量代码报错太多怎么办这是问得最多的一个问题也是团队落地时最容易翻车的点。有一个同事的团队直接把 lint-staged 接到一个维护了三年的 Vue2 项目上头一个提交瞬间炸出 300 多个错误差点原地解散这套方案。处理存量代码的正确姿势是“新代码严、老代码宽”。具体操作是给 ESLint 增加 overrides 配置overrides: [ { files: [old-module/**/*.{js,vue}], rules: { no-unused-vars: warn, vue/max-attributes-per-line: off } }, { files: [src/**/*.{js,vue}], rules: { no-unused-vars: error } } ]这样老模块的代码允许 warn 级别的警告新模块严格要求 error。CI 里也对应加白名单等团队哪天有空重构老模块再把规则逐步收紧。我的经验是不要指望一次重构到位但一定要明确新代码的高压线这样至少不会让存量债务继续扩大。4.2 ESLint 和 Prettier 冲突导致死循环这个坑非常经典。症状是 lint-staged 执行后文件被来回修改状态一直停留在暂存区甚至出现“刚才改好的代码又变回去了”的诡异情况。原因就是两者规则的职责边界没有划清。解决办法有两个层面。第一检查是否引入了eslint-config-prettier并且它必须是extends数组里的最后一个。第二ESLint 规则中不要手动配置那些 Prettier 已经管了的格式类规则比如quotes、semi、indent这些交给 Prettier 就行。记住分工ESLint 管代码质量Prettier 管代码颜值。4.3 Windows 环境下钩子不执行或闪退这个问题也出现过不少次。husky 生成的钩子文件依赖 shell 环境Windows 上如果安装 Git 时没有选“Use Git from the command line and also from 3rd-party software”钩子会静默失败或者弹一个黑框闪退。另外一个常见坑是钩子文件里的路径问题比如直接写了node_modules/.bin/lint-staged但 Windows 上实际路径不同。稳妥的做法是钩子文件里统一用npx调用因为它会从node_modules/.bin里自动查找命令。另外检查core.hooksPath的值执行git config core.hooksPath如果返回的不是.husky/_而是别的路径要手动修正。4.4 commit 信息规范引发的团队抵抗commitlint 开得太狠连type配置都严格限制团队很容易产生“这浪费时间”的抱怨。我在实际推行中逐渐总结出一条折中路线type保留常见的feat、fix、docs、style、refactor、test、chore就够了别搞一堆perf、build、ci、revert要求大家背scope允许为空不强制subject只要求不能为空且不少于 5 个字。规则能防住“update file”这种毫无信息的提交就达到了 80% 的目的剩下的自由度给开发者自己留。5. 这套方案还能怎么往外扩展5.1 从格式合规延伸到静态安全扫描与单元测试lint-staged 的机制可以扩展到任何你想在提交前快速确认的东西。比如引入eslint-plugin-security检测代码中的危险写法或者直接加一个单元测试的命令到 lint-staged 的 handlers 里。很多人担心“提交前跑单测太慢”但配合 lint-staged 只跑变更文件的测试通常也能控制在几秒内。对于 Vue 项目还可以接入vitest在 pre-commit 阶段对本次改动涉及的组件、composable、store 跑一轮轻量级单元测试。默认推荐的 Vitest 并行模式速度非常快业务不太复杂的项目基本能控制在 3 到 5 秒。5.2 把配置沉淀成团队脚手架模板最理想的状态是这套配置不是每个项目各搞一套而是沉淀成一个脚手架模板。新项目初始化的时候直接拉取模板所有规则、钩子、CI 脚本开箱即用。团队里的 eslint、prettier、stylelint 配置保持一致意味着切换项目的时候不需要重新适应不同的代码风格。我们内部就是把.eslintrc.cjs、.prettierrc、.stylelintrc.json、commitlint.config.cjs、lint-staged配置全部收进一个私有脚手架仓库。新项目启动时执行一条命令就能初始化好全部工程化能力老项目迁移时也只多花半天时间。从这个角度看提交即合规不只是一次技术升级更是一套团队协作方式的升级。5.3 规则治理文化的长期维护最后说一个很多人忽略的点自动化工具不是万能钥匙规则本身需要持续治理。如果团队里没有任何人维护 eslint 配置两年下来规则会变得又臭又长甚至出现互相矛盾的条目最终大家又开始手动跳过检查。合理的做法是每个季度花半天时间过一遍规则配置看看有没有因为团队技术栈升级而过时的规则有没有因为业务场景变化应该调整的开关。这个事应该指定专人负责或者至少在技术分享会上留出讨论机制。工具负责执行规则人负责定期校准规则这样才能让整套方案真正持久地运转下去。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑