ESLint集成实战:从配置到团队协作的完整指南

英瑞🍀 工具 阅读 2,013
赞 10 收藏
二维码
手机扫码查看
反馈

我的 ESLint 配置,改了三次才稳定下来

我第一次在项目里配 ESLint 时,以为就是装个包、加个配置文件完事。结果团队一拉代码,CI 直接爆红,各种规则冲突、格式报错,连空格都管。折腾了两天,才勉强跑通。后来在多个项目里反复踩坑,终于摸索出一套“能用、不烦、还能真帮上忙”的配置方式。下面分享下我现在的写法。

ESLint集成实战:从配置到团队协作的完整指南

先说结论:我建议用 @eslint/config-array + 共享配置 + IDE 深度集成的组合。但别急着复制,先看看我踩过的坑。

这几种错误写法,别再踩坑了

第一种:直接在 package.json 里写 ESLint 配置。看起来省事,但很快就会失控。比如:

{
  "eslintConfig": {
    "rules": {
      "no-unused-vars": "warn",
      "semi": ["error", "always"]
    }
  }
}

问题在哪?当项目变大,你要区分测试、构建、源码目录的规则时,这种写法根本没法扩展。而且团队成员一改就冲突,根本没法维护。我现在一律用独立的 .eslintrc.jseslint.config.js(ESLint 8.21+ 新格式)。

第二种:全靠 eslint --fix 自动修复,以为万事大吉。其实很多规则是不能自动修的,比如逻辑错误、变量命名风格。更糟的是,有人把 --fix 加到 pre-commit 里,结果每次提交都偷偷改代码,队友 pull 下来发现一堆“格式变更”,根本看不出业务改动。我建议只在开发阶段用 IDE 自动修复,提交前人工确认。

第三种:盲目开启所有规则。比如 eslint:all,听着很安全,实际上会引入大量实验性或过时的规则。我曾经开过,结果项目里一堆 prefer-const 报错,但有些变量确实需要后续赋值,强行改反而降低可读性。现在我只用 eslint:recommended 作为基础,再按需加规则。

核心代码就这几行

我现在主推 ESLint 扁平化配置(flat config),从 ESLint 8.21 开始支持,配置更清晰、作用域更明确。以下是我目前在 React 项目中的配置(TypeScript + Vite):

// eslint.config.js
import js from '@eslint/js';
import ts from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';

export default [
  {
    ignores: ['dist/', 'node_modules/', 'build/']
  },
  js.configs.recommended,
  ...ts.configs.recommended,
  {
    files: ['**/*.{js,jsx,ts,tsx}'],
    languageOptions: {
      parserOptions: {
        ecmaFeatures: { jsx: true }
      }
    },
    plugins: {
      react,
      'react-hooks': reactHooks
    },
    rules: {
      'react/react-in-jsx-scope': 'off', // React 17+ 不需要显式导入
      'react-hooks/rules-of-hooks': 'error',
      'react-hooks/exhaustive-deps': 'warn',
      'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn'
    }
  }
];

为什么这么写?几点关键考虑:

  • 明确忽略目录:避免扫描构建产物,拖慢速度还可能误报
  • 分层继承:先用官方推荐规则打底,再叠加 TypeScript 和 React 插件
  • 环境感知:比如 no-console 在开发时 warn,上线前 error,避免漏掉调试日志
  • 关掉过时规则:React 17 以后 JSX 转换不需要 React 导入,所以关掉对应检查

这套配置在 CI 里跑得稳,本地开发也不卡。最重要的是——团队新人一拉代码就能跑,不用问“你 ESLint 配了吗”。

实际项目中的坑

第一个坑:TypeScript 类型定义和 ESLint 冲突。比如你在 tsconfig.json 里设了 "strict": true,但 ESLint 的 @typescript-eslint/no-explicit-any 又报错。这时候要统一标准:要么全靠 TS 检查,要么让 ESLint 补充。我现在的做法是——TS 负责类型安全,ESLint 负责代码风格和潜在 bug,两者互补但不重叠。

第二个坑:Monorepo 项目里不同子包规则不同。比如工具包用 CommonJS,前端用 ESM,测试文件允许 any。这时候别试图用一个配置搞定所有。我用 flat config 的 files 字段做精准匹配:

{
  files: ['packages/utils/**/*.js'],
  rules: {
    'no-var': 'off' // 兼容老语法
  }
},
{
  files: ['packages/web/**/*.{ts,tsx}'],
  rules: {
    '@typescript-eslint/no-explicit-any': 'error'
  }
}

第三个坑:VS Code 插件和命令行结果不一致。这是因为插件可能用了全局 ESLint,而项目依赖的是本地版本。解决方法很简单:在 VS Code 设置里加一行:

{
  "eslint.packageManager": "pnpm" // 或 yarn / npm
}

并且确保安装了 dbaeumer.vscode-eslint 插件,然后重启编辑器。我之前因为没设这个,本地不报错,CI 却挂了,查了好久才发现是版本差异。

别忘了和 Prettier 和平共处

很多人把 ESLint 和 Prettier 搞成“打架”状态。比如 ESLint 要求分号,Prettier 去掉分号,结果保存一次代码来回震荡。我的方案是:让 Prettier 管格式(缩进、引号、分号),ESLint 管逻辑(未使用变量、错误用法)。具体做法是用 eslint-config-prettier 关掉所有格式相关规则:

npm install -D eslint-config-prettier

然后在配置里加到最后(确保覆盖前面的规则):

import prettier from 'eslint-config-prettier';

export default [
  // ...其他配置
  prettier
];

这样 ESLint 就不会对格式指手画脚了,交给 Prettier 处理。我在 .prettierrc 里统一风格,团队只要装了 Prettier 插件,保存就自动格式化,没人再争论“该用单引号还是双引号”。

最后一点:别追求 100% 规则覆盖

我见过有人为了消除所有 ESLint 警告,把代码改得面目全非,比如硬拆函数、加无意义的注释。其实 ESLint 是工具,不是枷锁。如果某条规则在特定场景下明显不合理,大胆用 eslint-disable-next-line 注释,并写上原因。比如:

// eslint-disable-next-line no-await-in-loop
// 这里必须串行请求,避免 API 限流
for (const id of ids) {
  await fetch(https://jztheme.com/api/item/${id});
}

比起“零警告”,我更看重“有意义的警告”。现在我的项目里 ESLint 报错基本都是真问题,而不是风格之争。

以上是我个人对 ESLint 集成的完整总结,有更优的实现方式欢迎评论区交流。这个技巧的拓展用法还有很多,比如结合 lint-staged 做增量检查,后续会继续分享这类博客。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论