想象你是一家开了 100 家分店的连锁餐厅老板。你发现每家店的出品五花八门:有的厨师随手就放三勺盐,有的盘子边缘挂着酱汁就端上桌,顾客在 A 店吃到的和 B 店完全不是一回事。于是你请来两位专家:一位是质检员,他拿着厚厚的手册逐条检查——食材是否新鲜、火候是否到位、有没有危险操作;另一位是摆盘师,他不关心味道,只负责把每道菜的摆盘、装饰、餐具摆放做到分毫不差。质检员管“对不对”,摆盘师管“美不美”,餐厅口碑这才稳住。 写代码也是同一套逻辑。团队人一多,风格就乱:有人偏好双引号,有人爱单引号;有人行尾加分号,有人坚决不加;更糟的是,有些代码暗藏隐患——用了未定义的变量、写了永远走不到的死分支。ESLint 就是质检员,专门揪出代码里“不对”的问题;Prettier 就是摆盘师,负责把风格统一成同一副漂亮面孔。本文会带你完整搭建这套“标准化后厨”:从规则配置、格式化、两者协作,到 TypeScript 配合、提交前拦截、团队推广与工程化落地。

岗位关联

掌握 ESLint + Prettier,是前端工程师进入工程化的必修课。在团队协作与 AI 辅助编程时代,它让代码质量与风格始终可控,为你省下大量 Code Review 的口舌之争。

目录
  1. 可视化演示
  2. ESLint规则配置
  3. Prettier格式化
  4. 两者集成方案
  5. TypeScript配合
  6. Git Hooks集成
  7. 团队规范落地
  8. 工程化实战
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示ESLint的AST代码分析原理、Prettier格式化前后对比、ESLint+Prettier+Git Hooks集成流水线三种核心场景。

本节配有交互动效(进入视口后自动加载,约 3KB)。

ESLint AST代码分析 源码解析为AST抽象语法树 遍历AST节点,匹配规则检测问题 Source → Parser → AST → Rules → Report 基于AST的静态分析是Lint核心原理

ESLint规则配置

质检员上岗前,必须先领到一本《检查手册》。手册里写着每一条检查项:食材是否过期、刀具是否消毒、生熟是否分开。ESLint 也一样,它的“手册”就是一份配置文件,里面是一条条规则(rules),每条规则都规定了“什么是对的、什么是违规的”。没有手册的质检员只会凭感觉行事,没有规则的 ESLint 也形同虚设。

ESLint 的配置文件通常叫 .eslintrc.js 或 .eslintrc.json。它先通过 parser 指定解析器,告诉 ESLint“我读的是 JavaScript 还是 TypeScript”;再用 extends 继承一套现成的规则集,比如 eslint:recommended 就内置了最常见的问题检查;最后用 rules 字段自定义或覆盖规则,精细到每一类问题。一个最小配置就像一张点菜单:

每条规则的取值代表了问题的严重程度,这个“三级制”正是 ESLint 的灵魂:

回到厨房里:off 相当于这条检查项“不做要求”,warn 是质检员嘀咕一句“下次注意”,error 则是直接把这盘菜打回重做。规则定得越严,后厨越安全,但也要避免过度苛刻把团队逼疯——合理的等级搭配,是规范落地的第一步。

Rule={name, level, options},level∈{off=0, warn=1, error=2}\text{Rule} = \{\text{name},\ \text{level},\ \text{options}\},\qquad\text{level} \in \{\text{off}=0,\ \text{warn}=1,\ \text{error}=2\}
一条规则由“名字 + 等级 + 选项”构成;等级 0/1/2 分别表示关闭、警告、报错。
  1. Rule(规则条目)一条规则就像手册里的一行检查项,包含名字、等级和附加选项三要素。
    Rule={name, level, options}\text{Rule} = \{\text{name},\ \text{level},\ \text{options}\}
  2. name(规则名字)规则的唯一标识,例如 no-console 表示“禁止使用 console 打印”。
    name=no-console\text{name} = \text{no-console}
  3. level(错误等级)等级决定发现违规后的处置方式,0 关闭、1 警告提示、2 直接报错阻止。
    level∈{0, 1, 2}\text{level} \in \{0,\ 1,\ 2\}
  4. options(附加选项)部分规则支持细化配置,比如允许哪些例外写法。
    options={allow:[console.info]}\text{options} = \{\text{allow}: [\text{console.info}]\}
json8 行
{  "parser": "@typescript-eslint/parser",  "extends": ["eslint:recommended"],  "rules": {    "no-console": "warn",    "semi": ["error", "always"]  }}

Prettier格式化

质检员只负责“这东西能不能吃”,至于盘子正不正、酱汁画得圆不圆,他不管。这时候摆盘师登场了。Prettier 就是那位强迫症摆盘师:双引号还是单引号、行尾加不加分号、缩进用两个空格还是四个空格、一行最多写多少个字符——它有一套“黄金比例”,看到不符合的就默默帮你改整齐。

Prettier 的配置一般写在 .prettierrc 文件里,核心是一组风格选项。最常见的几个选项像摆盘的“标准模板”:printWidth 控制每行最大宽度,默认 80 个字符;tabWidth 控制缩进的空格数;semi 决定行尾是否加分号;singleQuote 决定是否统一用单引号。它们共同构成一套风格公式:

Prettier 还有两个贴心配置:.prettierignore 文件像“免检清单”,告诉摆盘师哪些菜不用摆(比如构建产物、第三方库);同时它也能集成进 VS Code,在保存文件的瞬间自动“摆盘”。摆盘师不评判菜品好坏,只负责让每一道菜端上来时都赏心悦目——这正是它和 ESLint 最本质的区别。

Config={printWidth:80, tabWidth:2, semi:true, singleQuote:true}\text{Config} = \{\text{printWidth}: 80,\ \text{tabWidth}: 2,\ \text{semi}: \text{true},\ \text{singleQuote}: \text{true}\}
Prettier 的配置就是摆盘标准模板,统一了行宽、缩进、分号与引号风格。
  1. printWidth(打印宽度)一行代码超过这个宽度就会被折行,就像摆盘时“不能溢出盘沿”。
    printWidth:80\text{printWidth}: 80
  2. tabWidth(缩进宽度)每一级缩进占几个空格,通常取 2 或 4,对应“配菜摆放的间距标准”。
    tabWidth:2\text{tabWidth}: 2
  3. semi(分号)值为 true 表示行尾统一加分号,false 表示尽量不加,但必要的分号 Prettier 仍会保留。
    semi:true\text{semi}: \text{true}
  4. singleQuote(单引号)统一使用单引号还是双引号,避免团队里“引号之争”。
    singleQuote:true\text{singleQuote}: \text{true}

两者集成方案

一家后厨里,质检员和摆盘师各管一摊,但如果两人同时上手,就可能打架:摆盘师刚把盘子摆正,质检员却说“这个角度不合格”,两人争执不下。ESLint 和 Prettier 也有这种冲突——Prettier 说“字符串要用单引号”,ESLint 却可能配置了“必须双引号”。怎么办?答案是明确分工、关闭冲突。

业界标准做法是引入 eslint-config-prettier,它像一份“和平协议”:把 ESLint 中与 Prettier 冲突的格式类规则统统关掉,让 ESLint 专心管代码质量,Prettier 专心管格式美观。另一方面,也有人用 eslint-plugin-prettier 把 Prettier 塞进 ESLint 当一条规则跑,相当于让质检员兼职摆盘——不推荐,但存在。理想的流水线是先让摆盘师 Prettier 格式化,再让质检员 ESLint 查质量:

在项目里,我们通常把两个检查串成一条 npm 脚本命令,比如 npm run lint 里先写 prettier --write . 再写 eslint .。这样不管是本地开发还是 CI 服务器,执行的永远是同一条“后厨流水线”。质检员和摆盘师各就各位,效率反而最高。

Quality(s)=Lint(Format(s))=PASS∨FAIL\text{Quality}(s) = \text{Lint}(\text{Format}(s)) = \text{PASS} \lor \text{FAIL}
集成方案的灵魂:先格式化、后检查,用 eslint-config-prettier 关掉冲突规则,让工具各司其职。
  1. Format(先摆盘)先用 Prettier 把代码风格统一,等价于把盘子摆正再送检。
    Format(s)\text{Format}(s)
  2. Lint(再质检)对格式化后的代码运行 ESLint,检查逻辑和潜在问题,避免格式干扰判断。
    Lint(Format(s))\text{Lint}(\text{Format}(s))
  3. PASS / FAIL(通过或拦截)Pipeline 最终只输出两个结果,干净代码放行,问题代码打回。
    PASS∨FAIL\text{PASS} \lor \text{FAIL}

TypeScript配合

如果你是一位质检员,突然被派去检查海鲜档口——海胆新不新鲜、河豚处理得对不对,这需要专门的资格证书。TypeScript 对 ESLint 来说就是“海鲜档口”:它有自己的类型、接口、泛型语法,普通解析器根本读不懂。这时候需要专用解析器登场。

@typescript-eslint/parser 是 TS 世界的“海鲜明档解析器”,它先把 TS 语法翻译成 ESLint 能理解的结构;@typescript-eslint/eslint-plugin 则提供了一批专属规则,比如“不允许使用 any 类型”“不允许未使用的变量”。更进一步,如果开启 parserOptions.project 指向 tsconfig.json,ESLint 还能获得类型信息,做“类型感知”的深度检查——相当于质检员能看懂食材的检测报告,而不仅是看外观。这套逻辑可以写成:

有了这套配合,团队写 TypeScript 时就能提前拦住“滥用 any”“类型断言满天飞”这类问题。质检员考到了海鲜执照,后厨的“高级菜品”才能放心上桌。

LintTS(s)=Lint(ParserTS(s), rulesTS)\text{Lint}_{\text{TS}}(s) = \text{Lint}\big(\text{Parser}_{\text{TS}}(s),\ \text{rules}_{\text{TS}}\big)
TypeScript 配合的核心:用 @typescript-eslint/parser 理解 TS 语法,再用插件规则做类型感知检查。
  1. ParserTS(TS 解析器)把 TypeScript 代码解析成 ESLint 能分析的语法树,是“看懂海鲜”的前提。
    ParserTS(s)\text{Parser}_{\text{TS}}(s)
  2. rulesTS(TS 专属规则集)来自 @typescript-eslint 插件,包含类型相关的检查规则。
    rulesTS\text{rules}_{\text{TS}}
  3. Lint(执行检查)解析器 + 规则集同时工作,产出审计结果。
    Lint(ParserTS(s), rulesTS)\text{Lint}(\text{Parser}_{\text{TS}}(s),\ \text{rules}_{\text{TS}})

Git Hooks集成

质检和摆盘都到位了,但还有一个漏洞:如果厨师做完菜不经过检查台就直接端出去呢?后厨的规矩是——所有菜必须经过传菜口的闸门。对应到代码世界,这个闸门就是 Git Hooks:在 git commit 提交代码之前,强制先跑一遍检查,不合格就拦下。

搭建这道闸门常用两个工具:husky 用来“挂钩子”,它能在 .husky 目录下注册 pre-commit 钩子;lint-staged 让检查只针对暂存区里“即将出锅的菜”,而不是把整座后厨翻个底朝天——这样速度快得多。典型配置是在 package.json 里写 "lint-staged": { "*.{js,ts}": ["eslint --fix", "prettier --write"] }。整个流程可以表示为:

这道闸门最大的价值是“把问题挡在提交之前”。再也不用在 Code Review 里争论“这里该不该加分号”——闸门已经替你处理好了,评审专家只需关注真正的业务逻辑。

Commit→huskylint-staged→lint∧formatCommitOK\text{Commit} \xrightarrow{\text{husky}} \text{lint-staged} \xrightarrow{\text{lint} \wedge \text{format}} \text{Commit}_{\text{OK}}
Git Hooks 集成 = husky 挂钩子 + lint-staged 只查暂存文件,让检查成为提交的强制闸门。
  1. husky(挂钩工具)在 Git 事件(如 pre-commit)上挂载自定义脚本,相当于安装“传菜口感应器”。
    Commit→huskyHook\text{Commit} \xrightarrow{\text{husky}} \text{Hook}
  2. lint-staged(暂存区检查)只对 git 暂存区中的文件运行 lint 和 format,速度快、不打搅存量代码。
    lint-staged→{lint, format}\text{lint-staged} \to \{\text{lint},\ \text{format}\}
  3. CommitOK(提交成功)只有检查和格式化都通过,提交才被放行,否则 Git 直接拒绝。
    lint∧format⇒CommitOK\text{lint} \wedge \text{format} \Rightarrow \text{Commit}_{\text{OK}}

团队规范落地

一个人店的规矩好定,一百家分店要执行同一套标准就难了。团队推行代码规范,最大的敌人不是工具,而是“大家不照着做”。所以落地要讲策略:共享配置、渐进推行、文化养成三管齐下。

首先,把 .eslintrc 和 .prettierrc 抽成独立的 npm 包(比如 @company/eslint-config),发布到私有仓库,所有项目安装即用——这就是“总店统一印刷的标准菜谱”。其次,别想着一夜之间重写全部老代码:新代码用 Git Hooks 严格把关,老代码排期分批整改,避免一次大改动引发海量冲突。最后,把规范的目的、常用规则的取舍写进文档,让团队成员理解“为什么这么定”,而不是被迫服从。规范达成可以总结为:

想想连锁餐厅:统一菜谱让厨师有据可依,试点门店积累经验再推广,最终每位厨师都形成肌肉记忆。代码规范也是如此,工具只是“他律”的起点,团队的“自律”才是终点。

规范达成=共享配置×渐进推行×文化沉淀\text{规范达成} = \text{共享配置} \times \text{渐进推行} \times \text{文化沉淀}
团队规范落地 = 共享配置包 + 渐进式推行 + 文档与文化沉淀,三者相乘缺一不可。
  1. 共享配置把 ESLint/Prettier 配置抽成公司级 npm 包,各项目统一引用。
    共享配置=npm 包+统一版本\text{共享配置} = \text{npm 包} + \text{统一版本}
  2. 渐进推行新代码严格把关,存量代码分批整改,避免一次性大爆炸式重构。
    渐进推行:先试点→再铺开\text{渐进推行}: \text{先试点} \to \text{再铺开}
  3. 文化沉淀通过文档和 Code Review 约定,让规范内化为团队的默认习惯。
    文化沉淀:文档+习惯→自驱\text{文化沉淀}: \text{文档} + \text{习惯} \to \text{自驱}

工程化实战

最后,我们把整套流程放进真实的工程流水线里:本地开发、提交代码、CI 检查、合并上线,每个环节都有质检员和摆盘师的身影。所谓“工程化”,就是把这些检查动作自动化、脚本化、无法跳过。

本地开发时,VS Code 插件在保存瞬间自动跑 Prettier;提交代码时,husky + lint-staged 在 pre-commit 里跑 eslint --fix 和 prettier --write;推送分支后,CI(如 GitHub Actions)再跑一次完整检查:eslint .、prettier --check .、以及 TypeScript 的 tsc --noEmit。只有全部通过,代码才有资格合并到主分支。整个门禁可以抽象成:

到了这一步,你的“标准化后厨”就真正建成了:质检员、摆盘师、传菜口闸门、统一菜谱全部就位。无论团队扩张到多少人,代码质量和风格都稳如泰山——这就是工程化的力量。

CI: lint∧format_check∧typecheck⇒merge\text{CI}:\ \text{lint} \wedge \text{format\_check} \wedge \text{typecheck} \Rightarrow \text{merge}
工程化实战 = CLI 命令 + npm scripts + CI 门禁,让规范贯穿本地到上线的每个环节。
  1. lint(代码检查)在 CI 中对全量代码运行 ESLint,确保没有 error 级问题。
    lint:eslint .\text{lint}: \text{eslint .}
  2. format_check(格式校验)用 prettier --check 验证代码是否已被格式化,只报错不修改。
    format_check:prettier –check .\text{format\_check}: \text{prettier --check .}
  3. typecheck(类型检查)TypeScript 项目额外运行 tsc --noEmit,把类型错误挡在合并前。
    typecheck:tsc –noEmit\text{typecheck}: \text{tsc --noEmit}
  4. merge(合并放行)三项全绿才允许合并,否则 PR 打回重做。
    lint∧format∧type⇒merge\text{lint} \wedge \text{format} \wedge \text{type} \Rightarrow \text{merge}

AI 应用场景

AI 辅助编程的自动把关

阶段:代码生成与质量保障

解决的问题:如今前端工程师大量使用 Copilot、ChatGPT 生成代码,AI 产出的代码风格不可控,可能引入未声明变量、错误缩进、混合引号等问题。若人工逐行核对,效率极低。

具体案例:某 AI 产品团队 40% 的代码由 AI 生成。他们在 VS Code 中开启“保存时自动格式化”,并配置 husky + lint-staged,AI 生成的代码一旦提交就自动走 eslint --fix 与 prettier --write,问题代码被当场拦截。工程师从“帮 AI 改代码”变成“验收 AI 代码”,效率提升明显。

大模型产品团队规范统一

阶段:前端工程化与协作

解决的问题:大模型应用(如 LLM Chat、Agent 工作台)前端团队常在多地协作,若没有统一规范,代码风格会迅速熵增,Code Review 里充满格式争论。

具体案例:某公司搭建 LLM 产品的前端团队 12 人,发布公司级 @company/eslint-config 和 .prettierrc 共享配置,所有子项目通过一条命令接入。新项目初始化即带规范,老项目按月分批整改,三个月后仓库内格式冲突归零。

AI 代码审查机器人的 Lint 管道

阶段:CI/CD 质量门禁

解决的问题:AI 代码审查机器人(如 CodeRabbit、PR-Agent)虽能发现逻辑问题,但格式类问题仍需第一道关卡快速拦截,避免浪费 AI 审查算力。

具体案例:团队在 GitHub Actions 中配置 job:PR 触发后先跑 eslint . 与 prettier --check .,失败则自动在 PR 上标注 ❌ 并阻止合并,通过后才调用 AI 审查 API 做语义级 Review。AI 的资源被用在“真正需要判断力”的地方。

Python 演示

python68 行
"""迷你版 ESLint + Prettier: 代码质量检查与格式化流水线"""  class CodeInspector:    """质检员类: 模拟 ESLint 规则检查与 Prettier 格式化"""     def __init__(self, max_line_len=80):        self.max_line_len = max_line_len        self.error_count = 0     def lint(self, code_lines):        """逐行检查风格问题, 返回 (行号, 规则名, 等级) 列表"""        problems = []        for i, line in enumerate(code_lines, 1):            line = line.rstrip("\n")            if len(line) > self.max_line_len:                problems.append((i, "line-too-long", "error"))            if line.rstrip() != line:                problems.append((i, "trailing-space", "warn"))            if line.startswith("\t"):                problems.append((i, "tab-as-indent", "error"))        self.error_count = len(problems)        return problems     def format(self, code_lines):        """统一风格: 去行尾空白, Tab 转 4 空格"""        result = []        for line in code_lines:            line = line.rstrip()            line = line.expandtabs(4)            result.append(line)        return result     def run_gate(self, code_lines):        """总检闸门: 先格式化再检查, error 级问题直接拦截"""        clean = self.format(code_lines)        problems = self.lint(clean)        has_error = any(level == "error" for _, _, level in problems)        return clean, problems, not has_error  def main():    messy_code = [        "def greet(name):      \n",        "\tprint('Hello, ' + name)\n",        "    if name == 'AI':\n",        "        print('Welcome AI dev with a very very long message over limit!')\n",    ]    inspector = CodeInspector(max_line_len=60)     print("=== Step 1: ESLint 质检 ===")    for lineno, rule, level in inspector.lint(messy_code):        print(f"  line {lineno} violates {rule}, level={level}")    print(f"found {inspector.error_count} problems\n")     print("=== Step 2: Prettier 格式化 ===")    clean = inspector.format(messy_code)    for line in clean:        print(repr(line))    print()     print("=== Step 3: 总检闸门 ===")    _, problems, ok = inspector.run_gate(messy_code)    print("PASS, ship it!" if ok else "BLOCKED, fix error-level issues first!")  if __name__ == "__main__":    main()
目的:用纯 Python 实现一个微型"ESLint + Prettier"流水线,演示 lint 检查、prettier 格式化与提交闸门拦截的完整流程。
  1. def lint(self, code_lines)质检员方法:逐行检查三种违规(超长、行尾空格、Tab 缩进),并返回带等级的检查报告。
  2. problems.append((i, "line-too-long", "error"))超长行记为 error 级,相当于 ESLint 的 max-len 规则设为 "error"。
  3. if line.startswith("\t")检测 Tab 缩进并记为 error,模拟 ESLint 的 no-tabs 规则,TS 项目里尤其常见。
  4. self.error_count = len(problems)统计问题总数,对应 ESLint 控制台输出的"problems"汇总。
  5. def format(self, code_lines)摆盘师方法:去掉行尾空白并把 Tab 转成 4 空格,模拟 Prettier 的 tabWidth: 4。
  6. line.expandtabs(4)把 Tab 字符展开为 4 个空格,是格式统一的核心操作。
  7. def run_gate(self, code_lines)组合流水线:先 format 再 lint,返回最终是否放行,对应 Git Hooks 的 pre-commit 拦截。
  8. any(level == "error" for _, _, level in problems)存在任一条 error 级问题即拦截,模拟 ESLint 非零退出码导致提交失败。

常见误区

误区“我见过 eslint 加 --fix 也能自动修格式,跟 Prettier 差不多,装一个不就行了?省得配两套东西,多麻烦。”

正解两者职责完全不同。ESLint 是质检员,核心价值是找出“代码对不对”——未使用变量、危险写法、潜在 Bug;Prettier 是摆盘师,只处理“代码好不好看”——缩进、引号、换行。ESLint 的 --fix 只修复少量安全的格式项,它的格式能力远不如 Prettier 全面;反之 Prettier 不会帮你查 Bug。就像你不能让质检员顺带摆盘,也不能让摆盘师鉴定食品安全。

为何常见:因为两者确实有部分功能重叠(都能改缩进、引号),初学者看到表面相似就误以为可以互相替代,深入使用后才会感受到“查质量”与“修颜值”的鸿沟。

误区“自动改代码太危险了,万一把我的逻辑改坏了怎么办?我从来不敢用 --fix,都是手动改。”

正解ESLint 对自动修复非常保守,只有被标记为 fixable 的规则才会被 --fix 处理,而这些修复都不会改变代码语义——比如补空格、统一引号、加行尾分号。像 no-unused-vars(删除未使用变量)这类可能改变行为的规则,ESLint 默认不做自动修复,只提示你手动处理。它就像质检员只帮你把盘子摆正,绝不会替你重炒一盘菜。

为何常见:很多人有过“自动工具改坏代码”的阴影(比如某些一键重构工具),于是把这种恐惧投射到所有自动修复上,却忽略了 ESLint 设计上对语义安全性的严格保障。

误区“我把 semi 设为 false 后,代码里应该没有任何分号了,结果发现有些行还是有分号,Prettier 是不是有 bug?”

正解这不是 bug,而是 Prettier 的“安全优先”设计。在 JavaScript 中,某些语句以 (、[、` `` 开头时,前一行的结尾如果省略分号,可能被解释成函数调用或数组索引,从而改变语义。Prettier 会在这些“必要场景”强制保留分号,防止引入难以排查的运行时错误。摆盘师再追求美观,也不会为了好看把盘子叠到会碎的程度。

为何常见:初学者把 semi 选项理解为“一刀切地删除所有分号”,忽略了 JS 语法本身的歧义性,遇到 Prettier“聪明地保留”时便误以为是工具故障。

误区“我把 eslint-plugin-prettier 装上了,Prettier 就变成 ESLint 的一条规则,以后只要跑 eslint 就行,何必再单独格式化?”

正解eslint-plugin-prettier 是把 Prettier 作为规则塞进 ESLint 运行,这会让 ESLint 变慢,且报错信息变成“格式问题”而不够直观。社区更推荐的做法是:用 eslint-config-prettier 关掉 ESLint 与 Prettier 冲突的规则,然后并行地使用 prettier --write 做格式化、eslint . 做质量检查。分工清晰、各跑各的,速度和体验都更好。让质检员别碰摆盘,让摆盘师别碰质检。

为何常见:很多人被插件的名字误导,以为“既然能合体就一定要合体”,却没意识到“集成”的正确姿势恰恰是解耦——各司其职才是最优解。

误区“本地每次 commit 都要跑检查,太慢了,我直接推送,等 CI 报错再修不也一样吗?”

正解CI 发现问题时,代码已经进入远端仓库,修复需要“提交流程 + 重新推送 + CI 重跑”一整轮,反馈周期从几秒恶化到几分钟甚至几十分钟;而且会把坏代码暴露给所有协作同事。lint-staged 的设计恰恰解决了性能问题——它只检查暂存区里要提交的那几个文件,通常在几百毫秒内完成。让质检闸门摆在“传菜口”而不是“顾客投诉台”,成本低得多。

为何常见:人们容易高估 CI 的“兜底能力”,低估远端失败后的沟通与返工成本;同时不了解 lint-staged 的增量检查机制,被“全量检查很慢”的旧经验误导。

面试题

Q1. ESLint 规则中"error"等级对应的数字是什么?

单选题 · easy

  • A.数字 0,表示完全关闭该规则
  • B.数字 1,表示发现问题仅给警告
  • C.数字 2,表示发现问题直接报错← 正确答案
  • D.数字 3,表示必须重写整个文件

答案:C。ESLint 的三级错误等级对应 0/1/2:0 关闭、1 警告、2 报错。就像质检手册里“不做要求/口头提醒/打回重做”三档,不存在等级 3。B 描述的是 warn(1),A 是 off(0),D 是凭空捏造。

Q2. Prettier 与 ESLint 在规则上发生冲突时,推荐的解决方式是?

单选题 · mid

  • A.卸载 Prettier 只保留 ESLint 检查
  • B.用 eslint-config-prettier 关闭冲突规则← 正确答案
  • C.让 ESLint 修改自己的规则去兼容
  • D.把两者冲突规则都设置为完全关闭

答案:B。eslint-config-prettier 是社区标准答案,它关闭 ESLint 中与 Prettier 冲突的格式类规则,让工程师分别管理“质量”和“风格”。A 是逃避问题,C 不可行(ESLint 不会自动改自己),D 把所有冲突规则全关掉等于放弃了检查能力。

Q3. 下列哪些任务属于 Prettier 的专职职责?

多选题 · mid

  • A.检查未使用变量并给出警告
  • B.统一代码缩进和行尾分号← 正确答案
  • C.自动修复行宽超过限制的语句← 正确答案
  • D.检测函数是否存在逻辑死循环

答案:BC。Prettier 是“摆盘师”,只管缩进、分号、行宽、引号等外观统一,对应 B 和 C。A 是 ESLint 的 no-unused-vars 规则职责,D 属于静态分析或人工审查范畴,两者都不在 Prettier 的能力范围内。

Q4. lint-staged 在 Git 提交流程中最核心的作用是什么?

单选题 · mid

  • A.只对暂存区的文件运行检查和格式化← 正确答案
  • B.把全仓库代码重新格式化一遍再提交
  • C.在提交后自动回滚出问题的代码
  • D.直接修改远端仓库的代码并推送

答案:A。lint-staged 的“staged“指 Git 暂存区,它只处理即将提交的增量文件,几秒内完成检查。B 是它极力避免的”全量扫描“;C 和 D 与代码检查毫无关系。它是传菜口只检查”这一批菜”的精准闸门。

Q5. 关于 eslint-config-prettier 与 eslint-plugin-prettier,下列说法正确的有?

多选题 · hard

  • A.前者关闭与 Prettier 冲突的规则← 正确答案
  • B.后者把 Prettier 作为 ESLint 规则运行← 正确答案
  • C.两者都是官方强制要求安装的插件
  • D.两者功能完全相同可以直接互换

答案:AB。eslint-config-prettier 是“和平协议”,关掉冲突规则;eslint-plugin-prettier 是把 Prettier 嵌进 ESLint 当规则跑。两者思路相反,C 说“强制安装”是误解,D 说“完全相同”是错的——一个用于解耦,一个用于合体。

Q6. 使用 ESLint 检查 src 目录下所有 JS 文件的正确命令是?

单选题 · easy

  • A.npx eslint src --ext .js← 正确答案
  • B.npm run eslint src/js
  • C.node eslint src --ext .js
  • D.yarn eslint src -ignore .js

答案:A。npx eslint <目录> --ext .js 是标准用法,npx 直接调用本地安装的 eslint。B 中 npm run 后面应该是 npm scripts 里定义的名字,不能直接跟路径;C 少了 npx 包装;D 的 -ignore 参数不存在。

Q7. 下列哪些工具常用于搭建 Git 提交前代码检查的 Hooks?

多选题 · easy

  • A.husky← 正确答案
  • B.lint-staged← 正确答案
  • C.webpack
  • D.nodemon

答案:AB。husky 负责在 Git 事件上挂载钩子,lint-staged 负责对暂存文件做增量检查,两者是 pre-commit 检查的黄金搭档。webpack 是打包工具,nodemon 是文件监听重启工具,它们都不属于 Git Hooks 领域。

Q8. 关于 eslint --fix 的自动修复能力,正确的说法是?

单选题 · hard

  • A.会将代码中所有潜在 Bug 一次性修复
  • B.只修复不会改变语义的格式化类问题← 正确答案
  • C.能自动补全 TypeScript 缺失的类型标注
  • D.修复前必须手动备份整个项目代码

答案:B。ESLint 只对标记为 fixable 的规则执行安全修复(缩进、引号、分号等),绝不改变代码语义。A 夸大了能力,Bug 修复需要人脑;C 是 TypeScript 语言服务的职责;D 没有必要,--fix 的修复本身就是保守安全的。

Q9. TypeScript 项目中让 ESLint 理解 TS 语法,需要配置什么?

单选题 · mid

  • A.配置 @typescript-eslint/parser 作为解析器← 正确答案
  • B.把 prettier 的 semi 选项设为 false
  • C.在 tsconfig.json 里开启 noImplicitAny
  • D.将 eslint 的 env 选项设置为 node

答案:A。@typescript-eslint/parser 是 TS 语法的专用解析器,能让 ESLint 读懂 interface、泛型等语法。B 是 Prettier 风格选项,与语法理解无关;C 是 TS 编译器选项;D 是运行时环境声明,都不解决“解析 TS 语法”的问题。

Q10. 团队推行代码规范时,下列哪些做法更符合渐进式落地原则?

多选题 · hard

  • A.一键安装全套规则并对存量代码强制修复
  • B.先在线下子项目试点再逐步推广到全体← 正确答案
  • C.用 git hooks 对新代码把关,存量分批整改← 正确答案
  • D.要求团队记住所有规则并逐一手动书写

答案:BC。渐进式落地的关键是“小步快跑”:先试点积累经验(B),新代码用闸门把关、老代码分批整改(C)。A 的“强制一次性修复”会造成巨大 diff 和回归风险,D 违背了工具自动化的初衷。规范落地靠的是机制而非记忆。