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

Система конфигурации ESLint изначально строилась вокруг файлов .eslintrc, которые поддерживали несколько форматов: JSON, YAML и JavaScript. Конфигурация могла наследоваться, расширяться через extends, переопределяться через overrides и дополняться плагинами. Такой подход долгое время обеспечивал гибкость, но с ростом сложности JavaScript-экосистемы начал демонстрировать структурные ограничения.

Развитие фронтенд-инструментария привело к появлению монорепозиториев, ESM-модулей, TypeScript-интеграций и сложных цепочек трансформаций кода. На этом фоне модель конфигурации ESLint начала терять предсказуемость и масштабируемость.


Неоднозначность и сложность модели наследования

Одной из ключевых причин появления новой системы стала сложность механизма объединения конфигураций.

Старый подход использовал несколько уровней наследования:

  • extends для базовых конфигураций
  • overrides для условий по файлам
  • локальные настройки, перекрывающие глобальные
  • плагинные конфигурации, встраивающие собственные правила

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

Особые проблемы возникали при:

  • многократном наследовании конфигов
  • конфликтующих правилах из разных shareable-конфигураций
  • глубоко вложенных overrides
  • использовании условных файловых паттернов

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


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

Старый механизм конфигурации требовал значительных затрат на этапе инициализации.

Причины:

  • рекурсивное разрешение extends
  • загрузка множества файлов конфигураций из node_modules
  • динамическое выполнение JavaScript-конфигов
  • разрешение плагинов и их внутренних зависимостей
  • повторное вычисление итоговой конфигурации для разных файлов

При больших проектах с монорепозиториями это приводило к заметной задержке старта ESLint.

Особенно критичным становилось:

  • повторное сканирование конфигураций при запуске CLI
  • отсутствие эффективного кэширования итоговой структуры конфигурации
  • необходимость многократного разрешения одних и тех же зависимостей

Ограничения динамической JavaScript-конфигурации

Поддержка JavaScript в .eslintrc.js давала гибкость, но одновременно создавала неопределённость.

Основные проблемы:

  • выполнение произвольного кода при загрузке конфигурации
  • невозможность статического анализа конфигурации
  • сложность предсказания итогового результата
  • побочные эффекты при импортах
  • зависимость от окружения Node.js

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


Ограничения системы overrides

Механизм overrides позволял применять разные правила для различных файлов, но его поведение становилось всё более сложным.

Проблемные аспекты:

  • порядок применения overrides имел критическое значение
  • пересечение паттернов приводило к неожиданным конфликтам
  • невозможно было легко визуализировать итоговые правила для конкретного файла
  • вложенные overrides усложняли ментальную модель конфигурации

При росте числа файловых групп система становилась трудной для сопровождения и масштабирования.


Сложности интеграции с современными модулями (ESM)

Переход экосистемы на ES Modules выявил ограничения старой системы конфигурации.

Проблемы включали:

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

ESLint долгое время поддерживал гибридный подход, но это увеличивало технический долг и усложняло архитектуру.


Масштабирование в монорепозиториях

Современные проекты часто включают десятки пакетов в одном репозитории. В старой системе это приводило к следующим проблемам:

  • дублирование конфигураций между пакетами
  • сложность централизованного управления правилами
  • дорогостоящий резолвинг конфигурации для каждого пакета
  • нестабильность при наследовании через уровни директорий

Особенно сложными становились случаи, когда разные пакеты требовали:

  • различных версий плагинов
  • частично пересекающихся правил
  • индивидуальных исключений для тестов и сборки

Система .eslintrc не обеспечивала эффективной модели изоляции конфигураций.


Неэффективность модели плагинов в контексте конфигурации

Плагины ESLint исторически не только предоставляли правила, но и могли экспортировать конфигурации.

Это приводило к нескольким проблемам:

  • неявное наследование правил через плагины
  • скрытые зависимости конфигурации
  • невозможность точно определить источник правила
  • конфликты между версиями плагинов

Фактически конфигурация становилась распределённой системой, где итоговое поведение зависело от цепочки подключённых пакетов.


Отсутствие строгой модели данных конфигурации

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

Конфигурация представляла собой смесь:

  • JSON-объектов
  • JavaScript-функций
  • строковых ссылок на пакеты
  • глобальных и локальных переопределений

Отсутствие строгой модели приводило к тому, что:

  • невозможно было корректно сериализовать конфигурацию
  • сложно было сравнивать конфиги между собой
  • инструменты анализа конфигурации были ограничены

Необходимость детерминированного результата

Одним из ключевых архитектурных требований стала предсказуемость результата линтинга.

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

  • порядка загрузки файлов
  • версии Node.js
  • структуры зависимостей
  • особенностей резолвинга модулей

Это создавало проблемы при:

  • кэшировании результатов
  • интеграции с редакторами
  • параллельной обработке файлов

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


Рост требований к интеграции с инструментами разработки

ESLint начал активно использоваться не только как CLI-инструмент, но и как часть IDE-инфраструктуры.

Это потребовало:

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

Старая система конфигурации плохо подходила для таких сценариев из-за своей динамической природы и сложного процесса наследования.


Переход к более декларативной модели конфигурации

Общий вектор изменений заключался в переходе от гибридной (декларативно-императивной) модели к строго декларативной.

Ключевые цели новой архитектуры:

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

Старая система конфигурации перестала соответствовать этим требованиям из-за накопившейся исторической сложности и большого количества обратной совместимости.


Снижение когнитивной нагрузки при анализе конфигурации

При работе с крупными проектами разработчики сталкивались с необходимостью вручную интерпретировать итоговую конфигурацию ESLint.

Причины сложности:

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

Отсутствие простой модели «вход → итоговый набор правил» делало анализ конфигурации трудоёмким и подверженным ошибкам.


Эволюция архитектуры конфигурационного ядра

Совокупность перечисленных факторов привела к необходимости пересмотра архитектуры конфигурации ESLint. Основной акцент сместился на:

  • упрощение структуры данных конфигурации
  • устранение скрытых механизмов объединения
  • снижение стоимости резолвинга
  • повышение предсказуемости и воспроизводимости результата
  • адаптацию к современным форматам модулей и монорепозиториев

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