一、前言
Element Plus 组件非常庞大,多人开发是必要的,但多人开发存在开发人员的代码风格不一致,需要规范代码才能提交。为了统一代码风格,我们可以使用ESLint 代码校验工具,通过配置 ESLint 相关配置来对代码进行检测,提醒我们的按照符合校验的代码风格进行编码。
本章节将会详细介绍 ESLint 在 Element Plus 中的配置,以及详细概括 ESLint 的基本原理、配置文件中的配置项和 Prettier 的基本使用。
二、ESLint 的工作原理
一)、寻找配置文件
ESLint 会在项目的根目录或者指定路径下寻找配置文件,配置文件可以支持多种格式 。
- JavaScript 文件:( .eslintrc.js 或 eslint.config.js )
- JSON 文件:( .eslintrc.json )
- YAML 文件:( .eslintrc.yml 或 .eslintrc.yaml )
ESLint 会先寻找 .eslintrc.*
文件,如果这些文件都不存在,会去查找 package.json
中的 eslintConfig
字段。ESLint 会从根目录或指定路径,向上递归查找配置文件,如果在**某个配置文件中设置了 **<font style="color:#117CEE;">root:true</font>**
,则会终止向上查找,表示这个配置文件是根配置文件。**
二)、解析源码生成 AST 、分析 rules 配置项原理
1、解析源码生成 AST
ESLint 是一个基于抽象语法树( AST )静态代码分析工具、它通过使用**解析器解析源码,转换为 AST**** **, ESLint 中默认的解析器( parser )是 Espree
,用来解析 ECMAScript 规范中的 JavaScript 代码。如果想使用其他的解析器,可以直接指定 parser
配置项。比如 parser:@typescript-eslint/parser
。
2、分析 rules 配置项原理
获取到 AST 后, ESLint 会遍历 AST ,在遍历的过程中,ESLint 会应用用户在配置项配置的 rules ,每个规则都注册了特定的节点类型,当遍历到与规则相关的节点时,ESLint 会调用规则的处理函数进行检查。rules 的执行原理分为以下步骤。
读取配置、加载规则、解析规则配置、遍历 AST、执行规则处理函数、报告处理、自动修复(可选)、输出结果。
1)、规则源码的代码结构
每个 ESLint 规则源码通常有以下结构
module.exports = {
meta: {
type: "problem", // 规则的类型,可以是 "problem", "suggestion", "layout"
docs: {
description: "disallow the use of 'var'",
category: "Best Practices",
recommended: true
},
fixable: "code", // 是否支持自动修复
schema: [] // 规则的配置选项,通常是一个 JSON schema
},
create(context) {
return {
VariableDeclaration(node) {
if (node.kind === "var") {
context.report({
node,
message: "Unexpected var, use let or const instead.",
fix(fixer) {
return fixer.replaceText(node, "let"); // 自动修复代码
}
});
}
}
};
}
};
2)、加载和解析规则
ESLint 读取配置文件会读取 rules
配置项,配置项指定了要启用的规则,ESLint 通过规则名称在 **ESLint 内置的规则集或者自定义的规则**中找到对应的规则模块,如果这个规则被启用,会为这个规则 其传入 context
对象。context
提供了规则执行过程中所需的上下文信息和工具(如报告错误、获取源码位置、执行自动修复等)。
3)、执行规则
ESLint 中的 parser 解析器解析源码后,将它转换成 AST ,遍历各个节点,检查节点是否有与该节点类型相关的规则处理函数,如果存在则调用规则处理函数进行处理,并将当前节点参数传递给它。
以 no-var
规则为例,当遍历到 VariableDeclaration
节点时,no-var
规则的处理函数会被调用,且会将当前的节点和节点上下文传递给处理函数,如果生成报告后需要 fix 它会调用 replaceText
函数进行修复,代码被修复成想要的格式。
VariableDeclaration(node) {
if (node.kind === "var") {
context.report({
node,
message: "Unexpected var, use let or const instead.",
fix(fixer) {
return fixer.replaceText(node, "let"); // 自动修复代码
}
});
}
}
相信看到这里,我们应该对 rules 的运行原理有个更加清晰的认识。 rules 的作用是:**rules**
** 用于启用或禁用特定的 ESLint 规则,或对规则进行自定义配置**。规则的值可以是 "off"
(禁用)、"warn"
(警告)、"error"
(错误),并可以附带具体的配置选项 。它配置的规则在整个配置文件中优先级也是最高的。
三)、ESLint 中 extends 选项解析
在 ESLint 中,extends
关键字**用于继承现有的配置。这使得你可以基于某个预设配置或者其他已经定义好的配置文件,快速建立自己的 ESLint 配置,而不需要从头开始。这种继承机制可以帮助你避免重复配置**。
extends
允许继承官方推荐配置 eslint:recommended
、继承插件推荐配置,比如常见的 plugin:vue/recommended
。也支持配置自己创建的 ESLint 配置模块,Element Plus 组件库中就是在根目录中继承在子项目中配置 ESLint 配置模块,想要在多个项目中使用可以将自己配置的 ESLint 可以发布 npm 包在 extends
中引入插件推荐的配置。
在 extends
中配置多个配置项时,这些在extends
中的配置会按照**由下置上的优先级顺序检测,如果配置项之间的规则有冲突时,优先级高的会覆盖优先级低的配置项并合并成一个配置规则**。配置项的名称遵循以下规则。
- eslint: 开头的代表是以 ESLint 自身的规则。
- plugin: 开头的代表以 ESLint 插件的规则,
plugin:vue/vue3-recommended
,**/**
** 后面的**vue3-recommended**
表示插件推荐的 ESLint 规则名称**。
了解以上这些,我们再来看看 ELement Plus 中的 ESlint 配置项 extends 中的配置,应该就很容易理解了。
extends: [
'eslint:recommended', //使用eslint推荐的规则
'plugin:import/recommended', //使用eslint-plugin-import 推荐的规则
'plugin:eslint-comments/recommended', //使用eslint-plugin-comments-recommended推荐的规则
'plugin:jsonc/recommended-with-jsonc', //使用eslint-plugin-jsonc推荐的规则,适用于JSONC(json with Comments)
'plugin:markdown/recommended', //使用eslint-plugin-markdown 插件推荐的规则
'plugin:vue/vue3-recommended', //使用eslint-plugin-vue 推荐Vue3的规则
'plugin:@typescript-eslint/recommended', //使用@typescript-eslint 推荐的规则
'prettier', //使用prettier配置,关闭所有与prettier冲突的eslint规则
],
四)、ESLint 其他配置项解析
配置项的说明在代码块中举例说明。
{
//env 用于指定代码运行的环境,从而启用特定环境的全局变量和规则。
"env": {
"browser": true, // 启用浏览器环境的全局变量 (window, document 等)
"node": true, // 启用 Node.js 环境的全局变量 (require, module 等)
"es6": true // 启用 ES6 环境,默认支持 ES6 全局变量
},
//parser 用于指定代码的解析器
"parser": "@typescript-eslint/parser" ,// 使用 TypeScript 的解析器
//parserOptions 用于配置解析器的选项,如 ECMAScript 版本、模块类型、是否允许 JSX 语法
"parserOptions": {
"ecmaVersion": 2020, // 支持 ES2020 语法
"sourceType": "module", // 使用 ES6 模块语法
"ecmaFeatures": {
"jsx": true // 支持 JSX 语法
}
}
//plugins 用于加载额外的 ESLint 插件,这些插件可以提供额外的规则、环境定义、或解析器
"plugins": [
"vue", // 加载 eslint-plugin-vue 插件
"@typescript-eslint" // 加载 @typescript-eslint 插件
],
//overrides 用于为特定的文件或文件类型设置不同的配置
"overrides": [
{
"files": ["*.ts", "*.tsx"], // 仅对 TypeScript 文件应用以下规则
"rules": {
"@typescript-eslint/no-unused-vars": "error" // TypeScript 特定的规则
}
},
{
"files": ["*.vue"], // 仅对 Vue 文件应用以下规则
"rules": {
"vue/html-indent": ["error", 2] // Vue 文件中的 HTML 缩进规则
}
}
],
//globals 用于定义项目中的全局变量,并指定这些变量是否可写
"globals": {
"jQuery": "readonly", // jQuery 作为只读全局变量
"$": "readonly" // $ 作为只读全局变量
},
//settings 用于为ESlint配置一些全局设置,它可以用来提供一些额外的配置选项
"settings": {
//这个主要是配置了eslint-plugin-import 插件,主要用于指定拓展名来解析模块路径