ESLint Flat Config 插件配置完全指南:从安装到 processor、language 的实战用法
2026/9/12 13:15:41 网站建设 项目流程

ESLint Flat Config 插件配置完全指南:从安装到 processor、language 的实战用法

【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint

本篇指南聚焦 ESLint 的 flat config 配置体系中插件(plugins)的完整配置方法:如何通过plugins键引入第三方插件与本地插件、如何按命名空间引用插件规则、如何借助处理器(processor)检查 Markdown 等非 JavaScript 文件、以及如何为 JSON 等语言指定自定义 language。读完本文,你将能独立在eslint.config.js中组织插件、规则、处理器与语言配置,并结合源码理解 ESLint 底层是如何解析与合并这些配置项的。

插件能为 ESLint 扩展什么

在 ESLint 中,插件是扩展核心能力的主要手段。插件本质上是一个“符合 ESLint 识别接口的对象”,它可以包含三类可扩展内容:

  • 自定义规则(Custom rules):校验你的代码是否满足某项预期,以及不满足时如何处理(例如no-console这类规则就是由插件规则扩展而来的)。
  • 自定义配置(Custom configurations):插件内预置的一组配置(如recommended),具体用法请以插件自身文档为准。
  • 自定义处理器(Custom processors):从其他类型的文件中提取 JavaScript 代码,或在 lint 之前对代码做预处理(例如从.md中提取代码块)。

从插件对象的接口定义看(参见 docs/src/extend/plugins.md),一个标准插件通常导出如下结构的对象:

const plugin = { meta: {}, // 插件元信息(name、version、namespace) configs: {}, // 插件内置的命名配置 rules: {}, // 自定义规则定义 processors: {}, // 命名处理器 }; // ESM export default plugin; // 或 CommonJS module.exports = plugin;

仓库自带的插件示例(docs/_examples/custom-rule-tutorial-code/eslint-plugin-example.js)就是最精简的形态:const plugin = { rules: { "enforce-foo-bar": fooBarRule } },仅暴露一条规则。下面我们重点讲解配置端如何使用这些插件。

配置插件:plugins键与命名空间

要在配置文件(flat config 格式的eslint.config.js)中启用插件,需要使用plugins键。它是一个对象:属性名代表插件的命名空间(namespace),属性值就是插件对象本身

// eslint.config.js import example from "eslint-plugin-example"; import { defineConfig } from "eslint/config"; export default defineConfig([ { plugins: { example, }, rules: { "example/rule1": "warn", }, }, ]);

命名约定:为插件创建命名空间时,惯例是去掉 npm 包名中的eslint-plugin-前缀。例如eslint-plugin-example的命名空间就是example

底层校验:plugins 必须是对象

从源码看(lib/config/flat-config-schema.js),pluginsSchemaplugins值做了严格校验:

  • 值必须是对象,如果是数组则会抛出IncompatiblePluginsError,提示“这看起来是 eslintrc 格式(字符串数组)而非 flat config 格式(对象)”;
  • 每个命名空间下的值也必须是对象;
  • 合并时,如果两个配置对象试图用不同的插件对象重定义同一个命名空间,会抛出Cannot redefine plugin "xxx"错误——这是 flat config 避免插件冲突的关键机制。

也就是说,flat config 不再像旧的 eslintrc 那样通过plugins: ["example"]字符串数组声明插件,而是直接传入插件对象本身,规则名中的example/前缀因此可以与对象直接对应。

配置本地插件

插件不一定要发布到 npm。你可以直接从本地文件加载插件:

// eslint.config.js import local from "./my-local-plugin.js"; import { defineConfig } from "eslint/config"; export default defineConfig([ { plugins: { local, }, rules: { "local/rule1": "warn", }, }, ]);

这里使用了命名空间local,你可以换成任意喜欢的名字。本地插件的价值在于:团队内部的专用规则无需发布,直接通过相对路径引入即可,配合下文“虚拟插件”甚至可以做到零文件组织的即时规则启用。

配置虚拟插件

插件定义可以直接在配置中“虚拟”创建。假设你有一个位于./rules/my-rule.js的规则文件,想直接在配置里启用它,可以把它包装成一个虚拟插件:

// eslint.config.js import myRule from "./rules/my-rule.js"; import { defineConfig } from "eslint/config"; export default defineConfig([ { plugins: { local: { rules: { "my-rule": myRule, }, }, }, rules: { "local/my-rule": "warn", }, }, ]);

这里命名空间local定义了一个虚拟插件,规则myRule在虚拟插件的rules对象中被命名为my-rule(规则名中不能包含/)。随后即可用local/my-rule引用并配置它。插件的完整对象格式可参考 docs/src/extend/plugins.md。

使用插件规则

启用插件后,就可以使用插件自带的规则。规则名采用命名空间/规则名的格式,前缀部分表明规则来自哪个插件而非 ESLint 内置规则。以 JSDoc 插件为例:

// eslint.config.js import jsdoc from "eslint-plugin-jsdoc"; import { defineConfig } from "eslint/config"; export default defineConfig([ { files: ["**/*.js"], plugins: { jsdoc: jsdoc, }, rules: { "jsdoc/require-description": "error", "jsdoc/check-values": "error", }, }, ]);

因为插件名与对象名恰好都是jsdoc,可以简写为:

import jsdoc from "eslint-plugin-jsdoc"; import { defineConfig } from "eslint/config"; export default defineConfig([ { files: ["**/*.js"], plugins: { jsdoc, }, rules: { "jsdoc/require-description": "error", "jsdoc/check-values": "error", }, }, ]);

自定义命名空间前缀

虽然同名是最常见惯例,但并非强制。你可以为插件指定任意前缀,例如把eslint-plugin-jsdoc命名为jsd

import jsdoc from "eslint-plugin-jsdoc"; import { defineConfig } from "eslint/config"; export default defineConfig([ { files: ["**/*.js"], plugins: { jsd: jsdoc, }, rules: { "jsd/require-description": "error", "jsd/check-values": "error", }, }, ]);

此时规则引用前缀也要同步改为jsd/注意:规则配置的严重度支持"off"0"warn"1"error"2六种取值(lib/config/flat-config-schema.js 中的ruleSeverities映射),配置错误会抛出invalid-rule-optionsinvalid-rule-severity错误。

命名空间格式限制

从源码(docs/src/extend/plugins.md)可知,命名空间有不带@与带@两种规则:

  • 不以@开头的命名空间不能包含/(如eslint/plugin非法);
  • @开头的命名空间可以包含/(如@eslint/plugin合法)。

这一限制是为了兼容旧 eslintrc 的插件命名规则。底层assertIsPluginMemberName(lib/config/flat-config-schema.js)用正则[\w\-@$]+(?:\/[\w\-$]+)+校验插件名/成员名的格式。

指定处理器(Processor)

插件还可以提供处理器(processor)。处理器的两种能力:

  1. 提取:从其他类型的文件中提取 JavaScript 代码,交给 ESLint 检查(如从 Markdown 提取代码块);
  2. 预处理:在 lint 之前对 JavaScript 代码做转换。

在配置文件中使用processor键,值格式为命名空间/处理器名。下面用@eslint/markdown*.md文件启用markdown/markdown处理器:

// eslint.config.js import markdown from "@eslint/markdown"; import { defineConfig } from "eslint/config"; export default defineConfig([ { files: ["**/*.md"], plugins: { markdown, }, processor: "markdown/markdown", }, ]);

处理器与命名代码块

处理器可能会产出命名代码块,例如0.js1.js。ESLint 会把这样的代码块当作原文件的子文件来处理,你可以用额外的配置对象对它们做精细化设置。例如,对所有 JavaScript 文件开启strict规则,但关闭 Markdown 内 JS 代码块的strict

// eslint.config.js import markdown from "@eslint/markdown"; import { defineConfig } from "eslint/config"; export default defineConfig([ // 应用于所有 JavaScript 文件 { rules: { strict: "error", }, }, // 应用于 Markdown 文件 { files: ["**/*.md"], plugins: { markdown, }, processor: "markdown/markdown", }, // 仅应用于 Markdown 文件内部的 JavaScript 代码块 { files: ["**/*.md/*.js"], rules: { strict: "off", }, }, ]);

注意**/*.md/*.js这种“斜杠嵌套”的 glob 模式,正是用来匹配“Markdown 文件内名为.js的代码块”的。

关键限制:ESLint 只检查命名代码块,且仅在它是 JavaScript 文件、或与某个配置对象的files条目匹配时才进行 lint。如果要检查非 JavaScript 的命名代码块,必须额外添加带匹配files条目的配置对象。同时,全局忽略规则同样适用于命名代码块。

下面是另一个实战示例:为 Markdown 内的 JSX 代码块开启 JSX 语法,同时忽略test.md文件内的 JSX 代码块:

// eslint.config.js import markdown from "@eslint/markdown"; import { defineConfig } from "eslint/config"; export default defineConfig([ // 应用于 Markdown 文件 { files: ["**/*.md"], plugins: { markdown, }, processor: "markdown/markdown", }, // 应用于所有 .jsx 文件,包括 Markdown 文件内部的 jsx 代码块 { files: ["**/*.jsx"], languageOptions: { parserOptions: { ecmaFeatures: { jsx: true, }, }, }, }, // 忽略 test.md 文件内部的 jsx 代码块 { ignores: ["**/test.md/*.jsx"], }, ]);

处理器源码层面的执行机制

从源码(lib/services/processor-service.js)可以印证处理器的调用链:ProcessorService.preprocessSync(file, config)会调用processor.preprocess(file.rawBody, file.path)得到代码块数组,再对每个块构造“子文件”(path.join(file.path, \${i}_${block.filename}`),即原路径/序号_块名的形式);lint 完成后,postprocessSync会把所有子文件的 lint 消息合并交回processor.postprocess(messages, file.path)做最终汇总。这解释了为什么代码块匹配模式是**/.md/.js——子文件的路径就是在原路径下以/` 拼接块名的。

同时,processorSchema(lib/config/flat-config-schema.js)要求:若processor直接传对象,则该对象必须同时具备preprocess()postprocess()方法;传字符串时则按插件名/处理器名格式校验。

指定语言(Language)

插件还可以提供语言支持(language),让 ESLint 检查 JavaScript 之外的语言。在配置文件中使用language键,值格式为命名空间/语言名。例如用@eslint/jsonjson/jsonc语言检查*.json文件:

// eslint.config.js import json from "@eslint/json"; import { defineConfig } from "eslint/config"; export default defineConfig([ { files: ["**/*.json"], plugins: { json, }, language: "json/jsonc", }, ]);

注意:当你在配置对象中指定了language后,languageOptions就会变得与这种语言绑定——每种语言都定义自己的languageOptions。具体支持哪些选项,需要查阅对应插件的文档。例如@eslint/jsonjsonc语言就带有与 JSON 解析相关的选项。

底层同样由languageSchema(lib/config/flat-config-schema.js)负责校验,值必须是插件名/语言名格式的字符串。语言机制让 ESLint 从一个“JavaScript linter”扩展为多语言 lint 平台,这一能力的详细设计可进一步阅读 docs/src/extend/languages.md。

常见问题排查

在配置插件过程中可能遇到两类典型问题:

  1. 插件规则使用 ESLint < v9.0.0 的旧 API:旧版插件基于 eslintrc 时代的 API 编写,直接用于 flat config 会报错,需要先让插件升级到兼容 v9+ 的 API。
  2. 插件配置尚未升级到 flat config:插件内置的configs仍是 eslintrc 格式。flat config 中需要通过extends引用插件的 flat config(例如example/recommended),对于旧式recommended配置,可参考 docs/src/use/configure/migration-guide.md#use-eslintrc-configs-in-flat-config 了解如何在 flat config 中继续使用它们;插件作者侧的双格式兼容写法(flat/recommendedrecommended并存)见 docs/src/extend/plugins.md。

小结

在 flat config 体系中,插件配置的核心脉络可以概括为四步:

  1. 引入import插件对象(第三方包、本地文件或虚拟对象均可);
  2. 注册:在plugins键中以“命名空间 → 插件对象”的形式注册,命名空间决定规则、处理器、语言的前缀;
  3. 使用:在rules中引用命名空间/规则名并指定严重度;在processor中引用命名空间/处理器名处理非 JS 文件;在language中引用命名空间/语言名扩展可 lint 的语言;
  4. 细化:利用**/*.md/*.js这类嵌套 glob 对处理器产出的命名代码块做差异化配置。

掌握这套机制后,无论是引入成熟的生态插件(如eslint-plugin-jsdoc@eslint/markdown@eslint/json),还是为团队编写并使用本地/虚拟插件,你都能在eslint.config.js中游刃有余地组织出一套清晰、可维护的 lint 体系。

【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询