## 关于 Husky 和 lint-staged 的一些技术随想最近在几个项目里重新配置了代码提交的检查流程用到了 Husky 和 lint-staged 这套组合。不少刚接触前端工程化的同事会问起这两个工具今天就聊聊它们到底是什么以及在实际项目中怎么用会比较顺手。他是什么Husky 本质上是一个 Git hooks 管理工具。Git hooks 是 Git 提供的一种机制允许你在特定的 Git 操作比如提交代码、推送代码前后插入自定义的脚本。但原生的 Git hooks 配置起来有点麻烦需要手动在项目的.git/hooks目录下写脚本而且这个目录默认不被纳入版本控制。Husky 的出现就是为了解决这个问题它让你能以一种更简单、更可维护的方式比如通过package.json来配置来管理和使用这些钩子。lint-staged顾名思义就是只对“暂存区”staged的文件进行 lint 检查的工具。在 Git 的工作流中我们修改了文件后会先用git add把它们放入暂存区然后再git commit提交。lint-staged 的作用就是在这个提交前的关键时刻只对那些你准备提交的、已经放在暂存区的文件运行指定的检查或格式化命令而不是对整个项目仓库进行扫描。这样做效率非常高尤其是项目大了以后。他能做什么这两者结合起来主要做一件事把代码质量问题尽可能早地拦截在本地提交环节。想象一下团队协作的场景。如果没有这类工具一个同事可能写了一些格式混乱、或者存在潜在语法错误的代码然后直接提交并推送到共享仓库。其他人在拉取代码后可能本地运行 lint 检查会报一堆错或者更糟有问题的代码被部署到了线上。这就像在一条生产流水线上如果能在第一个环节就把有瑕疵的零件挑出来就能避免它流到后面的组装、质检环节节省大量的时间和返工成本。具体来说通过配置我们通常用它们来做这些事在git commit执行前自动用 ESLint 检查暂存区里 JavaScript/TypeScript 文件的语法和风格。自动用 Prettier 格式化暂存区里的代码确保格式一致。检查提交信息本身的格式是否符合约定例如是否关联了任务号。运行与暂存文件相关的单元测试防止提交破坏现有功能。它的核心价值在于“自动化”和“前置拦截”。把代码规范检查从一种靠自觉的、可选的后置动作变成一种强制的、无缝的前置流程让遵守规范成为提交代码这个动作本身的一部分。怎么使用现在的使用方式已经变得非常简洁了。以一个新项目为例大致步骤如下首先安装它们。通常作为开发依赖安装npminstallhusky lint-staged --save-dev然后初始化 Husky。这个过程会在项目根目录创建.husky文件夹并设置好 Git hooks 的路径。npx husky init接下来我们需要创建一个 pre-commit 钩子。执行上面的命令后Husky 应该已经生成了一个.husky/pre-commit文件。编辑这个文件在里面调用 lint-staged。#!/usr/bin/env sh.$(dirname--$0)/_/husky.shnpx lint-staged最后配置 lint-staged。通常在package.json里添加一个lint-staged字段。这里是一个常见的配置示例{lint-staged:{*.{js,ts,jsx,tsx}:[eslint --fix,prettier --write],*.{json,md,css,scss}:[prettier --write]}}这个配置的意思是对于暂存区里任何.js,.ts,.jsx,.tsx文件依次执行eslint --fix尝试自动修复问题和prettier --write格式化对于其他如 JSON、Markdown、CSS 类文件则执行 Prettier 格式化。配置完成后当你下次执行git commit时就会自动触发这个流程。lint-staged 会按照配置对相应的暂存文件运行命令。如果 ESLint 检查出无法自动修复的错误这个过程会失败并阻止提交你需要根据提示修复问题后再次尝试提交。最佳实践用了一段时间后觉得有几点实践值得注意命令的幂等性尽量给 lint-staged 配置的命令加上--fix或--write这样的参数让它们能自动修复问题。如果只是检查eslint而不修复那么每次提交只要格式不对就会失败需要人工退出提交、手动格式化、重新添加再提交体验上会有割裂感。自动修复能让流程更顺畅当然前提是团队对自动修复的规则有共识。范围精准lint-staged 的威力就在于“精准”。确保你的命令只作用于传给它的文件列表。像eslint --fix .这样的写法就不太合适它会检查整个项目失去了 lint-staged 的效率优势。正确的做法是利用 lint-staged 将文件列表传递给命令大多数现代工具都支持这种模式就像上面配置的那样。性能考量对于非常耗时的操作比如端到端测试要谨慎考虑是否放在 pre-commit 钩子里。这可能会让每次提交等待几十秒甚至几分钟破坏开发节奏。这类检查更适合放在持续集成CI流水线中。pre-commit 钩子里的检查应该快速、聚焦旨在捕获那些明显且能快速判定的问题。提交信息的检查除了 pre-commit另一个有用的钩子是 commit-msg。可以用它来校验提交信息的格式例如使用commitlint工具来强制要求提交信息符合类似 “type(scope): subject” 的规范。这能保持提交历史的清晰可读。配置的可维护性当规则变得复杂时可以考虑将 lint-staged 的配置从package.json移到一个独立的文件如.lintstagedrc.js中这样可以编写更灵活的配置逻辑。和同类技术对比在 Git hooks 管理领域Husky 是目前最主流的选择社区活跃文档也完善。早期版本v4及以前的配置方式略有不同需要在package.json里写 hooksv5 之后采用了更显式的.husky目录方式感觉上更清晰也解决了之前一些路径问题。有一些类似的工具比如pre-commit一个 Python 实现的框架或者simple-git-hooks。simple-git-hooks更轻量配置也简单但生态和灵活性可能不如 Husky。选择 Husky 很多时候是因为它的“事实标准”地位以及和整个前端生态ESLint, Prettier, Commitlint良好的集成体验。至于 lint-staged 这个理念其实也有其他实现方式。比如可以在 Husky 的 pre-commit 钩子里直接写 shell 脚本手动找出暂存的文件然后运行命令。但 lint-staged 提供了一个非常声明式的配置方式并且处理了很多边缘情况如文件路径包含空格、处理多种文件类型等让我们省了不少心。可以说在“只检查暂存文件”这个细分需求上lint-staged 做得足够专注和优秀。总的来说Husky lint-staged 算不上什么高深的技术但它们体现了一种很好的工程思想通过工具而非文档来约束行为把最佳实践固化到工作流程中让好习惯变得自然而然。对于一个有一定规模、需要协作的前端项目来说花一点时间设置它们长期来看回报是相当不错的。