Переход на flat config в ESLint означает отказ от традиционной модели
конфигурации на базе .eslintrc.* в пользу явного
JavaScript-конфига, где все правила, плагины и настройки описываются в
одном массиве объектов. Это изменение устраняет неявные механизмы
наследования и сложную систему каскадирования конфигураций, делая
поведение линтера более предсказуемым.
В legacy-конфигурации использовались файлы .eslintrc,
.eslintrc.json, .eslintrc.js,
.eslintrc.yml, а также механизмы extends,
overrides, env, globals. Flat
config заменяет это единым файлом eslint.config.js, где
каждая конфигурация — это объект с явными полями.
Flat config представляет собой массив конфигурационных объектов:
// eslint.config.js
export default [
{
files: ["**/*.js"],
rules: {
semi: "error",
"no-unused-vars": "warn"
}
}
];
Каждый объект описывает:
files)plugins)rules)В legacy конфигурации поведение строилось на неявном объединении:
extendsoverridesenvFlat config заменяет это на явную композицию массивов, где порядок элементов имеет значение.
extendsВ legacy:
{
"extends": ["eslint:recommended", "plugin:react/recommended"]
}
В flat config:
import js from "@eslint/js";
import react from "eslint-plugin-react";
export default [
js.configs.recommended,
react.configs.recommended
];
Каждый набор конфигурации становится обычным JavaScript-объектом, который импортируется и вставляется в массив.
В legacy plugins регистрировались строками:
{
"plugins": ["react"]
}
В flat config плагины импортируются как модули:
import react from "eslint-plugin-react";
export default [
{
files: ["**/*.jsx"],
plugins: {
react
},
rules: {
"react/jsx-uses-react": "error"
}
}
];
Ключевое изменение заключается в том, что больше нет строковых идентификаторов — только явные ссылки на объекты.
Flat config объединяет несколько legacy-полей в
languageOptions.
import js from "@eslint/js";
export default [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 2022,
sourceType: "module",
globals: {
window: "readonly",
document: "readonly"
}
}
}
];
В legacy:
parserOptions.ecmaVersion →
languageOptions.ecmaVersionparserOptions.sourceType →
languageOptions.sourceTypeenv → languageOptions.globalsВ legacy:
{
"overrides": [
{
"files": ["*.test.js"],
"rules": {
"no-unused-expressions": "off"
}
}
]
}
В flat config overrides исчезают как отдельная сущность, так как каждый объект уже является изолированным override:
export default [
{
files: ["**/*.js"],
rules: {
"no-unused-expressions": "error"
}
},
{
files: ["**/*.test.js"],
rules: {
"no-unused-expressions": "off"
}
}
];
В legacy:
{
"globals": {
MyGlobal: "readonly"
}
}
В flat config:
export default [
{
languageOptions: {
globals: {
MyGlobal: "readonly"
}
}
}
];
В legacy:
{
"parser": "@babel/eslint-parser"
}
В flat config:
import babelParser from "@babel/eslint-parser";
export default [
{
languageOptions: {
parser: babelParser
}
}
];
Parser становится обычным объектом, а не строковым идентификатором.
Flat config требует явного доступа к правилам через объект плагина.
import react from "eslint-plugin-react";
export default [
{
plugins: {
react
},
rules: {
"react/jsx-no-undef": "error",
"react/jsx-uses-vars": "error"
}
}
];
Некоторые плагины экспортируют готовые конфигурации:
import react from "eslint-plugin-react";
export default [
react.configs.flat.recommended
];
В legacy использовался .eslintignore. В flat config
используется поле ignores.
export default [
{
ignores: ["dist/**", "node_modules/**"]
},
{
files: ["**/*.js"],
rules: {
"no-console": "warn"
}
}
];
ignores может быть как отдельным объектом, так и частью
общей конфигурации.
Flat config строго полагается на порядок массива:
Пример:
export default [
baseConfig,
nodeConfig,
{
files: ["**/*.test.js"],
rules: {
"no-undef": "off"
}
}
];
Каждый последующий объект перекрывает предыдущие значения.
Процесс перехода с legacy на flat config состоит из последовательного преобразования конфигурации.
Типичная структура:
{
"extends": ["eslint:recommended"],
"parserOptions": {
"ecmaVersion": 2021
},
"env": {
"node": true
},
"rules": {
"no-console": "warn"
}
}
import js from "@eslint/js";
export default [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 2021,
globals: {
console: "readonly"
}
},
rules: {
"no-console": "warn"
}
}
];
Некоторые конфиги используют цепочки extends, которые
сложно развернуть. В flat config необходимо явно импортировать каждый
уровень.
Не все плагины сразу предоставляют flat-совместимые
конфигурации. В таких случаях требуется вручную переносить правила.
Так как порядок имеет значение, неправильное расположение объектов может привести к неожиданному переопределению правил.
В некоторых версиях ESLint допускается параллельное существование
legacy и flat конфигурации, но приоритет отдаётся
eslint.config.js. Это может привести к ситуации, когда
старые .eslintrc файлы игнорируются полностью.
При увеличении проекта конфигурация обычно разбивается на модули:
import base from "./config/base.js";
import node from "./config/node.js";
import react from "./config/react.js";
export default [
base,
node,
react
];
Каждый модуль экспортирует массив или объект конфигурации, что
позволяет сохранять модульность без extends.
Flat config делает управление правилами более явным:
Каждое правило существует в конкретном месте и применяется строго по порядку.
Поскольку конфиг становится JavaScript-кодом, возможны:
Пример условной логики:
const isProduction = process.env.NODE_ENV === "production";
export default [
{
rules: {
"no-console": isProduction ? "error" : "warn"
}
}
];
Flat config требует перехода от декларативной “магии” legacy-конфига к композиционной модели:
Такой подход делает систему линтинга более прозрачной, но увеличивает необходимость контролировать структуру конфигурации вручную.