工程质量基线:ESLint和Prettier个人实践

工程质量基线:ESLint 和 Prettier 个人实践

前言

接手一个已有前端项目时,ESLint 和 Prettier 往往不是“从零配置”的问题,而是“如何让它们重新进入日常开发流程”的问题。

项目本身已经有 ESLint 插件和格式化脚本,但历史代码里存在不少不符合规则的写法。如果一开始就把所有检查都接入构建流程,很容易出现一种尴尬状态:工具是对的,但每次启动、构建、提交都会被旧问题阻断,最后大家只能选择绕开工具。

这次实践的重点不是新增一套复杂规范,而是重新确认两件事:

  • ESLint 用来发现代码质量、类型边界和潜在风险。
  • Prettier 用来统一格式,减少无意义的代码风格争论。

工程质量工具真正有价值的地方,是把“个人习惯”收敛成“项目基线”。

一、先处理构建阻断,而不是直接清空所有问题

项目里原本在 Vite 构建配置中接入了 EslintPlugin

// EslintPlugin({
//   cache: false,
//   include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
// }),

这段配置的作用是让项目在运行或构建时自动检查 src 下的 Vue、TypeScript、TSX 文件。

但接手时,项目已经积累了一批历史 lint 问题。如果继续让 ESLint 在每次运行时阻断流程,开发体验会非常差。所以我先临时注释掉这段插件配置,避免“工具阻断开发”,再通过命令和局部修复逐步清理。

这个动作不是放弃 ESLint,而是把 ESLint 从“启动即阻断”调整为“先人工收敛,再重新接入质量门禁”。

二、ESLint 负责代码质量,不负责格式美观

ESLint 检查的重点是代码质量和潜在风险。例如:

  • TypeScript 类型是否过宽。
  • 是否使用了不推荐的类型写法。
  • 是否存在已经被规则禁止的注释抑制。
  • Vue 模板属性顺序是否符合项目规范。

在一次自动修复后,项目内出现了 121 个文件改动,但这些改动都属于纯 lint 修复,没有实质业务逻辑变化。

主要变化只有两类:

  1. Vue 模板属性排序:eslint-plugin-vuevue/attributes-order 规则会重新排列属性顺序,例如把 ref 放到前面,把 v-ifv-for 放在 class 之前,把 @click 等事件放到后面。
  2. TypeScript 泛型修正:部分 API 文件中把 Map<String, Object> 调整为 Map<string, Object>

这类改动看起来文件很多,但本质是机械调整。实际统计是 478 行新增、478 行删除,净变化为 0,说明主要是规则驱动的重排或替换。

判断这类变更时,最重要的是先问一句:它有没有改变业务逻辑?

如果只是模板属性顺序、大小写类型修正、缩进和换行,这类改动可以集中提交,提交说明里明确标注为 lint 或 format 修复。

三、典型 ESLint 问题和修复思路

1. 用 @ts-expect-error 替代 @ts-ignore

示例报错:

D:\working\ecms-front-end\src\utils\tree.ts
  283:1  error  Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free  @typescript-eslint/ban-ts-comment

// @ts-ignore 的作用是屏蔽下一行 TypeScript 类型检查错误。

在一些 Vite 项目中,import.meta.glob 返回的模块映射对象可能没有合适的字符串索引签名,或者返回类型和 defineAsyncComponent 期望的参数不完全匹配。为了让编译继续通过,历史代码里可能会直接写:

// @ts-ignore

ESLint 更推荐改成:

// @ts-expect-error

两者在“下一行确实有类型错误”时效果一致,都会跳过这一行的类型检查。区别在于:如果下一行未来已经没有类型错误,@ts-ignore 会静默保留,而 @ts-expect-error 会主动报错,提醒你删除多余注释。

所以,把 @ts-ignore 批量替换成 @ts-expect-error 通常不会带来运行时影响。它改变的是类型检查阶段的反馈能力,让历史抑制注释不至于一直沉在代码里。

2. 避免使用 Function 作为类型

示例报错:

D:\working\ecms-front-end\src\utils\is.ts
  68:50  error  Don't use `Function` as a type. The `Function` type accepts any function-like value.

原代码:

export const isFunction = (val: unknown): val is Function => {
  return typeof val === 'function'
}

问题在于,Function 类型过于宽泛。它几乎接受任何可调用对象,调用时也无法提供参数和返回值的类型约束,类型安全性很弱。

可以改成更明确的函数签名:

export const isFunction = (val: unknown): val is (...args: unknown[]) => unknown => {
  return typeof val === 'function'
}

这个写法表达得更清楚:val 是一个可以接收若干未知参数,并返回未知值的函数。

3. 避免使用 Object 作为类型

示例报错:

D:\working\ecms-front-end\src\views\Login\components\useLogin.ts
  31:40  error  Don't use `Object` as a type  @typescript-eslint/ban-types

TypeScript 中的 Object 并不等于“普通对象”。它表示任意非 null、非 undefined 的值,数字、字符串、布尔值等原始类型也可能落入这个范围。

常见选择可以按语义区分:

目标语义 推荐类型
任意值 unknown
任意对象 object
明确键值结构 Record<string, unknown>
非空值 NonNullable<unknown>

所以,看到 Object 时不要机械改成 object,要先看它到底想表达什么。

如果是 Map<String, Object> 这类写法,至少应先把大写 String 改为小写 string。至于 Object 是否继续保留,则要结合实际数据结构判断。

四、Prettier 负责格式统一,不负责判断代码好坏

项目里的格式化命令是:

{
  "lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\""
}

执行:

npm run lint:format

Prettier 主要处理格式问题,例如:

  • 模板缩进对齐。
  • 长属性自动换行。
  • 自闭合标签格式统一。
  • import 语句按规则换行。
  • CSS 空格和换行统一。

vehicleOperationHistory/index.vue 为例,格式化后的变化主要是缩进、CSS 空格、属性断行,没有改动 API 调用、方法逻辑、组件属性或页面功能。

这就是 Prettier 的定位:它不告诉你代码写得好不好,只负责把代码排版成统一样子。

五、大批量格式化改动要单独看待

ESLint 和 Prettier 都可能制造“大量文件变更”的视觉压力。

但工程上更重要的是区分变更类型:

变更类型 是否影响逻辑 处理方式
Prettier 缩进、换行、空格 通常不影响 单独提交为 format
Vue 属性排序 通常不影响 单独提交为 lint
Stringstring 不影响运行时 可归入 lint 修复
Object 改为 object / unknown / Record 可能影响类型边界 需要逐处判断
@ts-ignore@ts-expect-error 不影响运行时 可批量替换,但要跑类型检查

如果把格式化、lint 修复和业务需求混在同一个提交里,review 时会非常痛苦。最稳妥的做法是:

  1. 先单独做 Prettier 格式化。
  2. 再单独做 ESLint 自动修复。
  3. 最后处理需要人工判断的类型问题。
  4. 业务改动另起提交。

这样每个提交的意图都很清楚,也方便回滚。

六、个人落地流程

我现在更倾向于把 ESLint 和 Prettier 分成三步落地。

第一步,先解除历史问题对本地开发的阻断。

如果旧项目问题很多,可以临时关闭构建阶段的强制 ESLint 插件,让项目先能正常启动和调试。

第二步,用命令集中识别问题。

格式化问题交给 Prettier:

npm run lint:format

代码质量问题交给 ESLint。能自动修复的先自动修复,不能自动修复的再逐类处理。

第三步,重新建立质量门禁。

当历史问题收敛后,再把 ESLint 接回构建、提交检查或 CI 流程中。这样工具就不是“拦路石”,而是项目质量的兜底机制。

七、实践 Checklist

  • 先确认 ESLint 和 Prettier 的职责边界。
  • 历史项目不要一开始就让 lint 阻断所有本地运行流程。
  • Prettier 改动单独提交,不和业务逻辑混在一起。
  • ESLint 自动修复和人工类型修复分开处理。
  • @ts-ignore 优先替换为 @ts-expect-error
  • 避免使用 FunctionObjectString 这类过宽或不推荐的类型。
  • 大批量文件变更先判断是否纯机械改动,再决定是否保留。
  • 质量工具稳定后,再接入构建、提交检查或 CI。

总结

ESLint 和 Prettier 解决的是两类不同问题。

Prettier 统一格式,让代码看起来一致。ESLint 约束质量,让代码在类型、安全性和项目规范上更可靠。

在历史项目里,最容易出问题的不是工具本身,而是落地节奏:如果一上来就让所有规则阻断开发,团队很快会绕开它;如果只格式化不处理类型边界,工程质量也不会真正提升。

更稳的方式是先区分问题类型,再分批收敛:格式归格式,lint 归 lint,业务归业务。这样 ESLint 和 Prettier 才能真正成为项目的质量基线,而不是一次性的清理动作。

posted @ 2026-07-14 17:31  bleemyoung  阅读(1)  评论(0)    收藏  举报