Pre-commit钩子在前端项目中的实践与踩坑经验分享
又踩坑了,pre-commit 怎么突然不工作了?
前两天我在项目里加了一个 pre-commit 钩子,用来跑 ESLint 校验代码。本来一切正常,但今天提交代码时,发现 pre-commit 突然不生效了!折腾了半天才发现问题出在哪。
简单说下解决方案吧:
- 第一步是检查 .husky/pre-commit 文件是否存在并且配置正确。
- 第二步是确认 package.json 中的 scripts.husky 字段是否被误删。
- 最后一步也是最关键的,如果你用的是 pnpm,需要确保在安装依赖时加上 –shamefully-hoist 参数。
核心代码就这几行:
# 确保 Husky 安装正确
npx husky install
# 初始化 pre-commit 钩子
npx husky add .husky/pre-commit "npm run lint"
为什么突然失效?原因分析
事情是这样的:前几天团队里新来了个小伙伴,他负责优化项目的依赖管理。他说原来的 node_modules 结构太乱了,建议我们切换到 pnpm。我当时觉得挺好,pnpm 确实能节省磁盘空间,速度也快一些。
结果就是从那之后,pre-commit 就挂了。我一开始还以为是 Husky 的版本问题,因为最近确实升级了几个依赖。于是我开始翻文档、查 issue,甚至还重新初始化了一遍 Husky:
# 重新初始化 Husky
rm -rf .husky
npx husky-init
但问题依旧存在,pre-commit 还是没反应。
踩坑提醒:pnpm 的依赖提升是个大坑
这里我踩了个坑:pnpm 默认不会把依赖提升到顶层 node_modules。这就导致 Husky 找不到它需要的一些依赖包。
折腾了半天发现,解决办法其实很简单——只需要在安装依赖的时候加上 –shamefully-hoist 参数:
pnpm install --shamefully-hoist
这个参数会强制把所有依赖都提升到顶层 node_modules,虽然违背了 pnpm 的设计理念,但对于像 Husky 这种需要全局访问依赖的工具来说,这是必须的。
排查过程中的其他小插曲
中间我还试过几种方案,比如手动修改 .husky/pre-commit 文件:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# 确保路径正确
npm run lint
后来试了下发现还是不行,原因是 Husky 依赖的一些二进制文件(比如 eslint)在 pnpm 的默认结构下根本找不到。
另外,我还怀疑是不是 Git 的问题,于是检查了一下 Git 的 hooks 路径:
“bash`>
git config core.hooksPath
结果显示路径没问题,指向的就是 .husky 目录。
最后实在没办法了,去查了下 pnpm 的官方文档,才发现这个 –shamefully-hoist 参数。名字起得挺有意思,直译过来叫“羞耻地提升”,哈哈。
以上是我踩坑后的总结
总结一下,这次的问题主要是因为 pnpm 的依赖隔离机制和 Husky 的依赖查找方式不兼容导致的。解决办法就是用 –shamefully-hoist 参数强行把依赖提升到顶层。
不过这里也有个小问题:即使加了这个参数,有些依赖还是会偶尔报错,尤其是那些动态 require 的模块。但我目前还没找到更好的办法,只能先这样用了。
如果你有更好的方案,欢迎评论区交流!顺便吐槽一句,pnpm 的这种设计虽然节省空间,但对新手真的不太友好。

暂无评论