前言
大家好!我是 嘟老板 。在前端开发中,ESLint
扮演着守护代码质量的关键角色。它通过一套严格的规则,确保代码的规范性和一致性。然而若负责多个项目,就会发现重复为每个项目配置 ESLint
是多么痛苦的事情。那有没有一种高效的方法,既能保证各项目的配置统一,又能减少重复劳动呢?今天我们就来聊聊如何封装 ESLint
预置函数,让你远离反复配置的烦恼,彻底解放你的双手。
阅读本文您将收获:
设计思路
预置函数基于
ESLint v9.x
,若版本在此之前,请查看迁移指南
设计比较简单,ESLint
配置文件 eslint.config.js
中,直接调用预置函数 preset
并导出其返回结果。
preset
函数允许针对特定项目场景,传入自定义的配置规则,覆盖预置规则。
preset
函数中预置了一系列 ESLint
规则配置,主要分为两部分 - 默认启用配置 和 按需启用配置。
默认启用配置 包括大多数项目都需要的基础配置,诸如 javascript
、Typescript
、ignores
等相关配置。
按需启用配置 依赖项目技术栈,将决定权交于用户,可通过设置对应的启用选项参数,按需启用,如 Vue
、JSON
、Markdown
、Prettier
等相关配置。
preset
函数内部将 自定义规则 和 预置规则 进行整合,输出最终配置。
封装过程
为达到 一次封装,到处可用 的目的,我们将预置函数封装成库。
工程初始化
以下涉及的执行语句,均在终端命令行输入,回车执行
- 新建项目目录
bash
mkdir eslint-config
cd eslint-config
执行成功后,会创建一个 eslint-config
空目录并跳转进入。
npm
初始化
bash
npm init -y
执行成功后,会在根目录下自动生成 package.json
文件。
typescript
初始化
bash
pnpm add typescript -D
tsc init
执行成功后,会在根目录下自动生成 tsconfig.json
文件,并带有默认配置。
- 创建目录结构
基础结构如下:
bash
mkdir src
cd src
touch index.ts
eslint.config.ts
暂且先不创建,预置函数封装完成后再处理。
OK,初始项目到此结束。
定义预置函数 preset
定义预置函数前,首先要考虑两个问题:
- 预置函数应该接收哪些 参数?
- 预置函数应该返回什么 结果?
参数
从设计可知,preset
函数允许以下操作:
因此 preset
至少要支持两个参数:
config
:自定义配置,优先级最高,可覆盖预置配置。envOptions
:环境配置选项,可包含诸如prettier
、vue
、json
、markdown
等,用于启用对应技术栈的预置ESLint
配置。
结果
从设计可知,preset
函数返回的结果,可以被 eslint.config.js
直接导出并生效,因为 Eslint V9.x
配置文件导出的是 平铺结构 ,即 数组 ,所以 preset
函数返回的结果,就是包含完整 ESLint
配置的数组。
preset
函数基础结构定义如下:
javascript
/**
* eslint config 预置函数
*
* @param config 覆盖配置
* @param evnOptions 环境配置项,可接受单个配置对象或多个配置数组
* @returns
*/
export function preset(config: Linter.Config | Linter.Config[] = [], envOptions: EnvOptions = {}) {
// 预置 eslint config 集合
const configs: Linter.Config[] = []
// 环境配置...
// 合并自定义配置
const hasCustomConfig = Array.isArray(config)
? config.length > 0
: Object.keys(config).length > 0
if (hasCustomConfig) {
configs.push(...(Array.isArray(config) ? config : [config]))
}
return configs
}
默认启用配置
封装配置
上文提到,默认启用配置 是指那些大多数项目都需要启用的 ESLint
规则,包括但不限于 Javscript
、Typescript
、ignores
、node
等相关规则。
本文以两个比较直观的 Javscript
规则为例:
bash
eqeqeq: ['error', 'smart'] // 要求代码中相等运算符必须使用全等,即 ===
'no-debugger': 'warn' // 要求代码中不能出现 debugger 调试语句
src
下创建 configs
目录,用来维护各种类型的 ESLint
预置配置文件。
bash
mkdir configs
configs
目录下新建 javascript.ts
文件,用来维护 Javascript
预置配置。
bash
cd configs
touch javascript.ts
javascript.ts
中写入以下代码,导出 javascript
预置配置对象 - javascriptConfigs
。
javascript
import globals from 'globals'
export const javascriptConfigs: Linter.Config[] = [
{
languageOptions: {
globals: {
...globals.browser
},
},
plugins: {},
rules: {
eqeqeq: ['error', 'smart'],
'no-debugger': 'warn'
},
},
]
注:
globals
是一个比较全面的涵盖多个环境全局变量的依赖包,包括但不限于浏览器环境,node
环境等。执行pnpm add globals -S
安装。
篇幅所致,本文定义的 Javascript
规则比较简单,实际项目可基于风格要求自行扩展,比如在 rules
配置内补充规则,在 plugins
配置内引用现有插件等等。
整合配置
将默认规则添加到 preset
函数中:
javascript
import { javascriptConfigs } from './configs/javascript'
// 默认 config
const BasicConfigs = [ ...javascriptConfigs ]
export function preset(config: Linter.Config | Linter.Config[] = [], envOptions: EnvOptions = {}) {
// 默认规则配置
const configs: Linter.Config[] = [ ...BasicConfigs ]
// 环境配置...
// 合并自定义配置...
return configs
}
按需启用配置
封装配置
按需启用配置 依赖项目应用技术栈,交由用户决定是否启用。
我们以相对简单的配置 - Prettier
为例。
尽管目前大多项目都结合使用 ESLint
和 Prettier
,以加强对代码质量的管理,然而 Prettier
并不是必选项,所以可将其作为按需规则之一。
Prettier
配置涉及两个相关插件:
eslint-plugin-prettier
:Prettier
格式化插件。eslint-config-prettier
:关闭ESLint
和Prettier
冲突的规则。
终端输入以下命令安装依赖:
bash
pnpm add eslint-plugin-prettier eslint-config-prettier -S
在 configs
目录下新增 prettier.ts
,用于维护 Prettier
相关配置:
bash
cd configs
touch prettier.ts
prettier.ts
中写入以下代码,导出 Prettier
预置配置对象 - prettierConfigs
。
javascript
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import eslintConfigPrettier from 'eslint-config-prettier'
export const prettierConfigs: Linter.Config[] = [
eslintPluginPrettierRecommended,
eslintConfigPrettier
]
方便起见,直接使用 eslint-plugin-prettier
的推荐配置(recommended
),结合 eslint-config-prettier
提供的配置解决与 ESLint
规则的冲突问题。
到这,基础的 Prettier
配置就搞定了,若插件默认的规则不符合项目要求,可在后面追加自定义的规则对象。例如:
javascript
export const prettierConfigs: Linter.Config[] = [
eslintPluginPrettierRecommended,
eslintConfigPrettier,
{
rules: {
'prettier/prettier': 'warn'
}
}
]
整合配置
现在将 Prettier
配置添加预置函数 preset
中,分为以下两步:
-
preset
第二个参数envOptions
新增prettier
选项,用于设置是否启用Prettier
相关配置,默认true
,即 启用。 -
preset
内部判断prettier
选项是否为true
,若是,则将Prettier
配置加入到最终配置configs
中。
javascript
import { javascriptConfigs, prettierConfigs } from './configs/javascript'
// 默认 config
const BasicConfigs = [ ...javascriptConfigs ]
export function preset(config: Linter.Config | Linter.Config[] = [], {
prettier: enablePrettier = true
}: EnvOptions = {}) {
// 默认规则配置
const configs: Linter.Config[] = [ ...BasicConfigs ]
if (enablePrettier) {
configs.push(...prettierConfigs)
}
// 环境配置...
// 合并自定义配置...
return configs
}
优化项
工具雏形已成,接下来就是在此基础上进行扩展完善,以适应更广泛的应用场景。
集成更多环境配置
一个前端项目,应用的技术多种多样,可针对项目需要,扩展工具内置配置项。
比如 TypeScript
、Vue
、React
、JSON
、Markdown
等,都是前端项目常用的技术栈,因此相关的 ESLint
配置也很有必要集成在工具内。
导出配置
对于某些特殊情况,如对已有 ESLint
配置的增强、完善,可能不想用 preset
函数,仅引用部分规则配置到项目中。
因此可以将工具内置的 ESLint
配置按类导出,供用户按需引入,添加到已有的 ESLint
配置文件中(eslint.config.js
)中。
preset 自动判断是否启用按需配置
preset
函数第二个参数 envOptions
涉及按需启用配置选项,如 vue
,除了直接给定默认值的方式外,还可通过 扫描项目依赖,自动判断是否启用。
例如:
javascript
import { isPackageExists } from 'local-pkg'
// 是否包含 vue
export const hasVue = isPackageExists('vue') || isPackageExists('nuxt')
在 preset
函数中使用:
javascript
export function preset(config: Linter.Config | Linter.Config[] = [], {
prettier: enablePrettier = true,
vue: enableVue = hasVue
}: EnvOptions = {}) {
// 配置整合逻辑...
if (enableVue) {
// 添加 Vue 配置
}
// 合并自定义配置...
}
其他...
实践应用
代码写好了,测试环节不能少,起码要意思意思。我们直接在当前工程应用,毕竟本项目也要注意代码质量。
本文开头 「工程初始化 」部分留了个尾巴,没创建 ESLint
配置文件,现在来完成它。
两步搞定 ESLint
配置:
- 根目录下新增
eslint-config.js
:
javascript
touch eslint-config.js
eslint-config.js
写入以下代码:
javascript
import { preset } from './dist/index.js'
export default preset()
./dist/index.js
是编译后的js
文件。
OK,ESLint
配置搞定,就这么简单。
配置生效的前提需要确保相关依赖已全部安装,如
eslint
、prettier
等,安装过程就不赘述了,点击查看官网即可。
在 src/index.ts
写一点不符合规则的代码,比如:
javascript
if (a == 0) {
debugger
}
此时会发现,VSCode
标记了不合格的代码,鼠标放到问题代码上,会提示不满足的规则配置。
结语
本文重点介绍了 ESLint
预置函数工具的开发过程,包括基础的设计思路,简单的配置整合及粗略的应用演示,旨在帮助同学们加深对于 ESLint
预置函数这东西的了解和应用。希望对您有所帮助。相关代码将上传至 GitHub,欢迎 star。
如您对文章内容有任何疑问或想深入讨论,欢迎评论区留下您的问题和见解。
技术简而不凡,创新生生不息。我是 嘟老板,咱们下期再会。