Создание хука Git pre-commit для автопроверки и исправления кода JavaScript и TypeScript

Важно выдерживать единый стиль написания кода в проекте, особенно если он выполнен на JavaScript и TypeScript. Это связано с тем, что JavaScript  —  очень гибкий язык, а TypeScript, хотя и менее гибок в синтаксисе, все же достаточно гибок в форматировании.

Представьте, что в одной части кода используется 2 пробела для отступа, а в другой  —  4. Вы можете подумать, что подобный линтинг носит лишь косметический характер. Тем не менее линтеры могут также проверять синтаксис и помогать улучшать качество кода в соответствии с общепринятыми отраслевыми стандартами.

Проверять качество кода и стили его написания вручную довольно обременительно. К счастью, с помощью Git-хуков это можно сделать автоматически, а автор кода не сможет создавать коммиты, если линтинг не был пройден.

Для проектов JavaScript и TypeScript разработано несколько хорошо зарекомендовавших себя пакетов, которые можно использовать для линтинга и управления Git-хуками. В этой статье речь пойдет о том, как создать хук Git pre-commit для проверки кода JavaScript и TypeScript с помощью ESLint, Prettier, lint-staged и Husky.


Установка и настройка ESLint

Настроить ESLint сложнее, чем пакеты, упомянутые выше.

Чтобы сделать это быстро, выполните команду для установки и конфигурации ESLint с помощью мастера:

$ npm init @eslint/config

Выберите параметры, которые лучше всего подходят для проекта, и файл package.json будет обновлен соответствующим образом. Автоматически создастся файл .eslintrc.js на основе сделанного вами выбора. Вам потребуется внести в него некоторые изменения, чтобы он соответствовал вашим требованиям. В этой статье будет использоваться этот файл .eslintrc.js.


Установка и настройка Prettier

Если проект содержит только код JavaScript и TypeScript, анализатора ESLint обычно достаточно, поскольку он может выполнять проверку синтаксиса и формата. Однако если в проекте есть также файлы HTML и CSS, потребуется установить Prettier  —  специальный инструмент для форматирования кода. Кроме того, поскольку Prettier доступен в большинстве IDE (например, VS Code), для автоматического форматирования кода удобнее использовать Prettier, чем ESLint.

Выполните следующую команду для установки Prettier:

$ npm install prettier eslint-plugin-prettier eslint-config-prettier --save-dev

Обратите внимание: кроме пакета Prettier также устанавливаются два пакета для ESLint. Таким образом, Prettier может работать совместно с ESLint, поскольку эти инструменты обладают схожими функциями в плане форматирования кода.

В большинстве случаев достаточно оставить настройки Prettier по умолчанию. Однако, если нужны особые стили, добавьте их в файл с именем .prettierrc.json в корневой папке проекта. Можно также непосредственно добавить опции в командную строку, если их не слишком много. Перейдите по этой ссылке, чтобы ознакомиться со всеми опциями форматирования для Prettier.


Установка и настройка lint-staged

По умолчанию линтеры, такие как ESLint и Prettier, проверяют все файлы в проекте. Однако это крайне неэффективно. При создании коммита нужно, чтобы линтеры проверяли только те файлы, которые были изменены или индексированы. Файл индексируется, когда вы выполняете git add, чтобы добавить его в область индексирования. Именно здесь поможет пакет lint-staged, который позволяет линтить только индексированные файлы.

Чтобы установить lint-staged, выполните команду:

$ npm install --save-dev lint-staged

Чтобы настроить lint-staged, можно создать либо новый объект под названием lint-staged в package.json, либо новый файл .lintstagedrc.json в папке проекта. Последний вариант предпочтительней, если у вас сложные настройки. Однако здесь будет использовать первый вариант, поскольку в данном случае настроек немного:

"lint-staged": {
"*.ts": "npx tsc --noEmit",
"*.{js,jsx,ts,tsx}": "npx eslint",
"*.{js,jsx,ts,tsx,html,css}": "npx prettier --check"
}

Мы определяем три задачи для lint-staged. По умолчанию lint-staged будет выполнять их параллельно. Поэтому потребуется особое внимание, если один и тот же файл изменяется разными задачами. Результат может быть непредсказуемым из-за эффекта гонки. Необходимо убедиться в том, что настройки разных линтеров не конфликтуют. При необходимости можно отключить параллелизм, указав в командной строке для lint-staged параметр --concurrent false:

# Запустить задачи параллельно:
$ npx lint-staged
# Запустить задачи последовательно:
$ npx lint-staged --concurrent false

Обратите внимание, что при сбое одной задачи все остальные будут пропущены или завершены.


Установка и настройка Husky

Выше мы запустили lint-staged вручную с помощью npx. Если нужно обеспечить линтинг до создания коммита, следует запустить lint-staged в Git-хуке pre-commit. Этот хук является просто запускаемым скриптом, который выполняется перед созданием коммита. В него можно поместить любой код, и код линтинга  —  идеальный пример для использования.

Вот три способа добавить код линтинга для lint-staged в хук pre-commit.

  • Создать хук pre-commit вручную и добавить в него приведенную выше команду для запуска lint-staged. Это немного громоздко, поскольку придется вручную скопировать и перенести хук pre-commit в папку .git/hooks/.
  • Использовать программу установки pre-commit. Это удобно, если есть только хуки pre-commit, и нет других типов Git-хуков, таких как commit-msg и pre-push.
  • Использовать Husky! Husky поддерживает все Git-хуки. В настоящее время это самый популярный способ управления Git-хуками в проекте JavaScript/TypeScript, и мы выберем именно этот вариант.

Чтобы установить Husky и инициализировать проект с его помощью, выполните следующую команду:

$ npx husky-init && npm install

В папке проекта будет создана папка с именем .husky, которая включает в себя специальную папку, названную знаком подчеркивания _, и шаблон хука pre-commit. Кроме того, в package.json добавляется новый скрипт prepare, который запускает команду husky install. Скрипт prepare создаст папку .husky до упаковки пакета.

Добавим команду для запуска lint-staged в хук pre-commit в папке .husky:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

Этот хук pre-commit будет вызываться перед созданием коммита в текущем проекте. Нужно добавить его и в папку проекта, чтобы он сохранялся в проекте при его переносе в удаленный репозиторий. Не стоит переживать: он не будет перезаписан командой husky install.

$ git add package.json
$ git add package-lock.json
$ git add .husky/pre-commit
$ git commit

Теперь, когда вы попытаетесь создать коммит для файла, соответствующего шаблонам, определенным lint-staged, как показано выше, произойдет автоматический вызов хука pre-commit. Будут проверены только индексированные файлы:

[lynn@js-ts-git-hooks]$git add src/example.ts 
[lynn@js-ts-git-hooks]$git commit
✔ Preparing lint-staged...
❯ Running tasks for staged files...
❯ package.json — 1 file
❯ *.ts — 1 file
✖ npx tsc --noEmit [KILLED]
❯ *.{js,jsx,ts,tsx} — 1 file
✖ npx eslint [KILLED]
❯ *.{js,jsx,ts,tsx,html,css} — 1 file
✖ npx prettier --check [FAILED]
↓ Skipped because of errors from tasks. [SKIPPED]
✔ Reverting to original state because of errors...
✔ Cleaning up temporary files...

✖ npx prettier --check:
[warn] src/example.ts
[warn] Code style issues found in the above file. Forgot to run Prettier?
Checking formatting...

✖ npx eslint failed without output (KILLED).

✖ npx tsc --noEmit failed without output (KILLED).
husky - pre-commit hook exited with code 1 (error)

Мы успешно настроили хук Git pre-commit, который помогает поддерживать стандарты написания и форматирования кода. Теперь не получится добавить коммит с файлом, нарушающим правила, определенные линтерами. Это делает кодовую базу менее подверженной ошибкам, более простой в обслуживании и более приятной для чтения.

Весь код, представленный в этой статье, можно найти в этом репозитории.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Lynn Kwong: Create a Pre-commit Git Hook to Check and Fix Your JavaScript/TypeScript Code Automatically

Предыдущая статьяКак создать компонент Toast в SwiftUI
Следующая статьяРазведочный анализ данных в одной строке кода