🛡️ 代码质量的“埃癸斯”:为什么你的项目需要这面更懂业务的 ESLint 神盾?

在前端项目的长期维护中,我们经常会遇到这样的痛点:代码能跑,但"味道"不对。

虽然我们已经有了 ESLint 标准规则、Prettier 格式化,甚至引入了 SonarJS 这样严格的质量检测工具,但在实际的业务场景(特别是大型复杂应用)中,通用的规则往往显得"笨重"------要么太宽泛起不到约束作用,要么太死板导致满屏 // eslint-disable

为了解决这些"现有规则无法满足的特定需求",我开发了 eslint-plugin-aegis

Aegis (埃癸斯) 是希腊神话中雅典娜和宙斯持有的神盾,象征着保护、权威与智慧。我希望这个插件能像 Aegis 一样,成为守护代码质量的一道防线。

💡 背景:我们为什么需要它?

既然社区里已经有几千个插件了,为什么要造这个轮子?

核心原因只有一个:灵活性与业务场景的深度结合

很多通用规则在设计时,很难顾及到具体的业务上下文。例如:

  • 重复字符串检测 :通用规则会把所有重复字符串都揪出来。但在做国际化(i18n)时,t('confirm') 出现几十次是很正常的,强制提取常量反而降低了可读性。
  • 魔法数字 :通用规则禁止所有数字。但在写 CSS-in-JS 或配置 UI 布局时,exclude: ['width', 'opacity'] 这种简单的忽略名单往往不够用,我们需要更强大的正则匹配来忽略一类属性。
  • 复杂对象类型 :虽然 TS 具备强大的推导能力,但在面对复杂对象时,缺乏显式定义的隐式推导过于臃肿的内联类型(Inline Type Literal) 会让代码契约变得模糊且难以复用,显著增加项目的维护难度。

eslint-plugin-aegis 就是为了解决这些细微但影响深远的痛点而生。


🚀 核心能力概览

1. 灵活可控的重复字符串检测:no-duplicate-string

痛点sonarjs/no-duplicate-string 很好,但它"杀伤力"太大了。有时候我只是在调用打点函数或者国际化函数,它也报错。

Aegis 的去重规则支持了更细粒度的控制:

  • 🎯 基于上下文的忽略 :支持配置 ignorePatterns 正则。不仅可以忽略特定格式的字符串(如 URL、CSS 单位),更强大的是它是可以忽略特定函数调用中的字符串
    • 场景t('submit')track('submit') 中的 'submit' 虽然重复,但只要配置正则匹配 ttrack 函数名,就能自动忽略这些调用中的字符串,无需手动 disable。
  • 🧩 精准避让类型定义 :自动忽略 TypeScript 的字面量类型定义(如 type Status = 'active' | 'active'),这通常是合法的业务定义。

配置项 (Options)

属性 类型 默认值 说明
threshold integer 2 重复次数阈值。达到该值时报错。
minLength integer 5 触发检查的字符串最小长度。
ignoreStrings string[] [] 精确匹配忽略的字符串列表。
ignorePatterns string[] [] 正则表达式列表,匹配的字符串或所在的函数名将被忽略。
ignoreTSLiteralTypes boolean true 是否忽略 TypeScript 的字面量类型 (例如 type T = 'draft')。

示例配置

javascript 复制代码
"aegis/no-duplicate-string": ["error", {
  "threshold": 2,
  "minLength": 2,
  "ignoreStrings": [
    "application/json", // 常见 MIME
    "YYYY-MM-DD" // 日期格式
  ],
  "ignorePatterns": [
    "^/", // 路径
    "^http(s)?://", // URL
    "^#([0-9A-Fa-f]{3,6})$", // HEX 颜色
    "^[0-9]+(px|rem|em|vh|vw|%)$", // CSS 单位
    "^t$" // 忽略国际化函数 t('...') 中的字符串
  ]
}]

2. 拒绝隐式黑盒:no-implicit-complex-object

痛点 :接手老代码时,看到 const config = { ...50个属性... } 且没有类型定义,想知道这个对象到底长什么样,只能靠猜或者看赋值。而且在 Vue 3 中,不显式定义泛型的 ref 往往会降低类型提示的直观性。

这个规则强制要求:当对象字面量的属性超过一定数量(默认 2 个)时,必须显式定义 Interface 或 Type。

这不仅仅是为了 TS 类型检查,更是为了代码即文档

  • ⚡️ Vue 3 友好 :自动识别 ref()reactive()
  • 🔧 渐进式 :可以通过 propertyThreshold 调整阈值,逐步收紧标准。
  • 📥 函数参数支持 :不仅检查变量赋值,还会自动检查函数参数中的复杂内联类型(如 function(user: { name: string, age: number }))。

配置项 (Options)

属性 类型 默认值 说明
propertyThreshold integer 2 属性数量阈值。当对象属性达到该值时且未显式定义类型时报错。
ignoreVue3Wrappers boolean false 是否忽略 Vue 3 的 ref()reactive() 包装对象。
ignorePatterns string[] [] 正则表达式列表,匹配的变量名将被忽略。

示例配置

javascript 复制代码
"aegis/no-implicit-complex-object": ["error", {
  "propertyThreshold": 2,
  "ignorePatterns": [".*Rules$"]
}]
typescript 复制代码
// ❌ Error: 复杂对象未定义类型
const user = { name: "Li", age: 18, role: "admin", dept: "IT" };

// ✅ Pass: 显式契约,结构清晰
const user: IUser = { name: "Li", age: 18, role: "admin", dept: "IT" };

3. 严谨的魔法数字:no-magic-numbers-strict

痛点 :原生 no-magic-numbers 很难用。在 UI 开发中,width: 100opacity: 0.5 都要提取常量实在太繁琐。

Aegis 复刻并增强了这一规则,加入了强大的正则过滤能力:

  • 🎨 属性名正则过滤 :通过 ignorePropertyPatterns,你可以忽略 width, minHeight, flexGrow 甚至是所有以 Cls 结尾的属性中的数字。
  • ⚙️ 函数调用正则过滤setTimeout(fn, 500) 中的 500 是魔法数字吗?也许是,但在这种通用函数中,我们通常希望放行。Aegis 允许你通过正则忽略特定函数(如 setTimeout, Date)的参数。

配置项 (Options)

属性 类型 默认值 说明
ignore number[] [] 忽略的具体数字列表。
detectObjects boolean false 是否检测对象属性中的数字。
enforceConst boolean false 是否强制要求变量声明使用 const
ignoreArrayIndexes boolean false 是否忽略数组索引 arr[0]
ignoreEnums boolean false 是否忽略 enum 定义中的数字。
ignoreTypeIndexes boolean false 是否忽略 TS 类型索引 Data[0]
ignoreNumericLiteralTypes boolean false 是否忽略 TS 数字字面量类型。
ignoreReadonlyClassProperties boolean false 是否忽略类中的 readonly 属性初始值。
ignoreDefaultValues boolean false 是否忽略参数默认值中的数字。
ignoreClassFieldInitialValues boolean false 是否忽略类字段初始值。
ignorePropertyPatterns string[] [] 正则表达式列表,匹配的对象属性名将被忽略。
ignoreCalleePatterns string[] [] 正则表达式列表,作为这些函数参数的数字将被忽略。

示例配置

javascript 复制代码
"aegis/no-magic-numbers-strict": ["error", {
  "ignore": [-1, 0, 1, 2],
  "ignoreArrayIndexes": true,
  "ignoreTypeIndexes": true,
  "ignoreEnums": true,
  "detectObjects": true,
  "enforceConst": true,
  "ignorePropertyPatterns": ["^width$|Width$"],
  "ignoreCalleePatterns": ["^(Date|setTimeout|setInterval|delay)$"]
}]

🛠 快速开始

插件已发布至 npm,支持 ESLint Flat Config。

安装

bash 复制代码
npm install eslint-plugin-aegis --save-dev
# or
yarn add eslint-plugin-aegis -D

配置

eslint.config.js 中引入并配置:

javascript 复制代码
import aegis from "eslint-plugin-aegis";

export default [
  // 1. 使用推荐配置 (开箱即用)
  aegis.configs.recommended,

  // 2. 或者按需深度定制
  {
    plugins: {
      aegis,
    },
    rules: {
      // 检测重复字符串
      "aegis/no-duplicate-string": [
        "error",
        {
          threshold: 2, // 阈值
          minLength: 2, // 最小检测长度
          ignoreStrings: [], // 忽略的字符串列表
          ignorePatterns: ["^t$", "^track$"], // 忽略 i18n 和埋点函数
        },
      ],
      // 检测魔法数字
      "aegis/no-magic-numbers-strict": [
        "error",
        {
          ignore: [-1, 0, 1, 2], // 忽略的魔法数字
          ignoreEnums: true, // 忽略枚举定义
          ignoreTypeIndexes: true, // 忽略类型索引
          ignoreArrayIndexes: true, // 忽略数组索引
          detectObjects: true, // 检测对象
          enforceConst: true, // 允许使用 const 声明魔法数字,非 const 声明的会提示
          ignorePropertyPatterns: ["^width$|Width$"], // 忽略的属性
          ignoreCalleePatterns: ["^(Date|setTimeout|delay)$"], // 忽略的调用
        },
      ],
      // 检测隐式复杂对象
      "aegis/no-implicit-complex-object": [
        "error",
        {
          propertyThreshold: 2,
          ignorePatterns: [".*Rules$"],
        },
      ],
    },
  },
];

结语

工具的目的是服务于人,而不是束缚人。eslint-plugin-aegis 的初衷就是在严格的代码质量要求流畅的开发体验之间找到一个平衡点。

如果你也在被通用的 Lint 规则误伤,或者希望对团队代码风格有更细粒度的掌控,欢迎尝试一下 Aegis,也欢迎来 GitHub 提 Issue 或 PR,共同完善这面"神盾"!

🔗 GitHub : github.com/LLLaiYoung/...


Let's build better code, together.

相关推荐
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte4 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
NEXT065 小时前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法