前言
大家好!我是 嘟老板 。在前端开发中,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。
如您对文章内容有任何疑问或想深入讨论,欢迎评论区留下您的问题和见解。
技术简而不凡,创新生生不息。我是 嘟老板,咱们下期再会。