尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Oxlint anti-slop规则集:用轻量lint拦截AI生成的代码废料

Oxlint anti-slop规则集:用轻量lint拦截AI生成的代码废料 先直接给结论如果你正在接触 Oxlint并且经常被 AI 生成的“表面正确、实际冗余”的代码困扰那这套 anti-slop 规则集思路非常适合你。它不追求把所有规则都打开而是围绕“减少代码废料、提升 review 效率”这一个目标把真正有价值、有态度的规则收进来。本文会从 slop 代码的常见形态讲起逐步拆解 Oxlint 的规则体系最后给出一套可以直接复制到项目里使用的.oxlintrc.json完整配置。阅读本文后你能掌握Oxlint 的安装与基础用法、anti-slop 规则集的分类思路、完整规则配置与解释、错误示例触发演示、接入 Git Hooks 和 CI 的方法以及落地时常见的坑点与解决建议。本文适合前端开发者、全栈开发者以及正在团队内维护代码规范、引入 AI 辅助编码的工程效率负责人。1. 背景与核心概念1.1 什么是 slop 代码“slop”这个词最初在 AI 内容生产领域被广泛讨论指的是那些表面上通顺、实际上缺少质量和把关的内容。放到代码场景里slop 代码就是一批“语法没问题、跑起来没报错、但明显没经过认真设计”的代码。常见的 slop 代码形态包括使用而不是比如if (isLogin true)变量永远不会被重新赋值却写成了letcatch块里只有一个空注释或者干脆吞掉异常为了“保险”写出无意义的条件分支例如if (value ! undefined)把简单逻辑拆成三层嵌套每个分支还带一个else使用new Array()、new Object()这类多余写法一个函数写了七八个参数谁调用谁迷糊。单独看每一条确实不致命规则也不至于报错。但当一个项目里积累了几百处这种写法后代码的可读性、可维护性和审查成本都会明显恶化。更现实的一个场景是团队开始使用 AI 辅助编码之后生成的代码常常是“语法非常标准、风格十分平庸”。它不犯错但也不简洁。这时候单纯靠人肉 review 去拦截成本太高。最好的方式就是让一套有态度的规则集在提交前自动把这些模式拦下来这就是 anti-slop 的核心价值。1.2 为什么传统 lint 配置不够用很多人第一反应是我直接用 ESLint 不就行了但实际落地时你会发现几个问题第一ESLint 配置体系复杂。需要额外安装 parser、plugin、shareable config还要处理项目里不同目录的不同规则覆盖。光是让 TypeScript 项目里的 ESLint 跑通配置就要写一大段。第二反馈速度慢。大型前端项目跑一遍 ESLint经常要几十秒甚至几分钟。反馈周期一长开发者就不愿意在本地频繁跑很多规则实际上没有在日常存活只会在 CI 阶段突然冒出来。第三很多团队的 ESLint 配置偏向“保守”默认关闭了大量有价值但对错误率容忍度低的规则。因为一旦配错全组都会开始报警运维成本太高。所以当一个项目需要一套“能真正拦住代码废料”的规则时轻量、快速、默认合理的新一代 linter 就成了更优选择。1.3 anti-slop 规则集的定位我理解的 anti-slop 不是某个单一规则而是一整套“有观点”的规则组合大致可以分成四层防冗余干掉明显无意义的代码防模板化识别 AI 生成代码里频繁出现的“废话模式”防过度设计限制复杂度、参数数量、嵌套深度防危险风格对容易埋坑的写法直接亮红牌。后面第 4 节会按这四层逐一展开并给出对应的 Oxlint 规则。2. Oxlint 为什么适合承担 anti-slop2.1 Oxlint 是什么Oxlint 是由 Oxc 项目Oxidation Compiler团队维护的开源 JavaScript / TypeScript linter。Oxc 的目标是用 Rust 重写前端工具链中的核心组件Oxlint 就是这套工具链里的 lint 部分。它的特点非常鲜明用 Rust 编写不做任何 Node 侧的原生解析内置对 JavaScript、TypeScript、JSX、ESM、CommonJS 的支持不需要额外安装 parser默认启用 correctness 类别的规则开箱即用支持--fix自动修复提供了与 ESLint 规则高度兼容的规则命名体系。换句话说你不用再经历“装 parser、查兼容性、写 parserOptions”这一整套流程装好就能跑。2.2 与 ESLint 的定位差异Oxlint 并不是要取代 ESLint 的所有能力它的核心定位是“快速反馈”。在 Oxc 团队给出的对比数据里Oxlint 在多数场景下比 ESLint 快 50 到 100 倍。这个差距带来的体验变化是质的以前修改完代码要等几秒钟才看到 lint 结果现在几乎是输入停下的瞬间结果就已经出来了。快速反馈意味着你可以把 lint 嵌入到每次保存、每次 git commit、每次 CI 中而不需要担心拖慢开发流程。也正因为快它才真正适合做“提交前拦截”这件事。2.3 性能带来的工作流变化传统 lint 工具因为慢日常使用频率下降最后往往只在 CI 阶段跑一次发现问题后再回头修改来回成本很高。Oxlint 的性能让它可以进入开发者本地高频使用场景编辑器保存后立即执行pre-commit 阶段全量跑一遍耗时也很低CI 阶段当作一个快速质量门禁甚至可以放在代码生成脚本里生成完马上自检。所以本文下面的完整配置不止是“给 CI 用”的规则更是给开发者在日常编码时使用的一套实时反馈规则。3. 环境准备与安装3.1 安装 Oxlint在 Node 项目里推荐以 devDependency 的方式安装固定版本避免团队间行为不一致npm install oxlint --save-dev也可以用 yarn 或 pnpmpnpm add -D oxlint如果想先体验一下不安装到项目里可以直接用 npxnpx oxlint --version安装完成后可以先在项目根目录执行一次最简单的 lintnpx oxlint默认情况下Oxlint 会扫描当前目录下符合规则的文件并运行内置的正确性规则。如果什么配置都没写它也不会报错而是使用一个比较克制的默认集合。3.2 检查安装结果可以创建一个临时文件test.js内容故意写一个未使用变量const unusedVar 1;然后运行npx oxlint test.js预期会看到类似下面的提示Found 1 warning.这说明 Oxlint 工作正常。如果输出里没有任何提示说明你的版本或配置路径可能有问题可以先执行npx oxlint --help查看可用参数。3.3 项目目录结构本文后续示例采用以下目录结构my-project/ ├── .oxlintrc.json ├── package.json ├── src/ │ ├── main.js │ └── slop-demo.js └── .oxlintignore.oxlintrc.json是 Oxlint 的配置文件放项目根目录即可。如果项目里还有其他子项目或 monorepo 工作区可以在各子项目里再放独立的配置文件Oxlint 会从当前工作目录向上查找。4. anti-slop 规则集分类与设计在设计 anti-slop 规则集时我建议不要盲目把所有规则都打开。Oxlint 内置了大量规则部分规则之间还有观点冲突全部打开只会收到一堆噪音最后大家只能选择忽略。下面按四类目标分别说明。4.1 防冗余先扫掉无意义代码这一层的规则目标很纯粹代码里不该出现“写了等于没写”的部分。规则作用典型触发场景no-unused-vars未使用的变量或参数变量声明后从未读取prefer-const用const代替不会被重新赋值的letlet temp value;后面从不修改no-var禁止使用var存量代码中的var声明no-empty禁止空代码块空的catch、if、finally块no-useless-catch禁止只抛出原异常的catchcatch(e) { throw e; }no-unreachable禁止不可达代码return后面的console.logno-self-assign禁止对自己赋值a a;no-useless-return禁止无意义的return函数末尾多余的空return这里挑一个很典型的例子try { doSomething(); } catch (error) { throw error; }这段代码把异常原样抛出去等于没处理。捕获之后应该要么记录日志、要么兜底处理、要么干脆不捕获。它很容易被 AI 生成因为看起来“做了异常处理”实际上什么都没做。还有一个高发问题空 catch 吞异常。try { await saveData(data); } catch (error) { // ignore }如果业务上确实需要忽略特定异常我建议至少在里面写一行注释说明原因并且要把no-empty配置成不允许空 catch。4.2 防模板化识别 AI 生成的“废话模式”这一层是最有意思的部分。AI 生成的代码往往有一些稳定的“风格指纹”比如if (xxx true)而不是if (xxx)let result ...明明之后根本没改过const flag isDone ? true : false;直接赋值不香吗习惯性写else但if分支里已经return了字符串拼接用而不是模板字符串函数参数里塞一个options {}默认值但调用时根本不传。对应的规则规则作用eqeqeq强制使用和!禁用no-else-returnif分支 return 后禁止多余的elseno-unneeded-ternary禁止无意义的三元表达式prefer-template优先使用模板字符串no-lonely-if禁止else块里只有单个ifunicorn/no-useless-undefined禁止无意义的undefinedtypescript-eslint/no-unused-varsTypeScript 场景下的未使用变量检查看两个最典型的例子// 反例 if (isLogin true) { return Login /; } else { return Profile /; }这段代码有三个问题 true多余if 分支已经returnelse没必要整个逻辑可以进一步简化为// 正例 return isLogin ? Login / : Profile /;再比如这个const status isDone ? true : false;这行代码完全可以把isDone直接赋值给status三元表达式纯属废话。no-unneeded-ternary会把这种情况直接标出来。4.3 防过度设计控制复杂度和嵌套AI 生成的代码还有一个明显问题喜欢把简单逻辑层层嵌套。尤其是当它“想让代码看起来更严谨”的时候经常生成三层 if、两层 map、一堆临时变量。过度设计的代码不是“不能跑”而是“跪着跑”。后续维护者每看一个函数都要在脑子里模拟三层状态成本极高。建议配置以下规则规则建议阈值作用complexity10 或 12控制圈复杂度max-depth4限制控制流嵌套层数max-params4限制函数参数数量no-nested-ternary开启禁止嵌套三元表达式max-lines300 或 500限制单文件行数这里要说明这些规则属于“意见强烈”的一类不同团队审美不同。如果你接手的是一个庞大的老项目直接开max-lines会瞬间爆出成百上千条警告。所以在 anti-slop 配置里这些规则我建议先设为warn不要一上来就是error。让团队先看到问题再约定一个时间窗口分批优化。4.4 防危险风格对埋雷写法直接亮红牌最后一层属于硬约束。这类写法即使不违反业务逻辑也极容易在后续维护中引入 bug建议一律设为error。规则作用no-debugger禁止debugger语句留在代码里no-constant-condition禁止常量条件比如while(true)和if(false)no-await-in-loop禁止在循环里无脑awaitrequire-awaitasync 函数里没有await说明标注错误no-async-promise-executor禁止 async 回调作为 Promise executorcurly所有控制语句都必须使用大括号guard-for-in使用for...in时必须先过滤自身属性no-async-promise-executor是个容易踩的坑const promise new Promise(async (resolve, reject) { const data await fetchData(); resolve(data); });这段代码的问题在于async函数返回的 Promise 和外部new Promise的 resolve/reject 之间没有关联。如果fetchData内部抛错外层 Promise 可能会保持 pending 状态导致调用方永远等不到结果。正确写法是把异步逻辑放进async函数里或者直接在调用处使用 async/awaitasync function getData() { const data await fetchData(); return data; }5. 完整实战搭建并运行 anti-slop 规则集这一节给出一个可以直接复制到项目里的完整过程。5.1 创建 .oxlintrc.json在项目根目录创建.oxlintrc.json{ $schema: ./node_modules/oxlint/configuration_schema.json, plugins: [react, unicorn, typescript, import, promise], categories: { correctness: error, perf: warn, nursery: warn, pedantic: off }, rules: { eqeqeq: [error, always], prefer-const: error, no-var: error, no-debugger: error, no-console: warn, no-empty: [error, { allowEmptyCatch: false }], no-else-return: warn, no-unneeded-ternary: error, prefer-template: warn, no-useless-catch: error, no-unreachable: error, no-constant-condition: [error, { checkLoops: false }], no-await-in-loop: warn, require-await: error, no-async-promise-executor: error, curly: [error, all], guard-for-in: warn, max-params: [warn, 4], complexity: [warn, 10], no-nested-ternary: warn, max-depth: [warn, 4], typescript-eslint/no-explicit-any: warn, typescript-eslint/no-unused-vars: [error, { argsIgnorePattern: ^_ }] } }简单解释几个关键字段categories控制规则类别的总开关。correctness是正确性规则我建议直接设为errorperf是性能相关规则先给warnnursery是新加入的、还在实验阶段的规则建议观察一段时间再决定是否开启pedantic规则大多偏向个人审美默认关闭避免噪音。rules对具体规则进行覆盖可以细粒度调整“打开/关闭/错误级别”。plugins启用需要用到的插件。如果项目里用 React就加上react如果写 TypeScript加上typescript。如果你不需要 React可以把plugins里的react去掉。如果你需要更多风格类规则可以在plugins里追加unicorn和import。5.2 创建一个 slop 示例文件在src目录下创建slop-demo.js故意写一段“表面上能跑、实际上全是废料”的代码// 文件路径src/slop-demo.js function processItems(items) { let result []; let index 0; for (index 0; index items.length; index) { let item items[index]; if (item.active true) { if (item.value ! undefined) { let temp item.value; result.push(temp); } else { // ignore } } else { // nothing } } return result; } processItems();这段代码里至少包含以下问题let result其实可以用constitem.active true触发了eqeqeqlet temp应该用const空else块触发了no-emptyprocessItems()调用时没有传参数但因为函数内部没有使用参数的默认值这可能是个真实的逻辑 bug。5.3 运行 Oxlint 并查看结果在项目根目录执行npx oxlint src/slop-demo.js预期输出会包含类似下面的结构不同版本措辞略有差异⚠ Found 4 warnings and 2 errors.同时会列出每个问题对应的文件、行号、列号、规则名和简短说明。如果你装了 Oxlint 的 VSCode 扩展编辑器中会直接看到波浪线提示保存时就能发现问题不需要等到命令行。5.4 使用自动修复Oxlint 支持自动修复一部分问题。可以执行npx oxlint src/slop-demo.js --fix自动修复后部分问题会被解决比如可能会被替换为、let可能会被替换为const。但像no-empty、no-unreachable这类需要人工判断的问题还是要靠开发者手动处理。这也是 anti-slop 的一个理念能自动修的交给工具需要人类判断的绝不硬修。5.5 重写成符合 anti-slop 的版本为了对比下面是改善后的版本// 文件路径src/slop-demo.fixed.js function processItems(items) { const result []; for (const item of items) { if (!item.active) { continue; } if (item.value undefined) { continue; } result.push(item.value); } return result; }对比一下可以发现for循环改成了for...of可读性更高条件判断去掉了额外嵌套用continue提前跳出当前轮次全部换成了临时变量temp删掉了let全部改成了const。这个例子并不是要告诉你“必须写成这样”而是展示 anti-slop 规则集真正想推动的方向代码更短、分支更少、意图更明显。6. 把 anti-slop 接入日常开发流程规则配好之后如果只在命令行手动执行很快就会被遗忘。真正要发挥作用必须把它嵌入到开发流程里。6.1 package.json scripts在package.json里增加以下脚本{ scripts: { lint: oxlint, lint:fix: oxlint --fix } }这样团队成员统一使用npm run lint执行检查npm run lint:fix执行自动修复。不建议让每个开发者各自记住npx oxlint的各种参数。6.2 接入 Git Hooks推荐使用lint-staged它只对暂存区的文件运行检查速度快也避免一次性处理整个项目遗留问题。先安装依赖npm install --save-dev lint-staged husky然后初始化 huskynpx husky init在package.json里配置 lint-staged{ lint-staged: { **/*.{js,jsx,ts,tsx}: [oxlint --fix, git add] } }在.husky/pre-commit里写入npx lint-staged这样每次提交时只有本次改动的文件会先经过 Oxlint 检查和自动修复。如果有 error 级别问题提交会被中断开发者必须修复后才能继续。6.3 接入 CI如果团队使用 GitHub Actions可以在工作流里加上一个 lint jobname: lint on: pull_request: push: branches: [main] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm ci - run: npx oxlint --deny-warnings这里的关键参数是--deny-warnings。它会把所有 warning 当作 error让 CI 遇到任何质量隐患都直接失败。如果团队刚开始推行warning 太多可以先用--max-warnings 50之类的方法设置一个容忍阈值逐步清零。7. 常见问题与排查思路在实际使用 Oxlint 和 anti-slop 规则集的过程中有几个问题是比较常见的这里整理成表格方便检索。问题现象可能原因解决思路运行oxlint提示找不到配置文件项目根目录没有.oxlintrc.json或工作目录不对确认从项目根目录执行或使用-c指定配置路径规则没有按预期生效规则写在rules但拼写错误或插件未启用先运行npx oxlint --rules查看当前支持的规则名TypeScript 项目的类型相关规则没生效配置里没有启用typescript插件在plugins中加入typescript确认配置格式正确--fix之后还有大量提示这些问题不是自动修复类型区分自动修复和需要人工处理的规则分批优化CI 里 warning 太多导致构建失败--deny-warnings对所有 warning 都严格处理先设置--max-warnings阈值逐步清零与 ESLint 的规则结果不一致Oxlint 和 ESLint 对某些边缘情况的处理存在差异以 Oxlint 输出为准但涉及复杂自定义规则时建议保留 ESLintmonorepo 中不同子项目规则不同Oxlint 从当前工作目录向上查找配置可能读到父级配置在每个子项目根目录放独立.oxlintrc.json或用overrides区分目录这里单独说一下规则不生效的问题。Oxlint 的规则列表是不断变化的不同版本之间会新增规则、删除规则或调整默认级别。如果你从网上复制的配置里包含某个规则但当前版本不支持那这个规则会被静默忽略不会报错。排查方法是运行npx oxlint --rules回显的规则列表里会包含规则状态确认你配置的规则名在列表中存在并且级别和你设置的一致。8. 最佳实践与工程建议8.1 从 error 开始而不是从 warn 开始很多团队为了“不得罪人”会把所有规则先设为warn。但 warning 看得多了人就会麻木最终所有人都会无视 warning只处理 error。anti-slop 的价值就在于“态度明确”对于明显无意义的代码直接error对于存在争议的风格问题才用warn。这样 warning 数量是可控的每一条都值得被认真对待。8.2 新规则先观察再启用Oxlint 更新很快nursery类别里经常出现新规则。不要一看到新规则就加入配置建议先把新规则设为warn在主要业务代码上跑一遍观察误报率确认效果稳定后再升级为error。这样做可以避免频繁改动配置导致团队对 lint 结果失去信任。8.3 不要把所有文件一刀切在.oxlintignore里建议默认忽略以下目录node_modules dist build coverage public/vendor *.min.js如果需要忽略特定场景比如测试文件里频繁使用console.log可以在配置文件里加overrides{ overrides: [ { files: [**/*.test.js, **/*.spec.js], rules: { no-console: off } } ] }但这里要谨慎如果团队里约定测试文件也不能随意打印日志那就不要开这个口子。每一条 override 都是一种投降。8.4 把它当代码规范文档的“可执行版本”一份代码规范文档写得再好也容易被忽略。但 lint 规则不会。建议团队内部维护一份简短的代码规范文档每条规范尽可能对应一条 Oxlint 规则配置出现修改时同步更新文档说明“为什么这么改”。这样当有人质疑某条规则时讨论的是业务价值和代码质量而不是“工具不让写”。8.5 注意依赖版本锁定Oxlint 目前处于快速迭代期不同版本之间可能存在破坏性变更。建议在package.json里精确锁定版本号而不是使用^CI 里使用npm ci安装依赖升级时先小范围验证再全量切换。锁定版本不仅能保证团队行为一致也能避免某天队友升级后规则结果不同导致的认知混乱。9. 训练“反 slop”意识配置好规则之后有一个副作用值得留意当你习惯了 Oxlint 的提示你会开始主动避免写出这些模式而不是写完再等工具报错。这其实是 anti-slop 最有价值的部分。举个很常见的例子。以前写代码时我可能会习惯性写出let config getConfig();直到prefer-const反复提示后自然的反应就变成了“先想清楚这个变量会不会被重新赋值再决定用let还是const”。这种意识迁移比规则本身更能长期提升代码质量。所以我的建议是不要只把 Oxlint 当成一个“报错工具”而是把它当作一面高质量代码的镜子。它拦截的不只是 error更是一整类“看起来能跑、实际上经不起推敲”的写法。下一步你可以找一个代码量最大的存量文件运行npx oxlint --fix看看它自动修复了什么再手动处理剩余的提示感受一下 anti-slop 规则集带来的变化。配置从来不是目的可维护的代码才是。
返回列表