Разделение запуска ESLint становится критически важным в больших кодовых базах, где линтинг всего проекта целиком приводит к значительным задержкам, блокирует CI-пайплайны и ухудшает скорость обратной связи при разработке. Основная идея заключается в том, чтобы разбивать процесс анализа кода на независимые части и выполнять их параллельно или избирательно, минимизируя объём обрабатываемых файлов за один запуск.
Самый прямолинейный способ разнести запуск ESLint — ограничение области анализа через файловые шаблоны. Вместо глобального запуска по всему проекту используется несколько отдельных команд.
eslint src/
eslint tests/
eslint scripts/
Такой подход формирует несколько независимых процессов, каждый из которых работает в собственной области ответственности. При этом уменьшается нагрузка на парсер, особенно в проектах с большим количеством TypeScript-файлов или сложной конфигурацией правил.
Более детализированное разделение выполняется через glob-шаблоны:
eslint "src/**/*.ts"
eslint "src/**/*.tsx"
eslint "config/**/*.js"
Разделение по расширениям файлов снижает вероятность избыточной проверки нерелевантных файлов и позволяет более точно настраивать правила под конкретные типы кода.
В среде Node.js часто используется разбиение линтинга на набор npm-скриптов, каждый из которых отвечает за свою часть проекта:
{
"scripts": {
"lint:core": "eslint src/core",
"lint:ui": "eslint src/ui",
"lint:tests": "eslint tests"
}
}
Далее такие задачи могут выполняться независимо или в параллельном режиме. Подобная структура особенно эффективна в монорепозиториях, где разные области кода имеют разные правила и зависимости.
Для ускорения обработки применяется параллельный запуск нескольких процессов ESLint. Это особенно актуально на многоядерных системах, где последовательный запуск не использует вычислительные ресурсы полностью.
npm-run-all --parallel lint:core lint:ui lint:tests
Или через GNU parallel:
ls -d src/* | parallel eslint
Параллелизация требует осторожности при работе с общими кешами, поскольку одновременная запись может приводить к конфликтам, если не настроен корректный cache location.
Кеширование ESLint существенно снижает стоимость повторных запусков. При разделённой стратегии кеш становится связующим элементом между независимыми частями анализа.
eslint src --cache --cache-location node_modules/.cache/eslint/core
eslint tests --cache --cache-location node_modules/.cache/eslint/tests
Разделение кеша по областям позволяет избежать перезаписи и обеспечивает независимость результатов между разными частями проекта.
Одним из наиболее эффективных подходов является линтинг только изменённых файлов. В этом случае ESLint запускается на основе списка файлов, полученных из системы контроля версий.
eslint $(git diff --name-only --diff-filter=ACMRTUXB origin/main | grep "\.js$\|\.ts$")
Такой метод часто используется в CI-системах, где нет необходимости повторно анализировать неизменённый код. Он значительно снижает время проверки при частых коммитах.
Для более строгого разделения можно дополнительно группировать изменённые файлы:
git diff --name-only origin/main | split -l 50 - chunk_
И затем запускать ESLint для каждого фрагмента отдельно.
В распределённых CI-системах применяется подход шардирования, при котором весь набор файлов делится на фиксированное количество частей, каждая из которых обрабатывается отдельным агентом.
Пример логики разделения:
FILES=$(git ls-files "*.ts")
echo "$FILES" | awk "NR % 4 == 0"
echo "$FILES" | awk "NR % 4 == 1"
Каждый CI-агент получает свой шард и запускает ESLint только на нём. Это обеспечивает линейное масштабирование проверки при увеличении количества агентов.
В монорепозиториях разделённый запуск становится архитектурной необходимостью. ESLint применяется к независимым пакетам, каждый из которых может иметь собственную конфигурацию.
eslint packages/ui
eslint packages/api
eslint packages/shared
Инструменты управления монорепозиториями дополнительно автоматизируют этот процесс, анализируя граф зависимостей и определяя, какие пакеты затронуты изменениями.
При этом важно учитывать, что разные пакеты могут использовать разные версии зависимостей, что влияет на поведение правил ESLint и плагинов.
Системы оркестрации задач позволяют автоматически разбивать выполнение ESLint на независимые задачи.
В Nx задачи линтинга определяются как часть графа зависимостей:
nx run-many --target=lint --all
При этом система выполняет только те задачи, которые затронуты изменениями.
В Turborepo используется кэширование на уровне задач:
turbo run lint
Каждый пакет получает собственный изолированный кеш и выполняется независимо, что фактически реализует автоматическое разделение запуска.
В локальной разработке применяется стратегия запуска ESLint только для изменённых файлов перед коммитом. Это позволяет распределить нагрузку на множество мелких запусков вместо одного большого.
npx lint-staged
Конфигурация:
{
"*.ts": "eslint",
"*.js": "eslint"
}
Lint-staged разбивает список файлов по паттернам и запускает ESLint несколько раз, изолируя группы файлов друг от друга.
При разделении запуска возникает необходимость учитывать контекст конфигурации. ESLint может вести себя по-разному в зависимости от директории выполнения:
.eslintrcparserOptionsПоэтому запуск в отдельных частях проекта часто требует явного указания working directory:
eslint --config packages/ui/.eslintrc.js packages/ui
Или через параметр --cwd, чтобы избежать конфликтов
путей и относительных импортов.
Разделение ESLint на независимые части создаёт ряд технических сложностей.
Одной из них является дублирование вычислений: одинаковые плагины и парсеры загружаются многократно в разных процессах, увеличивая общее потребление памяти.
Другой проблемой становится несогласованность правил между шардированными частями. При изменении конфигурации в одной зоне проекта возможны расхождения с другими зонами, если кеш или CI-агенты используют устаревшие данные.
Также критичным фактором становится порядок выполнения. В некоторых случаях результаты линтинга могут зависеть от порядка загрузки файлов, особенно при использовании нестандартных плагинов.
На практике используется сочетание нескольких подходов:
Такая комбинация позволяет снизить время полного линтинга с минут до секунд даже в крупных кодовых базах, сохраняя при этом полноту проверки на уровне всего проекта.