ESLint 到底在帮我们守住什么?从规则配置到工程实践
前面的课我们一直在写代码------前端组件、后端接口、全栈框架。代码能跑就行了吗?
这节课换一个角度:不写新功能,而是给代码立规矩。
工具就一个:
ESLint。它干的事一句话能说清------强制团队写出一致风格的代码,严格检查代码,找出潜在的 bug。
一、ESLint 是什么:代码工程质量的底线
先看关于 eslint 的定位:
eslint 是代码工程质量的重要保证,强制团队写出一致风格的代码,可以严格检查代码,找出潜在的 bug
三个关键词:一致风格 、严格检查 、找潜在 bug。
"一致风格"不是审美问题。两个人写代码,一个用 var,一个用 let;一个两空格缩进,一个四空格缩进;一个加分号,一个不加分号------代码能跑,但合并的时候冲突多到爆炸,review 的时候光看风格就累死了。
eslint 添加一些约束规则
ESLint 的做法是:你把规则定好,它替你盯着。 违反规则的代码,要么报警告,要么直接报错不让提交。
二、安装与项目结构
从 package.json 看整个项目的依赖和脚本:
json
{
"name": "eslint-demo",
"version": "1.0.0",
"description": "eslint 是代码工程质量的重要保证,强制团队写出一致风格的代码,可以严格检查代码,找出潜在的 bug",
"main": "index.js",
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"devDependencies": {
"@eslint/js": "^10.0.1",
"eslint": "^10.8.1",
"globals": "^17.11.0",
"typescript-eslint": "^8.67.0"
}
}
几个要点:
eslint放在devDependencies------ 它是开发工具,不是运行时依赖,生产环境不需要。- 两个脚本 :
"lint": "eslint ."------ 检查当前目录下所有文件"lint:fix": "eslint . --fix"------ 检查并自动修复能修的(比如引号、分号、缩进)
- 四个 devDependencies ,每个都有用:
@eslint/js------ ESLint 官方推荐的 JS 规则集eslint------ ESLint 本体globals------ 预定义的全局变量环境typescript-eslint------ TypeScript 的 ESLint 解析器和规则
运行 npm run lint 就是 eslint .,检查所有文件。运行 npm run lint:fix 就是 eslint . --fix,能自动修的就帮你修了。
三、配置文件:flat config 长什么样
ESLint 9+ 用的是 flat config------配置文件叫 eslint.config.mjs,不再是老的 .eslintrc。我的配置:
javascript
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"], plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.node },
rules: {
// 2=error 表示必须遵守,也就是错误,1=warn 表示警告,0=off 表示关闭
"no-var": 2,// 不能用 var 声明变量
"no-console": 1,// 1,开发阶段允许使用,但是上线之后不用 不能用 console 打印
"quotes": ["error", "double"],// 双引号
"semi": ["error", "always"],// 语句末尾有分号
"indent": ["error", 2],// 缩进 2 个空格
}
},
tseslint.configs.recommended,
]);
逐块拆开看。
3.1 四个 import
javascript
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
@eslint/js:ESLint 官方的 JS 规则包,提供js/recommended推荐规则集。globals:预定义全局变量集合。比如globals.node包含require、module、process等 Node.js 环境的全局变量,globals.browser包含window、document等。没有它,ESLint 会对这些全局变量报 "no-undef"。typescript-eslint:让 ESLint 能理解 TypeScript 语法,同时提供 TS 专属规则。defineConfig:ESLint 提供的配置辅助函数,提供类型提示。
3.2 files:规则对哪些文件生效
javascript
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"]
匹配所有 .js、.mjs、.cjs、.ts、.mts、.cts 文件。** 是递归匹配,子目录里的也算。
3.3 extends:继承推荐规则
javascript
plugins: { js },
extends: ["js/recommended"],
plugins: { js } 注册插件,extends: ["js/recommended"] 继承官方推荐规则集。推荐规则集里已经包含了几十条最佳实践规则,比如禁止使用 eval、禁止重复声明等。不用一条条自己写。
3.4 languageOptions:全局环境
javascript
languageOptions: { globals: globals.node },
告诉 ESLint:这段代码跑在 Node.js 环境。process、require、__dirname 这些 Node 全局变量不会报 "no-undef"。如果代码跑在浏览器,换成 globals.browser。
3.5 rules:6 条自定义规则
这是配置的核心。先看规则严重级别的约定:
2=error 表示必须遵守,也就是错误,1=warn 表示警告,0=off 表示关闭
也可以写成字符串:"error"、"warn"、"off"。数字和字符串等价。
6 条规则逐条看:
| 规则 | 值 | 含义 |
|---|---|---|
no-var |
2(error) |
不能用 var 声明变量,必须用 let 或 const |
no-console |
1(warn) |
开发阶段允许使用,但上线之后不用 console 打印 |
quotes |
["error", "double"] |
必须用双引号 |
semi |
["error", "always"] |
语句末尾必须有分号 |
indent |
["error", 2] |
缩进 2 个空格 |
有几种写法值得注意:
"no-var": 2------ 直接一个数字,表示 error 级别。没有额外参数。"no-console": 1------ warn 级别。允许你写,但会提醒你:上线前记得删。"quotes": ["error", "double"]------ 数组形式。第一个是严重级别,第二个是参数值。这里要求双引号。"semi": ["error", "always"]------ 同样是数组。"always"表示总是要分号。"indent": ["error", 2]------ 缩进必须 2 个空格,不是 tab。
注意 "no-var": 2 和 "quotes": ["error", "double"] 是两种写法------数字和字符串 "error" 等价。正式项目里建议统一用字符串,可读性更好。
3.6 tseslint.configs.recommended
javascript
tseslint.configs.recommended,
这一行在 defineConfig 数组的第二个位置,和第一个对象是并列的。它给 TypeScript 文件额外加了一套推荐规则------类型检查、TS 语法相关的最佳实践。
这种"数组里放多个配置对象"的方式是 flat config 的核心特性:每个对象管自己的 files,互不干扰。
四、被检查的代码:6 行代码能踩几个坑
index.mjs 是被检查的目标文件:
javascript
let name = "lk_ai";
// let a = 1;
function hello() {
console.log("hello " + name);
}
hello();
拿我们的规则跑一遍,看看会怎样:
no-var✅ 没有var,用的是let,通过。no-console⚠️console.log("hello " + name)触发警告------开发可以用,但提醒你上线前处理掉。quotes✅ 双引号,通过。semi✅ 每行末尾都有分号,通过。indent✅ 函数体缩进 2 个空格,通过。
注释 // let a = 1; 被注释掉了,不检查。
这段代码基本守规矩。如果把 let name 改成 var name,no-var 规则会直接报 error。如果改成单引号 'lk_ai',quotes 规则也报 error。这就是 ESLint 替你盯着的效果。
五、lint 和 lint:fix:检查和自动修复
两个脚本的区别很重要:
text
npm run lint → eslint .
检查所有文件,列出所有 error 和 warn,不改动代码
npm run lint:fix → eslint . --fix
检查并自动修复能修的(引号、分号、缩进等),
修不了的(比如 no-var 需要你判断用 let 还是 const)仍然报出来
--fix 不是万能的。风格类的规则(引号、分号、缩进)能自动改;但逻辑类的规则(比如 no-var 要你决定用 let 还是 const,no-console 要你决定删还是保留)只能提醒,不敢自动改。
我现在怎么理解这节课
这节课之前,我对 ESLint 的印象就是"编辑器里飘红线的那个东西"。配置文件打开看不懂,全是规则名,也不知道每个数字什么意思。
拆开配置以后,ESLint 的逻辑其实很直白:
text
定规则 → 检查代码 → 违反就报 error 或 warn → 能自动修的用 --fix
其中最关键的是三条严重级别:2=error 必须遵守,1=warn 警告,0=off 关闭。记住这一条,配置文件就能读个大概了。
更大的认知转变是:ESLint 不只是"查风格"。extends: ["js/recommended"] 里包含了几十条最佳实践规则,能帮你找到潜在的 bug------比如未使用的变量、重复声明、不安全的比较。风格只是它的一部分能力,找 bug 才是它更值钱的那部分。
回到 Vibe Coding 时代,ESLint 变得更重要了。AI 写代码很快,但它不会管你的项目用双引号还是单引号、用 var 还是 let。把 ESLint 配好,AI 写出来的代码过一遍 lint,风格不一致的地方立刻暴露。--fix 能自动修掉一大半,省下来的时间去看真正的逻辑问题。
这节课教的不是某个 API,而是一种工程思维 :代码能跑只是及格线,团队一致、风格统一、潜在 bug 被提前拦住,才是工程质量的底线。
术语速查
- ESLint:JavaScript/TypeScript 代码检查工具,通过自定义规则检查代码风格和潜在问题。
- flat config :ESLint 9+ 的新配置格式,配置文件为
eslint.config.mjs,用数组组织多个配置对象,替代了旧的.eslintrc。 - 规则严重级别 :
2或"error"表示报错(必须遵守),1或"warn"表示警告,0或"off"表示关闭。数字和字符串等价。 - extends(继承) :继承一套预设规则集,不用逐条手写。比如
js/recommended是 ESLint 官方推荐的 JS 规则集。 - plugins(插件):注册一个规则包,注册后才能 extends 它的规则集。
- globals 包 :预定义各运行环境的全局变量集合。
globals.node包含 Node.js 全局变量(require、module、process),globals.browser包含浏览器全局变量(window、document)。 - typescript-eslint:让 ESLint 理解 TypeScript 语法的解析器 + 规则集,提供 TS 专属的类型检查规则。
--fix:ESLint 的自动修复参数,能自动修正风格类问题(引号、分号、缩进),但不能修逻辑类问题(如no-var需要人工判断用let还是const)。- devDependencies:开发依赖,只在开发阶段使用,生产环境不需要。ESLint 作为代码检查工具,放在 devDependencies。