工程质量基线: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 修复,没有实质业务逻辑变化。
主要变化只有两类:
- Vue 模板属性排序:
eslint-plugin-vue的vue/attributes-order规则会重新排列属性顺序,例如把ref放到前面,把v-if、v-for放在class之前,把@click等事件放到后面。 - 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 |
String 改 string |
不影响运行时 | 可归入 lint 修复 |
Object 改为 object / unknown / Record |
可能影响类型边界 | 需要逐处判断 |
@ts-ignore 改 @ts-expect-error |
不影响运行时 | 可批量替换,但要跑类型检查 |
如果把格式化、lint 修复和业务需求混在同一个提交里,review 时会非常痛苦。最稳妥的做法是:
- 先单独做 Prettier 格式化。
- 再单独做 ESLint 自动修复。
- 最后处理需要人工判断的类型问题。
- 业务改动另起提交。
这样每个提交的意图都很清楚,也方便回滚。
六、个人落地流程
我现在更倾向于把 ESLint 和 Prettier 分成三步落地。
第一步,先解除历史问题对本地开发的阻断。
如果旧项目问题很多,可以临时关闭构建阶段的强制 ESLint 插件,让项目先能正常启动和调试。
第二步,用命令集中识别问题。
格式化问题交给 Prettier:
npm run lint:format
代码质量问题交给 ESLint。能自动修复的先自动修复,不能自动修复的再逐类处理。
第三步,重新建立质量门禁。
当历史问题收敛后,再把 ESLint 接回构建、提交检查或 CI 流程中。这样工具就不是“拦路石”,而是项目质量的兜底机制。
七、实践 Checklist
- 先确认 ESLint 和 Prettier 的职责边界。
- 历史项目不要一开始就让 lint 阻断所有本地运行流程。
- Prettier 改动单独提交,不和业务逻辑混在一起。
- ESLint 自动修复和人工类型修复分开处理。
@ts-ignore优先替换为@ts-expect-error。- 避免使用
Function、Object、String这类过宽或不推荐的类型。 - 大批量文件变更先判断是否纯机械改动,再决定是否保留。
- 质量工具稳定后,再接入构建、提交检查或 CI。
总结
ESLint 和 Prettier 解决的是两类不同问题。
Prettier 统一格式,让代码看起来一致。ESLint 约束质量,让代码在类型、安全性和项目规范上更可靠。
在历史项目里,最容易出问题的不是工具本身,而是落地节奏:如果一上来就让所有规则阻断开发,团队很快会绕开它;如果只格式化不处理类型边界,工程质量也不会真正提升。
更稳的方式是先区分问题类型,再分批收敛:格式归格式,lint 归 lint,业务归业务。这样 ESLint 和 Prettier 才能真正成为项目的质量基线,而不是一次性的清理动作。

浙公网安备 33010602011771号