Версионирование и обновление конфигурации

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

Версионирование конфигурации ESLint позволяет:

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

Особенно важным становится управление версиями в крупных проектах, монорепозиториях и библиотеках с длительным сроком поддержки.


Семантическое версионирование ESLint

ESLint придерживается принципов Semantic Versioning (SemVer).

Формат версии:

MAJOR.MINOR.PATCH

Например:

9.15.0

Где:

  • MAJOR — несовместимые изменения;
  • MINOR — новые возможности без нарушения совместимости;
  • PATCH — исправления ошибок.

Примеры:

Версия Тип изменений
8.56.0 → 8.57.0 Новые возможности
8.57.0 → 8.57.1 Исправления
8.57.1 → 9.0.0 Потенциально ломающие изменения

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


Версионирование конфигурационных файлов

Конфигурация ESLint обычно хранится в одном из файлов:

eslint.config.js
.eslintrc.js
.eslintrc.cjs
.eslintrc.json
.eslintrc.yml

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

Пример фиксации изменений в Git:

git add eslint.config.js
git commit -m "Update ESLint rules for async code"

История изменений позволяет определить:

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

Фиксация версии ESLint

Использование плавающих версий может привести к неожиданным изменениям поведения линтера.

Нежелательный вариант:

{
  "devDependencies": {
    "eslint": "^9.0.0"
  }
}

Символ ^ разрешает автоматическое обновление минорных версий.

Более контролируемый подход:

{
  "devDependencies": {
    "eslint": "9.15.0"
  }
}

В этом случае команда установки всегда получит одинаковую версию ESLint.


Роль lock-файлов

Для воспроизводимости среды используются lock-файлы:

npm

package-lock.json

Yarn

yarn.lock

pnpm

pnpm-lock.yaml

Lock-файл фиксирует:

  • версии ESLint;
  • версии плагинов;
  • версии парсеров;
  • транзитивные зависимости.

Без lock-файла одинаковый package.json может приводить к разным версиям зависимостей на разных машинах.


Версионирование плагинов

Помимо ESLint необходимо контролировать версии плагинов.

Пример:

{
  "devDependencies": {
    "eslint": "9.15.0",
    "eslint-plugin-import": "2.31.0",
    "eslint-plugin-react": "7.36.1"
  }
}

Плагин может:

  • добавлять новые правила;
  • менять логику существующих правил;
  • прекращать поддержку старых API ESLint.

Поэтому обновление плагинов требует такого же внимания, как и обновление самого линтера.


Версионирование расширяемых конфигураций

Многие проекты используют готовые конфигурации:

extends: [
    "eslint:recommended",
    "plugin:react/recommended"
]

Или:

import js from "@eslint/js";

export default [
    js.configs.recommended
];

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

После обновления пакета могут измениться:

  • активированные правила;
  • уровни серьезности;
  • параметры правил;
  • рекомендуемые практики.

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


Проверка текущей версии ESLint

Получение установленной версии:

npx eslint --version

Результат:

v9.15.0

Также версия отображается через менеджер пакетов:

npm list eslint

или:

yarn why eslint

Анализ устаревших зависимостей

Для npm:

npm outdated

Пример вывода:

Package    Current  Wanted  Latest
eslint      9.14.0  9.15.0  9.15.0

Значения:

  • Current — установленная версия;
  • Wanted — допустимая версия согласно package.json;
  • Latest — последняя опубликованная версия.

Такой анализ позволяет планировать обновления конфигурации.


Стратегии обновления ESLint

Консервативная стратегия

Обновления выполняются редко.

Преимущества:

  • высокая стабильность;
  • минимум неожиданностей.

Недостатки:

  • накопление технического долга;
  • сложные миграции между версиями.

Регулярная стратегия

Обновления выполняются постоянно.

Например:

  • ежемесячно;
  • после каждого минорного релиза.

Преимущества:

  • небольшие изменения;
  • проще устранять несовместимости.

Недостатки:

  • дополнительные затраты времени на сопровождение.

Стратегия обновления по релизам

Перед выпуском новой версии продукта выполняется:

  1. обновление ESLint;
  2. обновление плагинов;
  3. обновление конфигурации;
  4. исправление предупреждений.

Такой подход часто используется в корпоративной разработке.


Обновление ESLint

Установка новой версии:

npm install eslint@latest --save-dev

Или конкретной версии:

npm install eslint@9.15.0 --save-dev

После обновления необходимо выполнить:

npx eslint .

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


Изучение изменений перед обновлением

Перед обновлением рекомендуется анализировать:

  • release notes;
  • changelog;
  • migration guide.

Особенно это важно при переходе между мажорными версиями.

Например:

8.x → 9.x

может включать:

  • удаление устаревших API;
  • изменение формата конфигурации;
  • отключение старых механизмов;
  • новые требования к плагинам.

Переход от Legacy Config к Flat Config

Одним из крупнейших изменений в истории ESLint стал переход к Flat Config.

Старый формат:

module.exports = {
    rules: {
        semi: "error"
    }
};

Новый формат:

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

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


Проверка итоговой конфигурации

После обновления полезно анализировать итоговую конфигурацию.

Команда:

npx eslint --print-config src/index.js

Выводит объединенную конфигурацию с учетом:

  • extends;
  • plugins;
  • overrides;
  • flat config.

Это помогает обнаруживать изменения после обновления зависимостей.


Постепенное внедрение новых правил

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

Резкое включение всех правил часто приводит к проблемам.

Более безопасный подход:

rules: {
    "no-console": "warn"
}

После исправления нарушений:

rules: {
    "no-console": "error"
}

Такое внедрение снижает нагрузку на команду.


Использование предупреждений при миграции

Во время обновления часто применяют промежуточное состояние.

Пример:

rules: {
    eqeqeq: "warn",
    curly: "warn",
    semi: "error"
}

После устранения всех замечаний:

rules: {
    eqeqeq: "error",
    curly: "error",
    semi: "error"
}

Подобная схема особенно полезна для старых проектов.


Контроль изменений через CI/CD

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

Пример:

- run: npm ci
- run: npm run lint

Использование команды:

npm ci

гарантирует установку зависимостей строго по lock-файлу.


Создание отдельных веток для обновлений

Практикой сопровождения является выделение отдельной ветки:

chore/update-eslint

Процесс выглядит следующим образом:

  1. обновление зависимостей;
  2. запуск линтера;
  3. исправление нарушений;
  4. ревью изменений;
  5. слияние в основную ветку.

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


Автоматизация обновлений

Для автоматического контроля версий применяются сервисы:

  • Dependabot;
  • Renovate;
  • аналогичные системы управления зависимостями.

Они способны:

  • обнаруживать новые версии;
  • создавать pull request;
  • запускать CI-проверки;
  • формировать отчеты о совместимости.

Это особенно полезно для проектов с большим количеством ESLint-плагинов.


Документирование изменений конфигурации

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

Пример записи в CHANGELOG:

Changed:
- Updated ESLint from 8.57.0 to 9.15.0
- Migrated to Flat Config
- Enabled no-unused-private-class-members

Подобная история упрощает поддержку проекта спустя месяцы и годы.


Типичные проблемы после обновления

Правило перестало существовать

Ошибка:

Definition for rule 'some-rule' was not found

Причины:

  • удаление правила;
  • отключение плагина;
  • несовместимая версия расширения.

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

Ошибка:

ESLint couldn't find the config

Причины:

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

Несовместимость плагина

Ошибка:

This plugin is not compatible with ESLint 9

Решение:

  • обновить плагин;
  • временно остаться на предыдущей версии ESLint;
  • заменить расширение аналогом.

Изменение поведения правил

Даже без ошибок результаты проверки могут измениться.

Например:

"no-unused-vars": "error"

Новая версия правила может обнаруживать больше ситуаций, чем предыдущая.

Поэтому после обновления всегда требуется полный запуск линтера по всему проекту.


Версионирование внутренних конфигураций организации

Крупные компании часто создают собственные пакеты:

@company/eslint-config

Для них также применяется SemVer.

Пример:

{
  "extends": [
    "@company/eslint-config"
  ]
}

Изменения версий могут означать:

  • добавление новых правил;
  • изменение код-стайла;
  • новые требования безопасности;
  • обновление экосистемы TypeScript или React.

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


Рекомендации по безопасному обновлению

  1. Зафиксировать текущие версии зависимостей.
  2. Создать отдельную ветку обновления.
  3. Обновлять сначала ESLint, затем плагины.
  4. Изучать changelog каждой зависимости.
  5. Выполнять полный запуск линтера.
  6. Анализировать итоговую конфигурацию через --print-config.
  7. Проверять CI/CD после обновления.
  8. Использовать lock-файлы.
  9. Документировать изменения.
  10. Выполнять крупные миграции поэтапно, особенно при переходе между мажорными версиями ESLint.