前言
代码不仅仅是给机器看的,也是给人看的
在真实的工程项目中,尤其是多人协作的场景下,代码规范就变得非常重要了,它可以用来统一团队代码风格,避免不同风格的代码混杂到一起难以阅读,有效提高代码质量,甚至可以将一些语法错误在开发阶段提前规避掉。但仅有规范本身不够,我们需要自动化的工具(即Lint 工具)来保证规范的落地,把代码规范检查(包括自动修复)这件事情交给机器完成,开发者只需要专注应用逻辑本身。
本节,我们将一起来完成 Lint 工具链在项目中的落地,实现自动化代码规范检查及修复的能力。学完本节内容后,你不仅能熟悉诸如ESLint、Prettier、Stylelint和Commitlint 等诸多主流 Lint 工具的概念和使用,还能配合husky、lint-staged、VSCode 插件和Vite 生态在项目中集成完整的 Lint 工具链,搭建起完整的前端开发和代码提交工作流,这部分内容虽然和 Vite 没有直接的联系,但也是 Vite 项目搭建中非常重要的一环,是前端工程化的必备知识。
JS/TS规范工具:ESLint
简介
ESLint 是在 ECMAScript/JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。
Eslint 是国外的前端大牛Nicholas C. Zakas在 2013 年发起的一个开源项目,有一本书被誉为前端界的"圣经",叫《JavaScript 高级程序设计》(即红宝书),他正是这本书的作者。
Nicholas 当初做这个开源项目,就是为了打造一款插件化的 JavaScript 代码静态检查工具,通过解析代码的 AST 来分析代码格式,检查代码的风格和质量问题。现在,Eslint 已经成为一个非常成功的开源项目了,基本上属于前端项目中 Lint 工具的标配。
ESLint 的使用并不复杂,主要通过配置文件对各种代码格式的规则(rules)进行配置,以指定具体的代码规范。目前开源社区也有一些成熟的规范集可供使用,著名的包括Airbnb JavaScript 代码规范、Standard JavaScript 规范、Google JavaScript 规范等等,你可以在项目中直接使用这些成熟的规范,也可以自己定制一套团队独有的代码规范,这在一些大型团队当中还是很常见的。
初始化
安装eslint
pnpm i eslint -D
初始化eslint配置
npx eslint --init
接着eslint就会帮我们自动生成.eslintrc.js配置文件,需要注意的是。上述初始化过程中我们并没有使用npm安装依赖。需要手动进行安装:
现在我们项目中的eslint就配置好了,并且给我们生成了一份eslintrc.cjs的文件。根据我上面配置好了之后,他里面的内容是这样的:
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended"
],
"overrides": [
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint"
],
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"double"
],
"semi": [
"error",
"always"
]
}
};
核心配置解读
大家初次接触配置文件可能会有点不太理解,接下来我来为你介绍一下几个核心的配置项,你可以对照目前生成的.eslintrc.js一起学习。
1. parser - 解析器
ESLint 底层默认使用 Espree来进行 AST 解析,这个解析器目前已经基于 Acron 来实现,虽然说 Acron 目前能够解析绝大多数的 ECMAScript 规范的语法,但还是不支持 TypeScript ,因此需要引入其他的解析器完成 TS 的解析。
社区提供了@typescript-eslint/parser这个解决方案,专门为了 TypeScript 的解析而诞生,将 TS 代码转换为 Espree 能够识别的格式(即 Estree 格式),然后在 Eslint 下通过Espree进行格式检查, 以此兼容了 TypeScript 语法。
2. parserOptions - 解析器选项
这个配置可以对上述的解析器进行能力定制,默认情况下 ESLint 支持 ES5 语法,你可以配置这个选项,具体内容如下:
- ecmaVersion: 这个配置和
Acron的 ecmaVersion 是兼容的,可以配置ES + 数字(如 ES6)或者ES + 年份(如 ES2015),也可以直接配置为latest,启用最新的 ES 语法。 - sourceType: 默认为
script,如果使用 ES Module 则应设置为module - ecmaFeatures: 为一个对象,表示想使用的额外语言特性,如开启
jsx。
3. rules - 具体代码规则
rules 配置即代表在 ESLint 中手动调整哪些代码规则,比如禁止在 if 语句中使用赋值语句这条规则可以像如下的方式配置:
// .eslintrc.js
module.exports = {
// 其它配置省略
rules: {
// key 为规则名,value 配置内容
"no-cond-assign": ["error", "always"]
}
}
在 rules 对象中,key 一般为规则名,value 为具体的配置内容,在上述的例子中我们设置为一个数组,数组第一项为规则的 ID,第二项为规则的配置。
这里重点说一说规则的 ID,它的语法对所有规则都适用,你可以设置以下的值:
off或0: 表示关闭规则。warn或1: 表示开启规则,不过违背规则后只抛出 warning,而不会导致程序退出。error或2: 表示开启规则,不过违背规则后抛出 error,程序会退出。
具体的规则配置可能会不一样,有的是一个字符串,有的可以配置一个对象,你可以参考 ESLint 官方文档。
当然,你也能直接将 rules 对象的 value 配置成 ID,如: "no-cond-assign": "error"。
4. plugins
上面提到过 ESLint 的 parser 基于Acorn实现,不能直接解析 TypeScript,需要我们指定 parser 选项为@typescript-eslint/parser才能兼容 TS 的解析。同理,ESLint 本身也没有内置 TypeScript 的代码规则,这个时候 ESLint 的插件系统就派上用场了。我们需要通过添加 ESLint 插件来增加一些特定的规则,比如添加@typescript-eslint/eslint-plugin 来拓展一些关于 TS 代码的规则,如下代码所示:
// .eslintrc.js
module.exports = {
// 添加 TS 规则,可省略`eslint-plugin`
plugins: ['@typescript-eslint']
}
值得注意的是,添加插件后只是拓展了 ESLint 本身的规则集,但 ESLint 默认并没有开启这些规则的校验!如果要开启或者调整这些规则,你需要在 rules 中进行配置,如:
// .eslintrc.js
module.exports = {
// 开启一些 TS 规则
rules: {
'@typescript-eslint/ban-ts-comment': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
}
}
5. extends - 继承配置
extends 相当于继承另外一份 ESLint 配置,可以配置为一个字符串,也可以配置成一个字符串数组。主要分如下 3 种情况:
- 从 ESLint 本身继承;
- 从类似
eslint-config-xxx的 npm 包继承; - 从 ESLint 插件继承。
// .eslintrc.js
module.exports = {
"extends": [
// 第1种情况
"eslint:recommended",
// 第2种情况,一般配置的时候可以省略 `eslint-config`
"standard"
// 第3种情况,可以省略包名中的 `eslint-plugin`
// 格式一般为: `plugin:${pluginName}/${configName}`
"plugin:react/recommended"
"plugin:@typescript-eslint/recommended",
]
}
有了 extends 的配置,对于之前所说的 ESLint 插件中的繁多配置,我们就不需要手动一一开启了,通过 extends 字段即可自动开启插件中的推荐规则:
extends: ["plugin:@typescript-eslint/recommended"]
6. env 和 globals
这两个配置分别表示运行环境和全局变量,在指定的运行环境中会预设一些全局变量,比如:
// .eslint.js
module.export = {
"env": {
"browser": "true",
"node": "true"
}
}
指定上述的 env 配置后便会启用浏览器和 Node.js 环境,这两个环境中的一些全局变量(如 window、global 等)会同时启用。
有些全局变量是业务代码引入的第三方库所声明,这里就需要在globals配置中声明全局变量了。每个全局变量的配置值有 3 种情况:
"writable"或者true,表示变量可重写;"readonly"或者false,表示变量不可重写;"off",表示禁用该全局变量。
那jquery举例,我们可以在配置文件中声明如下:
// .eslintrc.js
module.exports = {
"globals": {
// 不可重写
"$": false,
"jQuery": false
}
}
相信有了上述核心配置部分的讲解,你再回头看看初始化生成的 ESLint 配置文件,你也能很好地理解各个配置项的含义了。
VSCODE设置文件保存时自动更正代码
这样就可以将vscode配置成当用户保存文件的时候自动帮你矫正代码格式了
Vite中接入ESlint
除了安装编辑器插件,我们也可以通过 Vite 插件的方式在开发阶段进行 ESLint 扫描,以命令行的方式展示出代码中的规范问题,并能够直接定位到原文件。
首先我们安装 Vite 中的 ESLint 插件:
pnpm i vite-plugin-eslint -D
然后在 vite.config.ts 中接入:
// vite.config.ts
import viteEslint from 'vite-plugin-eslint';
// 具体配置
{
plugins: [
// 省略其它插件
viteEslint(),
]
}
现在你可以试着重新启动项目, ESLint 的错误已经能够及时显示到命令行窗口中了。
由于这个插件采用另一个进程来运行 ESLint 的扫描工作,因此不会影响 Vite 项目的启动速度,这个大家不用担心。
样式规范工具:Stylelint
Stylelint,一个强大的现代化样式 Lint 工具,用来帮助你避免语法错误和统一代码风格。
Stylelint 主要专注于样式代码的规范检查,内置了 170 多个 CSS 书写规则,支持 CSS 预处理器(如 Sass、Less),提供插件化机制以供开发者扩展规则,已经被 Google、Github 等大型团队投入使用。与 ESLint 类似,在规范检查方面,Stylelint 已经做的足够专业,而在代码格式化方面,我们仍然需要结合 Prettier 一起来使用。
首先让我们来安装 Stylelint 以及相应的工具套件:
pnpm i stylelint stylelint-prettier stylelint-config-prettier stylelint-config-recess-order stylelint-config-standard stylelint-config-standard-scss -D
然后,我们在 Stylelint 的配置文件.stylelintrc.js中一一使用这些工具套件:
// .stylelintrc.js
module.exports = {
// 注册 stylelint 的 prettier 插件
plugins: ['stylelint-prettier'],
// 继承一系列规则集合
extends: [
// standard 规则集合
'stylelint-config-standard',
// standard 规则集合的 scss 版本
'stylelint-config-standard-scss',
// 样式属性顺序规则
'stylelint-config-recess-order',
// 接入 Prettier 规则
'stylelint-config-prettier',
'stylelint-prettier/recommended'
],
// 配置 rules
rules: {
// 开启 Prettier 自动格式化功能
'prettier/prettier': true
}
};
可以发现 Stylelint 的配置文件和 ESLint 还是非常相似的,常用的plugins、extends和rules属性在 ESLint 同样存在,并且与 ESLint 中这三个属性的功能也基本相同。不过需要强调的是在 Stylelint 中 rules 的配置会和 ESLint 有些区别,对于每个具体的 rule 会有三种配置方式:
null,表示关闭规则。- 一个简单值(如 true,字符串,根据不同规则有所不同),表示开启规则,但并不做过多的定制。
- 一个数组,包含两个元素,即
[简单值,自定义配置],第一个元素通常为一个简单值,第二个元素用来进行更精细化的规则配置。
接下来我们将 Stylelint 集成到项目中,回到 package.json 中,增加如下的 scripts 配置:
{
"scripts": {
// 整合 lint 命令
"lint": "npm run lint:script && npm run lint:style",
// stylelint 命令
"lint:style": "stylelint --fix "src/**/*.{css,scss}""
}
}
执行pnpm run lint:style即可完成样式代码的规范检查和自动格式化。当然,你也可以在 VSCode 中安装Stylelint插件,这样能够在开发阶段即时感知到代码格式问题,提前进行修复。
当然,我们也可以直接在 Vite 中集成 Stylelint。社区中提供了 Stylelint 的 Vite 插件,实现在项目开发阶段提前暴露出样式代码的规范问题。我们来安装一下这个插件:
pnpm i @amatlash/vite-plugin-stylelint -D
import viteStylelint from '@amatlash/vite-plugin-stylelint';
// 具体配置
{
plugins: [
// 省略其它插件
viteStylelint({
// 对某些文件排除检查
exclude: /windicss|node_modules/
}),
]
}
这样 vite就能够帮助我们在启动的时候配置自动样式检查了。