lint-staged检测范围异常:未暂存文件导致提交失败
Monorepo下lint-staged结合Yarn脚本只检查暂存文件的解决方案
问题背景
在monorepo的packageA里有两个带ESLint错误的JS文件,修复并暂存其中一个后,执行提交却因为未暂存的另一个文件触发lint失败,导致提交被拦截。
环境信息
目录结构
.lintstagedrc.mjs ├── packages │ ├── packageA │ │ ├── .lintstagedrc.mjs │ │ └── components │ │ ├── compA.js │ │ └── compB.js │ ├── packageB │ │ └── .lintstagedrc.mjs │ └── packageC │ └── .lintstagedrc.mjs
关键配置
- 根目录
.lintstagedrc.mjs:export default { '*.js': 'eslint --fix' }; - 子包
.lintstagedrc.mjs:export default { '*.js': 'yarn lint:js', '*.hbs': 'yarn lint:hbs' }; - 子包
package.json脚本:"scripts": { "lint:js": "eslint . --cache", "lint:hbs": "handlebars-lint ." } - Husky预提交钩子
.husky/pre-commit:npx lint-staged
问题原因
lint-staged已经正确识别并传入了暂存的compA.js文件,但yarn lint:js里的eslint . --cache会强制扫描整个当前目录,完全忽略了传入的文件列表,导致未暂存的compB.js中的错误被检测到,触发提交失败。你之前尝试的eslint ${@:-.} --cache未生效,是因为Yarn对脚本参数的解析逻辑和原生bash不同。
可行解决方案
方案1:修改Yarn脚本,适配参数传递
通过bash显式包裹脚本逻辑,确保参数能被正确解析。修改子包package.json的脚本:
"scripts": { "lint:js": "bash -c 'eslint ${@:-.} --cache' --", "lint:hbs": "bash -c 'handlebars-lint ${@:-.}' --" }
- 当lint-staged传入暂存文件列表时,脚本会用这些文件作为eslint的检查目标;
- 单独执行
yarn lint:js时,默认检查当前目录下所有文件,保留原有功能。
如果是Yarn 2及以上版本,也可以用更简洁的写法:
"scripts": { "lint:js": "eslint $@ --cache || eslint . --cache", "lint:hbs": "handlebars-lint $@ || handlebars-lint ." }
逻辑是先尝试使用传入的参数,没有参数时再默认检查当前目录。
方案2:调整lint-staged配置,显式传递文件
在子包的.lintstagedrc.mjs中,直接将暂存文件列表作为参数传给Yarn脚本:
export default { '*.js': (files) => `yarn lint:js ${files.map(f => `"${f}"`).join(' ')}`, '*.hbs': (files) => `yarn lint:hbs ${files.map(f => `"${f}"`).join(' ')}` };
同时修改子包package.json的脚本为:
"scripts": { "lint:js": "eslint $@ --cache", "lint:hbs": "handlebars-lint $@" }
这种方式让lint-staged主动把文件列表传递给脚本,脚本直接用$@接收参数,确保只检查指定文件。
验证方法
修改完成后,运行调试命令:
npx lint-staged --debug
可以看到执行的命令会带上暂存的文件路径,比如yarn lint:js "packages/packageA/components/compA.js",此时ESLint只会检查这个文件,不会触发未暂存文件的错误,提交即可成功。同时单独执行yarn lint:js仍会扫描整个目录,不影响日常lint检查。
内容的提问来源于stack exchange,提问作者gtb104
相关产品推荐
相关产品推荐

