如何对 JSX 文件启用 ESLint 的 react-hooks 规则
解读
面试官想知道三件事:
- 你能否在 Grunt 体系 里把 ESLint 跑起来;
- 你能否让 ESLint 只针对 JSX 文件 生效,而不是全量扫描;
- 你能否把 react-hooks 规则集(react-hooks/rules-of-hooks、react-hooks/exhaustive-deps)注入到规则链里,并保证规则等级正确。
国内真实场景下,项目往往同时存在 JS/TS/JSX,构建机资源紧张,“只扫该扫的” 是 CI 考核指标之一;答不到“范围可控、规则可配、缓存可用”这三点,会被认为“仅会跑命令,不会工程化落地”。
知识点
- grunt-eslint 插件的 files/src 匹配语法(支持 ! 反向、ext 通配)
- ESLint 配置级联:.eslintrc.* vs grunt 任务内的 options.configFile
- react-hooks 插件的注入方式:extends 数组 或 plugins + rules 手工声明
- JSX 解析器:@babel/eslint-parser 与 ecmaFeatures.jsx 的取舍(国内项目普遍用 Babel,需同步设置 requireConfigFile:false)
- 缓存与增量:grunt-eslint 的 cache 开关与 cacheLocation,降低 60%+ 扫描时间
- 规则等级:'error' 会打断后续任务,'warn' 仅输出,CI 脚本需配合 force: true 防止 Grunt 退出码非 0
答案
-
安装依赖
npm i -D grunt-eslint eslint-plugin-react-hooks @babel/core @babel/eslint-parser -
在项目根新建 .eslintrc.js,仅声明 JSX 相关
module.exports = {
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
ecmaFeatures: { jsx: true },
requireConfigFile: false
},
plugins: ['react-hooks'],
extends: [],
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn'
},
overrides: [{
files: ['**/*.jsx'],
rules: {
'react-hooks/exhaustive-deps': 'error' // JSX 文件里升级成 error
}
}]
}; -
Gruntfile.js 中注册任务
module.exports = function(grunt) {
grunt.initConfig({
eslint: {
jsx: {
options: {
configFile: '.eslintrc.js',
cache: true,
cacheLocation: 'node_modules/.cache/eslint-jsx/'
},
src: ['src/**/*.{jsx,tsx}'] // 只扫 JSX/TSX,其他文件阶段独立任务
}
}
});
grunt.loadNpmTasks('grunt-eslint');
grunt.registerTask('lint:jsx', ['eslint:jsx']);
};
- 在 CI 脚本里
npm run grunt lint:jsx
若出现 error 级别规则违反,Grunt 会返回 exit 1,直接阻断流水线,符合国内“质量门禁”要求。
拓展思考
- 如何把 TypeScript + JSX 一起管:把 parser 换成 @typescript-eslint/parser,并在 overrides 里对 tsx 文件关闭部分 react-hooks 规则,避免与 TS 类型检查冲突。
- 与 grunt-contrib-watch 联动:文件改动时只 lint 改动的 jsx,通过 grunt.event.on('watch',function(action, filepath) {}) 动态修改 src 数组,实现毫秒级增量检查。
- 产出 可视化报告:在 grunt-eslint 里加 options.format: 'html',并把输出文件托管到 nginx,让测试组无需命令行即可定位问题。
- 当项目升级到 ESLint 9 Flat Config 后,grunt-eslint 尚未官方支持,可先用 eslint.useFlatConfig 实验开关,或临时用 grunt-shell 调用 npx eslint,保证团队平滑过渡。