Git hooks представляют собой механизмы, позволяющие выполнять
произвольные скрипты на определённых этапах работы системы контроля
версий. Наиболее часто они применяются для автоматизации проверки
качества кода перед фиксацией изменений. Одним из ключевых этапов
становится pre-commit, на котором выполняется линтинг с
использованием ESLint.
Husky выступает надстройкой над Git hooks, упрощающей их настройку и
версионирование внутри репозитория. Вместо ручного создания скриптов в
.git/hooks, используется декларативная конфигурация внутри
проекта, что делает процесс предсказуемым и переносимым между
окружениями.
Базовая интеграция начинается с установки пакета:
npm install husky --save-dev
Инициализация структуры hooks выполняется через команду:
npx husky init
После выполнения создаётся директория .husky/ и базовый
hook pre-commit. Также в package.json
добавляется скрипт подготовки:
{
"scripts": {
"prepare": "husky"
}
}
Скрипт prepare обеспечивает автоматическую активацию
hooks после установки зависимостей.
После инициализации формируется каталог:
.husky/
pre-commit
Каждый файл внутри соответствует отдельному Git hook. Файл представляет собой shell-скрипт:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
Эта строка подключает внутреннюю инфраструктуру Husky и обеспечивает корректное выполнение команд в контексте Git.
Простейшая интеграция ESLint в Husky заключается в запуске проверки всего проекта:
npx eslint .
Однако такой подход неэффективен для больших кодовых баз, так как проверяются все файлы независимо от изменений.
Более оптимальный вариант — анализ только staged-файлов.
Для выборочной проверки изменённых файлов используется
lint-staged:
npm install lint-staged --save-dev
Конфигурация добавляется в package.json:
{
"lint-staged": {
"*.js": "eslint"
}
}
После этого pre-commit hook изменяется:
npx lint-staged
Механизм работы основан на следующих этапах:
*.js,
*.ts)Такой подход существенно сокращает время проверки и снижает нагрузку на систему.
Наиболее распространённая схема конфигурации:
npm install husky lint-staged eslint --save-dev
npx lint-staged
{
"scripts": {
"prepare": "husky"
},
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
}
}
Использование --fix позволяет автоматически исправлять
часть проблем до завершения коммита.
Для ускорения повторных проверок применяется кеширование:
npx eslint . --cache
Файл кеша .eslintcache сохраняет результаты предыдущих
проверок и позволяет пропускать неизменённые участки кода.
При использовании с lint-staged кеширование становится менее критичным, однако остаётся полезным при дополнительных ручных запусках.
В TypeScript окружении добавляется расширенная конфигурация:
{
"lint-staged": {
"*.{ts,tsx}": "eslint"
}
}
Дополнительно ESLint должен быть настроен с соответствующими парсерами:
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"]
}
Помимо pre-commit, Husky позволяет использовать
pre-push для более тяжёлых проверок:
npx eslint .
npm run test
Такой подход разделяет уровни контроля:
pre-commit — быстрый линтинг изменённых файловpre-push — полная проверка проекта и тестированиеВ монорепозиториях структура усложняется, и линтинг часто ограничивается конкретными пакетами.
Пример конфигурации lint-staged:
{
"lint-staged": {
"packages/*/src/**/*.{js,ts}": "eslint"
}
}
Husky при этом остаётся единым уровнем оркестрации, не зависящим от структуры репозитория.
В некоторых CI системах Git hooks не активируются автоматически. Решением становится явный запуск ESLint:
npx eslint .
При совместном использовании Prettier и ESLint порядок выполнения становится критичным:
{
"lint-staged": {
"*.{js,ts}": [
"eslint --fix",
"prettier --write"
]
}
}
Причины замедления:
Комбинация Husky и ESLint формирует слой локального контроля качества кода, встроенный непосредственно в Git workflow. Это позволяет перенести часть ответственности за корректность кода с CI-систем на локальное окружение разработчика, уменьшая количество дефектов, попадающих в удалённые ветки.
Структурно процесс выглядит как последовательность:
git commit
↓
Husky pre-commit hook
↓
lint-staged
↓
ESLint (staged files)
↓
разрешение или блокировка commit