|
| 1 | +# ESLint 命令与排查指南 |
| 2 | + |
| 3 | +本文档记录在项目中修复 ESLint 问题时常用的命令、统计方法、常见规则错误的排查和修复思路,方便日后自查与排错。 |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## 环境说明 |
| 8 | +- 项目为 ESM(package.json 中 `type":"module"`),ESLint 使用 flat config(注意插件/extends 的加载)。 |
| 9 | +- Node / npx 可用;以下命令在 Windows (Git Bash / WSL) 或类 Unix 环境下均可运行。 |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## 常用命令(快速参考) |
| 14 | +- 单文件检查(显示所有问题): |
| 15 | + |
| 16 | +``` |
| 17 | +npx eslint "src/pages/chatgpt/index.jsx" || true |
| 18 | +``` |
| 19 | + |
| 20 | +- 单文件只显示 errors(quiet 模式,隐藏 warnings): |
| 21 | + |
| 22 | +``` |
| 23 | +npx eslint --cache --quiet "src/pages/chatgpt/index.jsx" || true |
| 24 | +``` |
| 25 | + |
| 26 | +- 尝试对单文件自动修复: |
| 27 | + |
| 28 | +``` |
| 29 | +npx eslint --cache --fix "src/pages/chatgpt/index.jsx" || true |
| 30 | +``` |
| 31 | + |
| 32 | +- 全量扫描并将文本输出保存到文件: |
| 33 | + |
| 34 | +``` |
| 35 | +npx eslint "src/**/*.{js,jsx,ts,tsx}" 2>&1 | tee eslint-report-full.txt |
| 36 | +``` |
| 37 | + |
| 38 | +- 全量输出为 JSON(便于后续统计): |
| 39 | + |
| 40 | +``` |
| 41 | +npx eslint --format json "src/**/*.{js,jsx,ts,tsx}" -o eslint-report.json |
| 42 | +``` |
| 43 | + |
| 44 | +- 在 debug 模式下运行(用于排查 flat-config / 插件加载问题): |
| 45 | + |
| 46 | +``` |
| 47 | +npm run eslint -- --debug "src/**/*.{js,jsx,ts,tsx}" |
| 48 | +``` |
| 49 | + |
| 50 | +- 如果 package.json 中有自定义脚本(例如 `lint:errors`),可以直接运行: |
| 51 | + |
| 52 | +``` |
| 53 | +npm run lint:errors |
| 54 | +``` |
| 55 | + |
| 56 | +--- |
| 57 | + |
| 58 | +## 生成按文件排序的问题统计(推荐 JSON 方法) |
| 59 | +以下步骤产生一个按问题数降序的文本文件 `eslint-by-file.txt`: |
| 60 | + |
| 61 | +1. 生成 JSON 报告: |
| 62 | + |
| 63 | +``` |
| 64 | +npx eslint --format json "src/**/*.{js,jsx,ts,tsx}" -o eslint-report.json |
| 65 | +``` |
| 66 | + |
| 67 | +2. 用 Node 脚本统计并输出为可读列表(在项目根运行): |
| 68 | + |
| 69 | +``` |
| 70 | +node -e "const r=require('./eslint-report.json'); const m={}; r.forEach(f=>{const p=f.messages.length; if(p) m[f.filePath]=(m[f.filePath]||0)+p}); const out=Object.entries(m).sort((a,b)=>b[1]-a[1]).map(([f,c])=>c+'\t'+f).join('\n'); require('fs').writeFileSync('eslint-by-file.txt',out); console.log('wrote eslint-by-file.txt')" |
| 71 | +``` |
| 72 | + |
| 73 | +结果文件 `eslint-by-file.txt` 格式为: |
| 74 | +``` |
| 75 | +11 C:/.../src/components/KeepAlive/index.jsx |
| 76 | +5 C:/.../src/components/stateless/ReMarkdown/index.jsx |
| 77 | +... |
| 78 | +``` |
| 79 | + |
| 80 | +此法最精确(区分 errors/warnings 可在脚本中改进),也方便后续自动化处理。 |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +## 快速文本解析方法(替代) |
| 85 | +如果不想生成 JSON,可以将完整文本输出并用 grep/awk/sed 统计(适合临时检查): |
| 86 | + |
| 87 | +``` |
| 88 | +npx eslint "src/**/*.{js,jsx,ts,tsx}" 2>&1 | tee eslint-report.txt |
| 89 | +# 示例(在 Git Bash / WSL) |
| 90 | +grep -E "^\s+\d+:\d+\s+" eslint-report.txt | sed -E 's/^[ \t]*([0-9]+):([0-9]+)[ \t]+(error|warning).+\s+(.+)$/\4/' | sort | uniq -c | sort -rn |
| 91 | +``` |
| 92 | + |
| 93 | +注意:该方法对输出格式敏感,仅作快速估算。 |
| 94 | + |
| 95 | +--- |
| 96 | + |
| 97 | +## 常见错误类型与修复思路 |
| 98 | +下面列出会反复出现的问题类型与对应的快速修复策略。 |
| 99 | + |
| 100 | +1) react-hooks/purity(impure 在 render 中调用,例如 `Date.now()`) |
| 101 | +- 原因:组件或变量在渲染期调用了非纯函数(Date.now、Math.random、DOM 读取等)。 |
| 102 | +- 修复:将不稳定的值移到模块顶层或使用 `useMemo` / `useRef` / `useState` 初始化一次。 |
| 103 | + - 例如:不要在组件顶层的渲染直接 `return String(Date.now()).slice(-6)`,改为 `const idRef = useRef(Date.now())` 或把 helper 提升到模块顶层。 |
| 104 | + |
| 105 | +2) react-hooks/set-state-in-effect(在 effect 中同步调用 setState) |
| 106 | +- 原因:在 effect 的主体直接同步调用 setState,可能导致级联渲染。 |
| 107 | +- 修复:将 setState 推迟到微任务或回调中,例如: |
| 108 | + |
| 109 | +``` |
| 110 | +// 避免: |
| 111 | +useEffect(() => { |
| 112 | + setState(someValue) |
| 113 | +}, [deps]) |
| 114 | +
|
| 115 | +// 建议: |
| 116 | +useEffect(() => { |
| 117 | + let active = true |
| 118 | + Promise.resolve().then(() => { |
| 119 | + if (!active) return |
| 120 | + setState(someValue) |
| 121 | + }) |
| 122 | + return () => { active = false } |
| 123 | +}, [deps]) |
| 124 | +``` |
| 125 | + |
| 126 | +或把逻辑重写为条件渲染以避免不必要的 setState。 |
| 127 | + |
| 128 | +3) refs 在 render 中读写(impure / 不安全) |
| 129 | +- 原因:在渲染期访问 DOM(例如 `ref.current.innerText`)或创建 DOM 节点。 |
| 130 | +- 修复:把 DOM 访问/初始化放到 `useEffect` 中,用 state 将结果暴露给渲染。 |
| 131 | + |
| 132 | +4) hooks 条件调用(rules-of-hooks) |
| 133 | +- 原因:基于条件或 try/catch 在不同分支调用 Hook。 |
| 134 | +- 修复:始终在组件顶层调用 Hook。若需要可选上下文,提供 `useOptionalXxx` 返回 null/默认值,而不要在条件内调用 Hook。 |
| 135 | + |
| 136 | +5) no-undef / 未声明变量 |
| 137 | +- 原因:变量拼写错误或重命名后未同步更新。 |
| 138 | +- 修复:按 ESLint 报错定位(文件+行),补充 `import` 或把变量名修正;不要滥用 /* global */,除非确实需要。 |
| 139 | + |
| 140 | +--- |
| 141 | + |
| 142 | +## 捕获和保存诊断输出 |
| 143 | +- 建议把全量输出保存为文本: |
| 144 | + |
| 145 | +``` |
| 146 | +npx eslint "src/**/*.{js,jsx,ts,tsx}" 2>&1 | tee eslint-report-full.txt |
| 147 | +``` |
| 148 | + |
| 149 | +- 若要将 JSON 报告上传/分析,使用 `--format json -o file`: |
| 150 | + |
| 151 | +``` |
| 152 | +npx eslint --format json "src/**/*.{js,jsx,ts,tsx}" -o eslint-report.json |
| 153 | +``` |
| 154 | + |
| 155 | +--- |
| 156 | + |
| 157 | +## auto-fix 与限制 |
| 158 | +- 自动修复:`npx eslint --fix <file>` 能修复样式和部分简单问题(如 semi、quotes、no-unused-vars 的部分情况)。 |
| 159 | +- 注意:逻辑错误、Hook 使用错误、refs/purity 等通常需要手动修改代码。 |
| 160 | + |
| 161 | +--- |
| 162 | + |
| 163 | +## 建议加入的 package.json 脚本 |
| 164 | +在 `package.json` 中加入以下脚本便于复用: |
| 165 | + |
| 166 | +```json |
| 167 | +"scripts": { |
| 168 | + "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", |
| 169 | + "lint:fix": "eslint 'src/**/*.{js,jsx,ts,tsx}' --fix", |
| 170 | + "lint:errors": "eslint 'src/**/*.{js,jsx,ts,tsx}' --quiet" |
| 171 | +} |
| 172 | +``` |
| 173 | + |
| 174 | +- `lint:errors` 会只输出 errors(不显示 warnings),适合 CI 或快速定位必须修复的问题。 |
| 175 | + |
| 176 | +--- |
| 177 | + |
| 178 | +## 调试 flat config / 插件加载问题 |
| 179 | +- 如果 ESLint 报错提示 plugin 配置无法加载或 `extends` 无效,先使用 debug 模式查看加载过程: |
| 180 | + |
| 181 | +``` |
| 182 | +npm run eslint -- --debug "src/**/*.{js,jsx,ts,tsx}" |
| 183 | +``` |
| 184 | + |
| 185 | +- 确认 `eslint` 版本与插件版本兼容(flat config 与 legacy `extends` 行为不同,需要显式注册插件)。 |
| 186 | + |
| 187 | +--- |
| 188 | + |
| 189 | +## 故障排查小贴士 |
| 190 | +- 当 ESLint 报错但你确认代码已改:先清掉缓存重新运行: |
| 191 | + |
| 192 | +``` |
| 193 | +npx eslint --no-cache "<files>" |
| 194 | +``` |
| 195 | + |
| 196 | +- 对单文件调试更快: |
| 197 | + |
| 198 | +``` |
| 199 | +npx eslint --cache "path/to/file.jsx" || true |
| 200 | +``` |
| 201 | + |
| 202 | +- 如果需要把所有文件问题导出并在本地用编辑器跳转,优先使用 JSON 输出并在 VS Code 中安装 ESLint 扩展加载 `eslint-report.json`。 |
| 203 | + |
| 204 | +--- |
| 205 | + |
| 206 | +## 我在本次修复会话中记录的部分示例结果 |
| 207 | +(仅为会话快照,具体数字会随代码修改波动) |
| 208 | + |
| 209 | +- `src/components/KeepAlive/index.jsx` — 11 problems(曾为最高) |
| 210 | +- `src/components/stateless/ReMarkdown/index.jsx` — 5 problems |
| 211 | +- `src/pages/chatgpt/index.jsx` — 最初 5 problems,已在会话中修复多数 |
| 212 | + |
| 213 | +--- |
| 214 | + |
| 215 | +如需我把当前仓库的完整按文件问题统计(`eslint-by-file.txt`)生成并提交到仓库根目录,回复“是”,我会立刻运行并把文件写入。 |
0 commit comments