Изменения в flat config при обновлении

ESLint

Flat config в ESLint представляет собой отказ от каскадной системы .eslintrc в пользу явного, линейного массива конфигурационных объектов. Основное изменение заключается в том, что конфигурация перестаёт наследовать поведение через цепочку extends, env, overrides в привычном виде и становится полностью декларативной структурой, где порядок элементов определяет итоговое состояние правил.

Ключевая идея flat config — устранение неявности. Каждое правило, плагин, парсер и область применения определяются напрямую в одном или нескольких объектах конфигурации.

Структура файла eslint.config.js

Flat config реализуется через файл eslint.config.js, который экспортирует массив:

export default [
  configObject1,
  configObject2,
];

Каждый объект представляет собой автономный блок конфигурации, содержащий:

  • files — область применения (glob-шаблоны)
  • ignores — исключения
  • languageOptions — настройки языка (parser, ecmaVersion, globals)
  • plugins — подключение плагинов
  • rules — набор правил
  • settings — общие настройки плагинов

Пример базовой структуры:

export default [
  {
    files: ["**/*.js"],
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module"
    },
    rules: {
      "no-console": "warn"
    }
  }
];

Уход от .eslintrc и каскадного наследования

В классической системе .eslintrc конфигурация строилась на:

  • extends
  • env
  • overrides
  • автоматическом объединении конфигов
  • скрытом приоритете источников

Flat config заменяет это линейной моделью:

  • порядок объектов определяет приоритет
  • нет скрытого наследования
  • нет автоматического merge по сложным правилам
  • поведение всегда вычисляется сверху вниз

Это устраняет неоднозначности, возникавшие при сложных цепочках extends из нескольких пакетов.

Изменения в механизме overrides

В legacy-конфигурации overrides использовался как вложенная структура. В flat config он заменяется отдельными объектами с files.

Было:

{
  "overrides": [
    {
      "files": ["*.test.js"],
      "rules": {
        "no-unused-expressions": "off"
      }
    }
  ]
}

Стало:

export default [
  {
    files: ["**/*.test.js"],
    rules: {
      "no-unused-expressions": "off"
    }
  }
];

Каждый блок становится самостоятельным слоем конфигурации.

Порядок выполнения и приоритет конфигураций

Flat config полностью зависит от порядка массива. Конфигурации применяются последовательно:

  1. базовые настройки
  2. расширения и плагины
  3. специализированные переопределения

Поздние объекты перезаписывают ранние при совпадении ключей.

Пример приоритетов:

export default [
  {
    rules: {
      semi: "error"
    }
  },
  {
    rules: {
      semi: "off"
    }
  }
];

Итоговое значение semi будет off.

LanguageOptions вместо env

Одним из ключевых изменений становится отказ от env.

В flat config используется:

  • languageOptions.ecmaVersion
  • languageOptions.sourceType
  • languageOptions.globals

Пример:

export default [
  {
    languageOptions: {
      ecmaVersion: 2022,
      sourceType: "module",
      globals: {
        window: "readonly",
        document: "readonly"
      }
    }
  }
];

Это делает окружение более явным и независимым от внутренних preset-ов.

Подключение плагинов и изменение модели plugins

В legacy-модели плагины подключались строками в extends. В flat config плагины импортируются как объекты:

import js from "@eslint/js";

export default [
  js.configs.recommended,
  {
    rules: {
      "no-unused-vars": "warn"
    }
  }
];

Плагины больше не “магически” резолвятся по имени — они становятся частью JavaScript-логики конфигурации.

Изменения в extends и готовых конфигурациях

extends теряет центральную роль. Вместо него используются:

  • импортируемые конфиги
  • spread-конфигурации
  • явное включение наборов правил

Пример:

import js from "@eslint/js";

export default [
  js.configs.recommended
];

Конфигурации перестают быть строковыми ссылками и становятся объектами.

Игнорирование файлов: replaces .eslintignore

Flat config переносит игнорирование в сам конфиг:

export default [
  {
    ignores: ["dist/**", "node_modules/**"]
  }
];

Файл .eslintignore становится необязательным и постепенно вытесняется.

Система совместимости и переходный слой

Для проектов, зависящих от старых конфигураций, используется compatibility слой:

  • @eslint/eslintrc как мост
  • преобразование legacy-конфигов в flat-структуру
  • временное использование гибридного режима

Это позволяет постепенно мигрировать крупные кодовые базы без полной переписки конфигурации.

Отличия в резолве плагинов и парсеров

В flat config:

  • парсеры подключаются явно через languageOptions.parser
  • плагины импортируются как ES-модули или CommonJS объекты
  • отсутствует автоматический поиск по node_modules через строки конфигурации

Пример:

import babelParser from "@babel/eslint-parser";

export default [
  {
    languageOptions: {
      parser: babelParser
    }
  }
];

Изменения в работе с глобальными переменными

Ранее глобальные переменные определялись через env. Теперь они задаются явно:

languageOptions: {
  globals: {
    React: "readonly",
    process: "readonly"
  }
}

Это исключает скрытые наборы глобальных переменных, зависящие от окружения.

Сравнение поведения конфигурации

Legacy .eslintrc:

  • неявное наследование
  • сложный merge
  • строки в extends
  • env как источник магии

Flat config:

  • линейный массив
  • явные импорты
  • порядок важен
  • отсутствие скрытых зависимостей

Типичные проблемы миграции

При переходе на flat config в ESLint часто возникают следующие сложности:

  • потеря правил из-за неправильного порядка объектов
  • дублирование конфигураций при разбиении по файлам
  • необходимость ручного переноса env
  • несовместимость старых shareable configs без адаптера
  • ошибки резолва плагинов при строковом импорте

Изменения в расширяемости конфигураций

Flat config усиливает модульность:

  • конфиги можно импортировать как обычные модули
  • можно собирать конфигурацию динамически
  • допускается условная логика (if/else)
  • возможно формирование конфигурации на основе окружения Node.js

Пример:

const isProd = process.env.NODE_ENV === "production";

export default [
  {
    rules: {
      "no-console": isProd ? "error" : "warn"
    }
  }
];

Упрощение модели анализа файлов

Каждый конфиг блок теперь имеет:

  • явный набор файлов
  • локальные правила
  • локальные плагины

Это устраняет необходимость в сложной диагностике, какой именно слой .eslintrc применился к конкретному файлу.

Влияние на архитектуру линтинга

Flat config в ESLint переводит систему из декларативно-иерархической модели в программируемую конфигурацию. Это сближает линтер с инструментами сборки, где конфигурация является кодом, а не набором JSON-правил.

Поведение становится предсказуемым: одинаковый массив конфигураций всегда даёт одинаковый результат без скрытых внешних факторов.