尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用 Oxlint 把 anti-slop 变成自动化代码质量检查

用 Oxlint 把 anti-slop 变成自动化代码质量检查 最近在代码质量讨论里“anti-slop”这个词出现的频率越来越高。当你打开一个由 AI 助手生成的 PR看到一屏any、var、空的catch块、层层嵌套的if、莫名其妙的多余变量时第一反应往往不是“代码有 bug”而是一种说不出的“不对劲”。这种代码没有崩溃甚至能通过单元测试但它就是难读、难维护、难扩展。社区给这种“看起来能跑实际上缺乏质量”的产物起了个名字slop。anti-slop 不是某个单一库也不是一种强制的行业标准它更像是一种质量主张通过工具、规则和评审流程把代码里“差不多就行”的水分挤掉。本文不打算讨论理念口号而是落到一个具体可行的方案上——用 Oxlint基于 Rust 的 JavaScript / TypeScript 静态检查工具和它那些“意见明确”的规则把 anti-slop 从主观感受变成自动化检查。这篇文章适合正在尝试用 AI 辅助写代码但对产出质量不放心的前端开发者也适合想在 CI 里引入一套更严格 lint 规则的工程团队。读完你可以掌握anti-slop 到底在解决什么问题Oxlint 为什么适合承担 anti-slop 检查如何用.oxlintrc.json配置一套严格规则如何把规则应用到真实项目并跑通 CI 检查常见报错和工程落地建议。1. 什么是 slop什么是 anti-slop1.1 slop 代码的典型特征在 AI 生成内容泛滥之后“slop”逐渐被用来形容质量低下、缺乏思考、批量产出的内容。代码领域的 slop 也有比较明显的画像。我整理了几类高频特征特征典型表现为什么危险类型逃逸到处是any、as unknown as X类型系统形同虚设改动一处容易炸一片声明随意能用const却用let甚至用var变量作用域混乱隐式依赖多错误处理敷衍空的catch块、吞异常、只在catch里打印日志线上故障难以定位残留调试代码console.log、debugger污染日志影响性能可能泄露数据条件逻辑草率宽松比较、恒真/恒假条件边界情况不明确逻辑脆弱未使用代码声明了没用的变量、参数、函数增加阅读负担误导后续维护者复杂度过高多层if嵌套、巨型函数、魔法数字单元测试难写重构风险大这些代码单独拎出来看每一处似乎都不致命但它们堆在一起就会让一个项目的可维护性快速下降。更麻烦的是AI 生成代码时非常擅长输出“形式上完整、实际上松散”的代码所以 slop 在新项目里出现的频率比过去高很多。1.2 anti-slop 的思路anti-slop 的核心思路是与其在 code review 时争辩“这段代码好不好”不如先把好代码的标准固化成规则让工具自动挡住明显不合格的提交。这就是 Oxlint 这类 linter 的价值。它不只是抓语法错误还能通过规则集合把“代码风格”“类型使用”“错误处理”“复杂度”等维度变成机器可检查的约束。不过我要提醒一点anti-slop 不等于禁用 AI 生成代码。它更像是一道质检闸门——AI 生成的代码可以提交但必须先通过这套严格的规则。规则过不了就打回重写。这样既保留 AI 的效率又不牺牲质量。2. Oxlint 是什么为什么适合做 anti-slop2.1 Oxc 与 Oxlint 的出身Oxlint 是 OxcOxidation Compiler项目中的 linter 组件。Oxc 是一套用 Rust 编写的 JavaScript / TypeScript 工具链覆盖 parser、linter、transformer、minifier、formatter 等多个方向。Oxlint 的目标很简单在兼容 ESLint 规则生态的前提下把 lint 的速度提升一大截。对前端项目来说lint 速度不是“爽不爽”的问题而是“能不能坚持跑”的问题。很多项目把 ESLint 跑完需要几十秒甚至几分钟开发人员自然不愿意在本地频繁执行。Oxlint 的优势在于它是用 Rust 写的启动快、扫描快官方文档宣称性能比 ESLint 高数十倍。具体倍数会因机器、规则集、项目规模不同而不同但“明显快于 ESLint”是它在社区里被认可的核心印象。2.2 和 ESLint 的关系Oxlint 并不是要立刻取代 ESLint。它做了大量规则名称上的兼容很多 ESLint 核心规则和 TypeScript ESLint 规则在 Oxlint 里可以直接用同样的名字或近似的插件前缀来配置。这意味着已有 ESLint 配置的团队可以先用 Oxlint 做快速扫描规则语义基本一致迁移成本相对小你也可以让两者共存Oxlint 负责日常快速反馈ESLint 负责更复杂的生态插件检查。所以它非常适合作为 anti-slop 检查的第一道自动闸门快、严格、开箱即用。2.3 安装方式Oxlint 通过 npm 发布会为不同平台下载对应的预编译二进制。在项目里执行npm install oxlint --save-dev或者临时使用npx oxlint --version只要能顺利跑出版本号就说明环境基本就绪。3. 环境准备与快速起步3.1 基础环境在开始之前建议准备好以下环境Node.js建议使用当前 LTS 版本例如 18、20 或 22npm 或 yarn / pnpm用于安装 oxlint一个 JavaScript 或 TypeScript 项目目录IDE 终端或者直接用系统终端。Oxlint 是预编译二进制对 Node 版本本身依赖不算强但使用 LTS 版本能避免很多 npm 安装层面的兼容问题。3.2 创建示例工程为了后续演示我建议你跟着创建一个最小工程mkdir anti-slop-demo cd anti-slop-demo npm init -y npm install oxlint --save-dev然后创建源码目录mkdir src3.3 第一次运行在项目根目录执行npx oxlint src如果没有配置规则Oxlint 会使用默认规则集进行扫描。你会看到类似这样的输出Found 0 warnings and 0 errors这并不是说 Oxlint 什么都没做而是当前代码还没有触发规则。接下来我们要把规则收紧让它真正发挥 anti-slop 的作用。4. anti-slop 核心规则解析Oxlint 的规则大体上可以按类别理解。常见分类包括correctness正确性相关suspicious可疑代码style风格相关perf性能相关restriction限制性规则。anti-slop 配置的核心思路是把 correctness 和 suspicious 变成 error把 style 和 restriction 按团队接受度逐步开启。下面我们挑一些典型的 anti-slop 规则展开。4.1 变量与声明no-var禁止使用var声明变量。var的问题在于函数级作用域让人很难判断变量生命周期容易产生隐式依赖。在 anti-slop 规则里它应该直接报 error。prefer-const如果变量声明后从未重新赋值应使用const。这个规则很便宜但效果很好。它迫使你在写代码的时候想清楚“这个变量到底会不会变”。AI 生成代码时特别喜欢大量使用let这个规则能极大减少这种“保险起见”的写法。no-unused-vars禁止声明了但从未使用的变量。未使用变量在重构时非常迷惑人。你以为某个变量还在用实际上已经没有任何引用。这个规则应该配置为 error。下面是一段 slop 风格的典型代码var userName Alice; let unusedValue 42; let otherValue 1; otherValue 2;在no-var、prefer-const、no-unused-vars全开的情况下这段代码会同时触发三类警告。4.2 类型安全no-explicit-any禁止显式使用any类型。any是 TypeScript 里最大的“后门”。它表面上解决了类型报错实际上把类型检查全部关掉了。AI 生成的 TypeScript 代码里any出现频率非常高因为它是最省事的绕过方案。anti-slop 规则里no-explicit-any应该设置为 error。如果你的项目还没有开启 TypeScript 插件可以在 Oxlint 配置中声明插件{ plugins: [typescript], rules: { typescript/no-explicit-any: error } }这里我建议你在实际项目中先运行npx oxlint --help或查看当前版本文档确认插件前缀写法。不同版本的 Oxlint 对插件前缀的处理可能略有差异。4.3 函数与复杂度max-params限制函数参数数量。参数过多的函数往往承担了太多职责。比如function createUser(id, name, email, age, address, phone, isAdmin) { ... }这种函数要么拆分成对象参数要么按职责拆分成多个函数。Oxlint 是否支持该规则取决于版本建议在项目中用--rules或配置文件先验证。对于复杂度问题我推荐从两个方向思考当一段代码出现多层if嵌套时考虑用 early return 或函数提取当函数体过长时考虑抽象子函数。这些虽然不一定都能靠 lint 规则自动拦住但max-lines、max-depth等规则可以作为辅助信号。4.4 错误处理no-empty禁止空代码块。它最常见的就是空catch块try { riskyCall(); } catch (e) { // 什么都不做 }这种写法等于把错误信息直接吞掉了。一旦线上出问题你根本不知道这里发生了什么。no-empty应该配置为 error。4.5 逻辑与运算符eqeqeq强制使用和!。宽松比较在 JavaScript 里会做隐式类型转换容易掩盖真实的类型问题。AI 生成的代码偶尔会输出if (result null)这种写法虽然这里语义可能没错但为了统一和可预测性建议全项目强制使用严格比较。no-constant-condition禁止在条件判断里使用常量表达式。比如while (true)如果没有合理的退出条件或者if (1)这种写法都有问题。这个规则能帮助检查出逻辑里明显的草率。4.6 调试与日志no-debugger禁止debugger语句。no-console禁止console.log。这两个规则在具体项目里可以有不同的处理方式no-debugger建议直接 error因为留着它进线上环境很危险no-console可以考虑配置成 warn允许开发时使用但在 CI 中通过参数把 warning 变成 error。4.7 规则汇总表我整理了一张适合 anti-slop 的规则表你可以直接抄到配置里Slop 特征规则建议 severity使用varno-varerror未使用变量no-unused-varserror可以用const却用letprefer-consterror显式anyno-explicit-anyerror空代码块/空 catchno-emptyerror宽松比较eqeqeqerror恒真/恒假条件no-constant-conditionerrordebugger残留no-debuggererrorconsole.log残留no-consolewarn直接使用evalno-evalerror这些规则本身并不冷门但它们组合在一起就构成了 anti-slop 的基本防线。5. 实战搭建一个 anti-slop 检查工程5.1 项目结构我们在之前的anti-slop-demo基础上创建如下结构anti-slop-demo/ ├── package.json ├── .oxlintrc.json └── src/ ├── sloppy.js └── clean.ts5.2 编写.oxlintrc.json在项目根目录创建.oxlintrc.json{ plugins: [typescript], categories: { correctness: error, suspicious: error, style: warn, perf: warn, restriction: warn }, rules: { no-var: error, no-unused-vars: error, prefer-const: error, no-empty: error, eqeqeq: error, no-constant-condition: error, no-debugger: error, no-console: warn, no-eval: error, typescript/no-explicit-any: error } }然后在package.json中补充脚本{ scripts: { lint: oxlint src -c .oxlintrc.json --deny-warnings } }--deny-warnings的作用是把 warning 也当成失败适合在 CI 里使用。如果你的 Oxlint 版本不支持这个参数可以使用--max-warnings0或者直接在脚本里加|| true做临时处理但正式环境不建议绕过去。5.3 编写一份“问题代码”在src/sloppy.js写入以下内容。这是一段刻意写得很“slop”的代码几乎每行都踩了规则// 文件路径src/sloppy.js function get(url) { return { data: response from url }; } var userName Alice; let unusedValue 42; function fetchData(url) { if (url null) { console.log(url is null); } var data get(url); var result data; return result; } function processOrder(items) { var total 0; for (var i 0; i items.length; i) { var item items[i]; if (item.price 100) { if (item.discount 0) { total total item.price * (1 - item.discount); } else { total total item.price; } } else { total total item.price; } } return total; } function handleError() { try { riskyCall(); } catch (e) { // 什么都不做 } } const anyValue getAnyValue(); const stringValue anyValue.toFixed(2);注意getAnyValue在这里没有定义这是为了模拟“外部接口返回any”的场景。如果你用node直接运行这段代码它会报错但我们这里只是演示 lint不需要实际运行。5.4 运行 Oxlint在项目根目录执行npm run lint预期会得到一系列报错和警告包括var使用未使用变量unusedValue可以用const却用了let宽松比较空catch块console.log残留any类型使用。这些正是 anti-slop 想拦截的典型问题。5.5 编写修复后的代码现在创建一个src/clean.ts展示同样功能但更干净的写法// 文件路径src/clean.ts interface Data { ok: boolean; body: string; } interface OrderItem { price: number; discount: number; } function get(url: string): Data { return { ok: true, body: response from url }; } function fetchData(url: string): Data { if (!url) { throw new Error(url is required); } return get(url); } function processOrder(items: OrderItem[]): number { return items.reduce((total, item) { const discountedPrice item.discount 0 ? item.price * (1 - item.discount) : item.price; return total discountedPrice; }, 0); } function handleError(): void { try { riskyCall(); } catch (error) { console.error(riskyCall failed, error); throw new Error(riskyCall failed, { cause: error }); } }这段代码里明显的变化是去掉了var使用const或let补充了明显的类型定义空catch块里至少做了错误上报并且重新抛出用 early return 代替了多层if用reduce简化了循环累加逻辑。如果你在项目里同时使用 ESLint可能会对throw new Error(riskyCall failed, { cause: error })的 ES2022 特性有兼容要求这里作为演示可以按需调整。5.6 验证效果修改.oxlintrc.json后把clean.ts纳入检查范围npx oxlint src -c .oxlintrc.json如果sloppy.js还在目录中它依然会报错。实际项目中你应该逐步修复存量代码或者用 ignore 机制暂时排除旧目录把精力集中在新代码上。6. 与 ESLint 的迁移和共存策略6.1 为什么要两者共存Oxlint 虽然快但在生态丰富度上暂时还无法完全替代 ESLint。比如一些非常具体的 React 插件规则、自定义规则、复杂 AST 检查可能还是 ESLint 更全面。所以实际工程中更务实的做法是Oxlint 承担日常快速检查和 anti-slop 基础规则ESLint 承担项目特定的生态规则或自定义规则两者共享同一套代码风格理念但不要求完全互相覆盖。6.2 双引擎工作流在package.json中可以做如下拆分{ scripts: { lint:oxlint: oxlint src -c .oxlintrc.json --deny-warnings, lint:eslint: eslint src --ext .js,.ts, lint: npm run lint:oxlint npm run lint:eslint } }在本地开发时你可以只运行npm run lint:oxlint因为它的反馈速度很快。在 push 之前再跑完整的npm run lint。6.3 CI 中的处理如果项目放在 GitHub可以在 workflow 中加一个简单的步骤- name: Run Oxlint anti-slop check run: npx oxlintlatest src -c .oxlintrc.json --deny-warnings在 Jenkins、GitLab CI 或 CircleCI 中也是类似思路先安装依赖再执行 lint 脚本。关键是让 lint 失败时流水线失败而不是仅仅打印警告继续运行。6.4 渐进式迁移建议如果项目已经有很多历史代码不要把 anti-slop 规则一次性全开否则会有几百上千个报错团队很容易放弃。推荐的做法是先开no-var、no-debugger、no-eval这类安全问题再开no-unused-vars、prefer-const、eqeqeq最后开typescript/no-explicit-any、no-empty等需要改代码逻辑的规则用目录级 ignore 排除老代码优先保证新提交的代码符合规则设置一个 deadline在下个版本迭代中逐步清理存量问题。这样既不会让团队陷入“改旧代码”的泥潭又能让 anti-slop 从新代码开始生效。7. 常见问题与排查思路Oxlint 在使用过程中会遇到一些问题我整理了几个高频场景。问题现象常见原因解决思路配置了规则却不生效规则名或插件前缀写错查看当前版本支持的规则列表确认插件是否声明与 ESLint 同时跑出现重复报错两边规则重叠划分职责或者在一侧关闭重复规则老项目报错太多规则对存量代码过严用 ignore 排除旧目录或先设置 warn提示 unknown rule当前 Oxlint 版本未实现该规则改用 categories 批量控制或者升级版本本地不报错CI 报错CI 中 node_modules 没安装完整检查 CI 安装依赖步骤和 npm lock 文件不知道规则具体触发在哪一行输出信息不够直观使用--format等参数调整输出格式下面是几个问题的详细排查方法。7.1 规则配置不生效怎么办先运行npx oxlint --help查看当前版本支持的参数和配置入口。然后确认你的配置文件是否被正确读取。可以使用npx oxlint src -c .oxlintrc.json --format stylish如果仍然没有报错尝试在源码中故意写一行明显违规的代码var debugTest 1;然后再运行。如果还是没有no-var报错说明配置路径或规则名有问题。7.2 插件规则名怎么写Oxlint 为了兼容 ESLint 生态很多规则既可以写插件前缀形式也可以直接写规则名。比如{ rules: { typescript/no-explicit-any: error } }也可以尝试{ rules: { no-explicit-any: error } }不同版本可能表现不同。最稳妥的方式是查看官方文档中的规则列表或者在配置里先设置 categories让整个类别的默认规则生效再聚焦调整个别规则。7.3 如何忽略特定文件如果某个文件确实需要特殊处理可以在配置中增加 ignore 字段或者使用注释禁用// oxlint-disable-next-line const x: any someApi();不过 anti-slop 的灵魂是“减少例外”。如果某个规则在项目里频繁被 disable那就应该重新审视这个规则是否适合团队而不是放任不管。8. 最佳实践与工程建议8.1 将规则写入团队规范文档工具配置只能保证“机器可检查”但很多质量要求是工具暂时检查不出来的。建议把 anti-slop 的核心理念写进团队规范新增代码不得使用var新增代码必须显式声明返回类型和参数类型避免any泄漏错误处理不允许空catchconsole.log提交前必须清理或改为结构化日志函数尽量控制在 30 行以内嵌套最多不超过 3 层。这些约定和.oxlintrc.json一起放进代码库新成员入职时看一份文档就能明白项目的代码底线。8.2 设置“警告即失败”在 CI 中建议使用--deny-warnings或--max-warnings0。如果只把 error 视为失败warning 很容易被忽略。长此以往warning 数量会膨胀到没人关心。与其容忍 50 个 warning不如让流水线一开始就失败逼着大家处理。不过在项目迁移期这个策略可以放宽先保证错误级别规则全量通过warning 级别规则在指定目录内逐步清零。8.3 与 Prettier 分工建议不要用 lint 去处理格式问题。格式问题应该交给 Prettiernpm install prettier --save-dev npx prettier --write srcOxlint 专注语义和代码质量Prettier 专注格式风格。这样配置职责清晰不会出现 Oxlint 和 Prettier 因为换行、引号、缩进等格式化问题互相冲突的情况。8.4 AI 生成代码的强制检查如果你或团队在大量使用 AI 生成代码我建议给 AI 工具设定一个“提交前检查清单”代码必须通过 Oxlint anti-slop 检查不允许出现any和as any不允许新增未使用的变量错误处理必须包含日志和重新抛出复杂的逻辑必须配合函数注释。AI 生成的代码天然倾向于“最省事”的写法而这些规则恰好能拦住最省事的写法。不要指望 AI 自动遵守规则除非你在提示词里反复声明并且代码提交前真的有一道自动门禁。8.5 定期审视规则集anti-slop 不是一份永远不变的清单。随着团队对代码质量的要求变化规则也应该演进每个季度检查一次.oxlintrc.json中的规则是否还有效从 warning 中挑出高频问题升级为 error关闭那些团队完全无法接受的限制性规则把新出现的“坏味道”沉淀成新规则。好的规则集不是管得越多越好而是每一类规则都能对应一个真实发生过的问题。8.6 避免把 lint 变成教条最后提醒一句lint 是工具不是目的。anti-slop 想要的是可读、可维护、可长期演进的代码而不是“满足所有 lint 规则但依然难以理解”的代码。遇到规则和实际场景冲突时先判断规则背后的意图再决定是调整代码还是调整规则。9. 最后说点什么写抗 slop 的规则本质上是在和“代码只要能跑就行”这种态度对抗。你可能觉得var改const很小、空catch补一句日志也改变不了什么但这些小决定累积起来决定了一个项目十年后是被维护还是被重写。Oxlint 的价值在于它把很多以前靠代码评审经验才能发现的问题变成了一条条机器可执行的规则。它不能代替你成为一个好工程师但它能帮你在团队内部建立一条相对稳定的质量底线。真正的 hard part 仍然是人你愿不愿意在提交之前多花三十秒把那块any改成明确的类型把那个吞掉异常的catch改成真正面向失败的代码。如果这篇文章里有一两节内容能在你的项目里落地那它的价值就实现了。下一步建议你从“先建一份.oxlintrc.json”开始把no-var、no-unused-vars、prefer-const这“三驾马车”跑起来再逐步向更严格的规则收敛。
返回列表