Чистим код в Angular. Готовим ESLint, codelyzer, stylelint, husky, lint-staged и Prettier

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

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


Как только начали работать в команде  —  ситуация резко меняется. Если нет договоренностей, то каждый начинает писать код в таком стиле, в каком умеет. И даже если вы все же собрались и обсудили на словах codestyle на проекте и даже записали где-то, это, скорее всего, не поможет решить проблему, и вот почему.



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


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


Подготовка


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


Большинство инструментов, которые будут рассмотрены далее, можно применить не только к Angular, но в рамках этой статьи будем использовать Angular и начнем с того, что создадим новый проект:


npm install -g @angular/cli # если у вас не установлен @angular/cli
ng new angular-linters-sample

TSLint (deprecated)


На текущий момент в проекте, который сгенерирован через Angular CLI, по умолчанию используется TSLint. Уже сейчас вам будет доступна команда npm run lint, которая запустит встроенную в CLI команду билдера ng lint, тем самым запустив проверку кода на соответствие codestyle.


Теперь давайте проверим: намеренно допустим ошибку и запустим линтер (попробуйте догадаться, какая ошибка была внесена).



TSLint: Запуск линтера в Angular-проекте


При запуске линтер нашел ошибку и даже показал ссылку на правило в официальном styleguide, который рекомендован для Angular-разработчиков.


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


Однако на странице проекта в Гитхабе можно заметить, что TSLint помечен как deprecated, так что вместо него рекомендуют использовать ESLint (о нем расскажем далее).


Codelyzer


Помимо TSLint, который, исходя из названия, работает с TypeScript, в Angular-проекте хочется иметь правила, которые относятся конкретно к Angular.


И такое решение есть  —  codelyzer, который также по умолчанию устанавливается и настраивается при генерации проекта через Angular CLI. Правила codelyzer тоже применяются при запуске команды npm run lint. Это работает за счет файла конфигурации tslint.json, в котором интеграция TSLint и codelyzer осуществляется через свойство rulesDirectory.


ESLint


Так как TSLint был объявлен как deprecated, Angular-комьюнити начало движение в сторону ESLint. Если хочется узнать подробности, то на Хабре уже была статья, где подробно поясняется, почему стоит мигрировать.


На текущий момент (версия Angular 9.0.5) официальной поддержки ESLint в Angular еще нет, по этой причине CLI генерирует проект с TSLint и codelyzer. Стоит отметить, что codelyzer не совместим с ESLint и в этом случае рекомендуют начать использовать angular-eslint: тут есть builder и в планах — реализация schematic для автоматической миграции.
Также для миграции можно использовать решение от ESLint и написать свои правила с помощью eslint-plugin-typescript.


Если вы используете Nx, то в версии 9.1 появился плагин @nrwl/linter, поддерживающий ESLint.


Еще есть вариант использовать @tinkoff/linters, которые расширяют стандартный набор дополнительными наборами правил от Tinkoff. Последняя версия поддерживает ESLint, а предпоследняя — TSLint.


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


Stylelint


А как же стили? И для стилей тоже есть решение. Встречайте  —  stylelint. Активно развивается, много чего поддерживает и в наличии множество готовых правил. Также есть песочница — там можно сформировать необходимый вам набор правил.


Устанавливаем сам stylelint, а также стандартный набор правил:


npm install stylelint stylelint-config-standard --save-dev

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


{
 "extends": "stylelint-config-standard",
 "rules": {
   "at-rule-empty-line-before": null
 }
}

Добавляем скрипт в package.json, который можно запускать вручную для проверки стилей:


"scripts": {
 ...
 "lint-css": "stylelint src/**/*.css"
 ...
}

Далее запускаем и сразу ловим ошибку, так как по умолчанию в файле app.component.css стили отсутствуют, и это подпадает под правило no-empty-source, что показано на скриншоте ниже.



Stylelint: Первый запуск линтера стилей в Angular-проекте


Husky


Запускать вручную линтер каждый раз перед коммитом довольно утомительно, да и вообще  можно запросто забыть это сделать. Чтобы делать это автоматически, существует пакет husky, который позволяет удобным образом использовать Git Hooks.
К примеру, если необходимо выполнить какую-нибудь команду до коммита, определяем соответствующее поведения для хука pre-commit.
Помимо вышеописанного хука есть возможность определить поведение для хука pre-push. Обычно не использую его, потому что запуск линтеров на pre-commit помогает делать более качественные коммиты.


Перейдем к практике.  Как и договаривались, перед каждым коммитом будет автоматически запускаться команда npm run lint.
Для этого установим husky:


npm install husky --save-dev

Определим конфигурацию в файле .huskyrc (можно хранить и в package.json, но попробуем альтернативный вариант):


{
 "hooks": {
   "pre-commit": "npm run lint"
 }
}

После чего достаточно сделать коммит и посмотреть вывод:



Husky: Вывод в терминале при коммите


Как видно из скриншота, перед созданием коммита отработала команда ng lint, которая запустилась скриптом lint, определенным в package.json.
То есть получается следующая последовательность:


Husky → pre-commit hook → npm run lint → ng lint


Если команда вернет ошибку, коммит сделать не получится, придется исправлять найденные недочеты.


Lint-staged


В проект подключен husky, разработка ведется очень активно, и линтер запускается на каждый коммит, защищая код в соответствии с codestyle.


Однако, со временем, разработчики начинают замечать, что линтер что-то долго работает и кое-кто даже стал предлагать отключить линтер (ведь все и так уже знают codestyle, зачем ждать!). Отключать линтер, конечно же, не вариант, поэтому давайте определим, в чем проблема.


А проблема в том, что линтер запускается вообще для всех файлов проекта, а не только для тех, которые были изменены в процессе разработки. Так что при запуске линтера логичным будет учитывать только измененные файлы. Кроме этого, нас интересуют только те файлы, которые планируются добавить в коммит, а конкретно  —  файлы в статусе staged (подробнее про статусы файлов в git можно почитать здесь).


Переходим к практике.
Установим lint-staged:


npm install lint-staged --save-dev

Определим конфигурацию в файле .lintstagedrc (другие варианты описания конфигурации можно найти здесь). Далее настроим, что следует запускать скрипт линтера на файлы с расширением js и ts, а также еще один — на файлы с расширением css:


{
 "*.{js,ts}": "npm run lint",
 "*.css": "npm run lint-css"
}

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


{
 "hooks": {
   "pre-commit": "lint-staged"
 }
}

Теперь последовательность выглядит так:


Husky → pre-commit hook → lint-staged
→ tslint
→ stylelint


Prettier


Prettier отлично дополняет то, о чем было написано ранее.
Но зачем вообще его использовать, если и так уже есть столько замечательных инструментов?


Из плюсов:


  • Prettier может автоматически исправить любой код (auto fix). Да, тот же TSLint тоже умеет автоматически исправлять код, но не весь. Обратите внимание на пометку Has Fixer в его правилах. То же самое касается и stylelint: он умеет исправлять стили, где это возможно, через использование экспериментального флага --fix. В prettier есть соглашения по умолчанию, так что ваш код будет приведен к единому стилю.
  • Выполняет более “умное” автоисправление. Подробнее можно прочитать здесь.
  • Умеет интегрироваться с некоторыми линтерами, в том числе с ESLint, TSLint, stylelint.
  • Умеет интегрироваться с различными IDE.
  • Поддерживает множество форматов.
  • Расширяется за счет плагинов.

Из минусов:


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

В целом, плюсов больше чем минусов и prettier неплохо выполняет роль связующего звена, объединяя и дополняя вышеперечисленные инструменты. Также стоит отметить, что код, форматированный в одном стиле, удобно читать — уже не ожидаешь каких-то “сюрпризов” при проведении ревью. Поэтому, если в вашей команде вы все еще не используете этот инструмент, обратите на него внимание — возможно, это то, что вам нужно.


Перейдем к практике.
Устанавливаем Prettier и необходимые наборы правил для интеграции с TSLint и stylelint:


npm install prettier tslint-config-prettier tslint-plugin-prettier stylelint-config-prettier stylelint-prettier --save-dev

Добавляем интеграцию для TSLint через файл tslint.json:


{
 "extends": [
   "tslint-config-prettier",
   "tslint-plugin-prettier",
   "codelyzer"
 ],
 "rules": {
   "prettier": true
 }
}

Здесь важно уточнить: поскольку ESLint/TSLint и Prettier частично решают схожие задачи, они могут конфликтовать между собой.
Эти конфиги нужны для устранения конфликта, а именно — для делегирования форматирования полностью в руки Prettier.
Далее добавляем интеграцию для stylelint в файл .stylelintrc:


{
 "extends": ["stylelint-prettier/recommended"]
}

Описываем конфигурацию для Prettier в .prettierrc:


{
 "trailingComma": "es5",
 "tabWidth": 2,
 "semi": true,
 "singleQuote": true
}

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


npx tslint-config-prettier-check ./tslint.json
npx stylelint-config-prettier-check

Также добавим команду для запуска prettier в package.json:


"scripts": {
 ...
 "prettier": "prettier --write src/**/*.{js,ts,css}",
 ...
}

Не забудем обновить конфиг lint-staged, чтобы Prettier запускался автоматически перед коммитом:


{
 "*.{js,json,md,html}": [
   "prettier --write"
 ],
 "*.css": [
   "prettier --write",
   "npm run lint-css"
 ],
 "*.ts": [
   "prettier --write",
   "npm run lint"
 ]
}

Так как Prettier только что добавлен, необходимо запустить его:


npm run prettier

Итоги


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


Если вы работаете в команде, ведете разработку на Angular, но еще не настроили линтеры — самое время сделать это и эта статья точно для вас. Если же вы не используете Angular, то с небольшими доработками сможете адаптировать все вышеописанное под свой проект.


Код решения, рассмотренного в рамках этой статьи, можно найти в этом репозитории.


Также обратите внимание на @tinkoff/linters, который представляет собой готовое решение с нашими дополнительными наборами правил.
И для быстрого старта рекомендую посмотреть на вот этот репозиторий, где вы найдете готовую конфигурацию, в том числе и по линтерам.

Источник: https://habr.com/ru/company/tinkoff/blog/497282/


Интересные статьи

Интересные статьи

Компании переполнили рынок товаров и услуг предложениями. Разнообразие наблюдается не только в офлайне, но и в интернете. Достаточно вбить в поисковик любой запрос, чтобы получить подтверждение насыще...
Приветствую вас (лично вас, а не всех кто это читает)! Сегодня мы: Создадим приложение (навык) Алисы с использованием нового (октябрь 2019) сервиса Yandex Cloud Functions. Настроим н...
В 2019 году люди знакомятся с брендом, выбирают и, что самое главное, ПОКУПАЮТ через интернет. Сегодня практически у любого бизнеса есть свой сайт — от личных блогов, зарабатывающих на рекламе, до инт...
Тема статьи навеяна результатами наблюдений за методикой создания шаблонов различными разработчиками, чьи проекты попадали мне на поддержку. Порой разобраться в, казалось бы, такой простой сущности ка...
Как обновить ядро 1С-Битрикс без единой секунды простоя и с гарантией работоспособности платформы? Если вы не можете закрыть сайт на техобслуживание, и не хотите экстренно разворачивать сайт из бэкапа...