Pull to refresh

Переносим Angular проект на ESLint, с Prettier, Husky и lint-staged

Reading time 8 min
Views 30K
Привет, Хабр! Меня зовут Богдан, я работаю в ПИК Digital Front-End тимлидом. Большую часть проектов мы разрабатываем на Angular и недавно я решил пересмотреть наши стайл гайды, а также добавить новые инструменты для более удобной работы.

В качестве линтера я решил использовать ESLint, так как в скором времени на него планируют перевести Angular. И в этой статье я хочу поделиться инструкцией по переходу с TSLint на ESLint, а заодно рассказать, как запускать Prettier из ESLint, как добавить правила стайл гайда AirBnB, и как сделать линтинг удобным и незаметным с помощью настройки VS Code и Git хуков.

Prettier & ESLint


ESLint — это инструмент для статического анализа кода, правила в нём делятся на две группы:

  • Форматирование — для приведения кода в один вид: длина строк, запятые, точки с запятой и тд.
  • Качество кода — поиск проблемных шаблонов кода: ненужный код, ошибки.

Prettier — это инструмент автоматического форматирования кода.

Вопрос, который меня интересовал: зачем использовать Prettier, если ESLint тоже умеет форматировать код?

Ответ простой — Prettier форматирует код намного лучше: убирает всё форматирование и полностью переписывает код в едином стиле. Это позволяет разработчикам забыть о форматировании кода и не тратить время на обсуждение стиля кода на ревью. Например, у нас есть длинная строчка кода:

image

Если мы попробуем изменить форматирование через ESLint, он просто выдаст нам ошибку:

eslint example.ts --fix

output:
error    This line has a length of 97. Maximum allowed is 80

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

Если же мы сохраним или форматируем файл с Prettier, то строка примет вид:

image

Prettier обеспечивает единый стиль по всей кодовой базе. Поэтому его можно и нужно использовать вместе с ESLint, но необходимо настроить их так, чтобы они друг другу не мешали.

Настройка ESLint


Суть линтинга с помощью ESLint заключается в парсерах, которые трансформируют код в AST (Abstract Syntax Tree) для дальнейшей программной обработки, и плагинах, которые содержат правила, например, рекомендуемые правила для линтинга TypeScript или правила код гайда AirBnB.

Установка


Для миграции Angular приложения на ESLint нам потребуются следующие зависимости:

  • eslint — сам линтер,
  • @angular-eslint/builder — Angular CLI Builder для запуска ESLint для приложений на Angular с помощью стандартной команды ng lint,
  • @angular-eslint/eslint-plugin — плагин, содержащий правила для линтинга Angular,
  • @angular-eslint/template-parser — парсер, который с помощью angular/compiler делает возможным написание правил для линтинга Angular шаблонов,
  • @angular-eslint/eslint-plugin-template — плагин, который при использовании вместе с @angular-eslint/template-parser, запускает правила для линтинга Angular шаблонов,
  • @typescript-eslint/parser — плагин для парсинга TypeScript кода,
  • @typescript-eslint/eslint-plugin — плагин, который запускает правила для линтинга TypeScript.

Для их установки достаточно запустить команду:

ng add @angular-eslint/schematics

На момент написания статьи в typescript-eslint и angular-eslint реализованы не все эквиваленты для правил из стандартной конфигурации Сodelyzer для TSLint, но большая часть уже есть. Отслеживать актуальное состояние переноса правил из TSLint в ESLint вы можете в монорепозиториях Angular ESLint и TypeScript ESLint.

Настройка конфига


Всё, что нам надо для линтинга Angular приложения, мы установили. Теперь перейдём к настройке ESLint. Давайте создадим файл .eslintrc.js и добавим рекомендованные настройки для Angular ESLint:

module.exports = {
  root: true,
  overrides: [
    {
      files: ["*.ts"],
      parserOptions: {
        project: [
          "tsconfig.*?.json",
          "e2e/tsconfig.json"
        ],
        createDefaultProgram: true
      },
      extends: ["plugin:@angular-eslint/recommended"],
      rules: {
        ...
      }
    },
    {
      files: ["*.component.html"],
      extends: ["plugin:@angular-eslint/template/recommended"],
      rules: {
        "max-len": ["error", { "code": 140 }]
      }
    },
    {
      files: ["*.component.ts"],
      extends: ["plugin:@angular-eslint/template/process-inline-templates"]
    }
  ]
}

Конфиги можно описывать в разных форматах: JavaScript, JSON или YAML file. В JavaScript можно оставлять комментарии.

«plugin:@angular-eslint/recommended» содержит настройки сразу для 3 плагинов: "@typescript-eslint/eslint-plugin", "@angular-eslint/eslint-plugin" и "@angular-eslint/eslint-plugin-template". Прочитать, какие правила он задаёт, можно тут.

Обновление команды ng lint


Также в конфигурации angular.json нужно обновить команду ng lint на запуск @angular-eslint/builder:

"lint": {
  "builder": "@angular-eslint/builder:lint",
  "options": {
    "lintFilePatterns": [
      "src/**/*.ts",
      "src/**/*.component.html"
    ]
  }
},

Базовая настройка ESLint готова, теперь запустить ESLint можно стандартной командой ng lint.

Установка дополнительных плагинов


Чтобы установить плагин для ESLint, например, для линтинга unit-тестов в Angular, надо скачать и добавить в настройки плагин Jasmine:

npm install eslint-plugin-jasmine --save-dev

И добавить в свойство «overrides» новый блок настроек для файлов с расширением *.spec.ts:

overrides: [
  ...,
  {
    files: ['src/**/*.spec.ts', 'src/**/*.d.ts'],
    parserOptions: {
      project: './src/tsconfig.spec.json',
    },
    // Правила для линтера
    extends: ['plugin:jasmine/recommended'],
    // Плагин для запуска правил
    plugins: ['jasmine'],
    env: { jasmine: true },
    // Отключим правило 'no-unused-vars'
    rules: {
      '@typescript-eslint/no-unused-vars': 'off',
    },
  }
],

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

Добавляем правила стайл гайдов


Чтобы достичь большей консистентности кодовой базы, можно выбрать и добавить в конфиг ESLint правила одного из популярных стайл гайдов:

  • AirBnB: самый популярный и строгий из этих трёх, обязательные замыкающие запятые и точки с запятыми.
  • Google: похож на AirBnB в плане форматирования, но менее строгий, обязательные комментарии JSDoc.
  • StandartJS: запрещает использовать замыкающие запятые и точки с запятыми.

Выбирайте стайл гайд, который больше подходит вашей команде. Можете поочередно попробовать все стайл гайды на каком-нибудь большом проекте, посмотреть, какие ошибки выдаёт линтер и на основании этого сделать выбор.

Выбирайте реализацию стайл гайда на TypeScript, потому что правила для JavaScript могут неправильно отрабатывать на TypeScript.

В качестве примера, добавим в наш конфиг ESLint правила стайл гайда AirBnB. Для этого установим конфиг с правилами AirBnB для TypeScript и плагин с правилами для работы с синтаксисом import/export:

npm install eslint-plugin-import eslint-config-airbnb-typescript --save-dev


А также в свойстве «overrides» добавим правила стайл гайда AirBnB в блок с правилами для файлов с расширением "*.ts":

module.exports = {
  ...,
  overrides: [
    {
      files: ["*.ts"],
      parserOptions: {
        project: [
          "tsconfig.*?.json",
          "e2e/tsconfig.json"
        ],
        createDefaultProgram: true
      },
      extends: [
        "plugin:@angular-eslint/recommended",
        // Стайл гайд AirBnB
        'airbnb-typescript/base'
      ],
      rules: {
        ...
      }
    },
    ...
  ]
}

Чтобы добавить другой стайл гайд, нужно установить набор правил для TypeScript, создать новый блок правил в «overrides» с правилами стайл гайда и указать необходимый для их работы парсер.

Кастомизация правил


Если вы хотите отключить или переопределить какие-то правила стайл гайда, то это можно сделать в свойстве «rules»:

module.exports = {
  ...,
  overrides: [
    {
      files: ["*.ts"],
      parserOptions: {
        project: [
          "tsconfig.*?.json",
          "e2e/tsconfig.json"
        ],
        createDefaultProgram: true
      },
      extends: [
        "plugin:@angular-eslint/recommended",
        // Стайл гайд AirBnB
        'airbnb-typescript/base'
      ],
      rules: {
        // Кастомные правила
        'import/no-unresolved': 'off',
        'import/prefer-default-export': 'off',
        'class-methods-use-this': 'off',
        'lines-between-class-members': 'off',
        '@typescript-eslint/unbound-method': [
          'error',
          {
            ignoreStatic: true,
          }
        ]
      }
    },
    ...
  ]
}


Настройка Prettier


Чтобы добавить Prettier в нашу конфигурацию, нам надо установить сам Prettier, плагин с правилами Prettier, а также конфиг, который отключит все правила, которые могут конфликтовать с Prettier:

npm i prettier eslint-config-prettier eslint-plugin-prettier --save-dev

В «overrides» в блоке с правилами файлов с расширением *.ts в свойство «extends» в самый низ добавьте правила и настройки Prettier:

module.exports = {
  ...,
  overrides: [
    {
      files: ["*.ts"],
      parserOptions: {
        project: [
          "tsconfig.*?.json",
          "e2e/tsconfig.json"
        ],
        createDefaultProgram: true
      },
      extends: [
        "plugin:@angular-eslint/recommended",
        // Стайл гайд AirBnB
	'airbnb-typescript/base',
	// Настройки для Prettier
        'prettier/@typescript-eslint',
        'plugin:prettier/recommended'
      ],
      rules: {
        ...
      }
    },
    ...
  ]
}

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

`prettier/@typescript-eslint` отключает правила `@typescript-eslint`, которые могут конфликтовать с Prettier, а `plugin:prettier/recommended` делает три вещи:

  • включает eslint-plugin-prettier,
  • выводит в консоль ошибки правил prettier/prettier как  «error»,
  • добавляет правила форматирования Prettier eslint-config-prettier.

Конфиг для Prettier:


Prettier умеет форматировать код без всяких настроек, но для соответствия стайл гайду AirBnB необходимо добавить некоторые настройки. Создайте файл .prettierrc.js в корне приложения:

module.exports = {
  trailingComma: "all",
  tabWidth: 2,
  semi: true,
  singleQuote: true,
  bracketSpacing: true,
  printWidth: 100
};

Эти настройки будут использоваться как ESLint, так и Prettier, если вы будете использовать его для форматирования файлов в VS Code или с помощью команды:

prettier "--write ."

Настройка VS Code


VS Code может подсвечивать и исправлять при сохранении ошибки найденные ESLint. Для этого надо скачать плагин ESLint для VS Code и создать файл внутри проекта с настройками для рабочей области .vscode/settings.json:

  "eslint.validate": [ "javascript", "typescript", "html"],

  "eslint.options": {
    "extensions": [".js", ".ts", "html"]
  },

  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
  },

Здесь мы настраиваем ESLint, чтобы он подчёркивал и исправлял ошибки при сохранения файлов с расширениями .js, .ts и .html.

А чтобы форматировать документ комбинацией клавиш «shift+option+F» или «shift+alt+F» скачайте плагин Prettier для VS Code, и установите его как форматировщик по умолчанию.

Настройка Git хуков


Git хуки — это скрипты, которые Git вызывает при определённых событиях: commit, push, recieve.

С помощью них, мы можем запускать линтинг кода при создании коммита, чтобы в пул реквесты попадало меньше ошибок. Для более удобной работы с Git хуками установим Husky, а чтобы проверять только тот код, который добавлен в коммит (это полезно в больших проектах, где линтинг занимает много времени) lint-staged:

npm i husky lint-staged --save-dev

Добавим настройки для этих плагинов в package.json:

"scripts": {
  ...
},
"husky": {
  "hooks": {
    "pre-commit": "lint-staged --relative"
  }
},
"lint-staged": {
  "*.{js,ts}": [
     "eslint --fix"
  ]
},

lint-staged передаёт в вызываемую команду массив изменённых файлов. Команда ng lint не умеет принимать массив файлов, и для её использования надо писать дополнительный скрипт-обработчик. А можно просто вызвать ESLint, как в этом примере. Такое решение можно использовать для прекоммитов, а ng lint запускать для линтинга всего проекта, например в CI пайплайне.

Выводы


В будущих версиях Angular ESLint с базовыми правилами будет из коробки. Сейчас процесс настройки ESLint требует некоторых дополнительных действий, в ESLint нет эквивалентов для некоторых правил из TSLint, и Angular ESLint ещё находится в alpha-версии. Поэтому переходить сейчас на ESLint или нет — решать вам.

Однако код гайды, дополнительные правила, Prettier, Husky и lint-staged вам придётся настраивать самостоятельно. Надеюсь эта статья помогла вам разобраться как все эти вещи работают вместе.

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

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

Пример реализации можно посмотреть на Github.

Если вы нашли ошибку в конфиге, или у вас есть дополнения — пишите!

Ссылки


Tags:
Hubs:
+10
Comments 5
Comments Comments 5

Articles