Я решил написать эту статью, чтобы подвести итоги моей борьбы. Мы начали новый проект в компании, создали Prettier, ESLint и в какой-то момент добавили Typescript. К концу был создан Typescript. CI выполнял линтинг, хуки коммитов также линтинги, VSCode исправлял код и т. Д. (Это то, что я думал).
В какой-то момент я играл с проектом и понял, что некоторые файлы были предупреждены моим редактор, но не при запуске линтера (npm run lint в моем случае). Меня сработало. Мне трудно принять, что что-то работает, но я не могу понять, если это не внешний инструмент, который мне не нужно было настраивать самостоятельно, но здесь этого не было.

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

Красивее

Первый инструмент, который я хочу изучить, - Prettier. Я бы предоставил вам узнать больше о том, что это такое, но, вкратце, это средство форматирования кода. Что это означает? Это означает, что он будет поддерживать согласованность вашей кодовой базы (с точки зрения стиля кодирования). Вы используете ;? Если да, то он, например, гарантирует, что он есть во всех ваших файлах. Мне это нравится по двум причинам: нам почти не приходится обсуждать форматирование кода, и легко привлечь новых членов в команду.

На момент написания Prettier находится в версии 2.4.1, поэтому имейте в виду, что в будущих версиях кое-что может измениться (особенно форматирование).

Как настроить Prettier?

Я буду считать, что у вас уже есть проект, поэтому вкратце вам нужно его установить:

npm i prettier #--save-dev and --save-exact are recommended

Прямо сейчас вы можете начать использовать Prettier. Конфигурация не требуется (если она вам не нужна). Вы можете запустить его для своей кодовой базы с помощью:

npx prettier .

. в конце означает прохождение всей вашей кодовой базы. При желании вы можете работать с конкретным файлом или шаблоном.
Эта команда распечатает файлы в отформатированном виде, ничего особенного. Более полезная команда появляется, когда вы добавляете флаг --write. Вместо того, чтобы печатать форматированный код, он будет записывать в исходный файл.

Давайте создадим файл с именем index.js со следующим кодом:

// index.js
const a = 1

Если мы запустим npx prettier index.js, результат будет:

const a = 1;

Он автоматически добавляет нам ;, но не сохраняется в файле. Если мы запустим npx prettier index.js --write, файл изменится, и к нему будет добавлен ;.

Круто, это самая простая настройка Prettier. Правила по умолчанию задокументированы на их веб-сайте и могут быть изменены (немного). Мы рассмотрим это дальше, но прежде, чем я хочу упомянуть еще один флаг: --check.

Флаг --check, npx prettier index.js --check, полезен, если вы просто хотите проверить, соответствует ли файл (или кодовая база с .) Prettier. Это полезно для CI и хуков git, например, если вы просто хотите предупредить пользователя (вы также можете включить --write в этих сценариях).

Если мы снова рассмотрим следующий код:

// index.js
const a = 1

И запускаем npx prettier index.js --check, получаем следующий результат:

Checking formatting...
[warn] index.js
[warn] Code style issues found in the above file(s). Forgot to run Prettier?

Более красивая конфигурация

Вы можете настроить Prettier в некоторой степени. Сделать это можно через CLI или через конфигурационный файл, что более адекватно. Файл конфигурации может иметь множество форматов, поэтому вы можете выбрать тот, который вам больше всего подходит.

Добавьте файл конфигурации в корень вашего проекта (у вас может быть конфигурация / папка, но я бы оставил это на ваше усмотрение, чтобы изучить этот путь) и начните добавлять к нему правила:

// .prettierrc
{
  "semi": false
}

С этим файлом конфигурации и следующим кодом запуск --check снова будет успешным:

// index.js
const a = 1

npx prettier index.js --check:

Checking formatting...
All matched files use Prettier code style!

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

ESLint

ESLint существует уже давно. Короче говоря, он делает немного больше, чем Prettier, поскольку он анализирует ваш код, чтобы найти проблемы (или шаблоны, которые вам не нужны, например, переменные, которые не используются, должны быть удалены). Опять же, я предлагаю вам прочитать документацию ESLint, если вы хотите углубиться в тему. Мне нравится ESLint по той простой причине, что он помогает мне находить проблемы и настраивать некоторые шаблоны в проекте (это может быть полезно при адаптации новых людей). Он также чрезвычайно расширяем, если вам интересно.

На момент написания этой статьи ESLint находится в версии 7.32.0, поэтому имейте в виду, что в будущих версиях все может измениться (особенно форматирование). Версия 8 в настоящее время находится в стадии бета-тестирования.

Как настроить ESLint?

Короче говоря, очень похоже на Prettier, но вам нужен файл конфигурации. Я буду считать, что у вас уже есть проект, поэтому, вкратце, вам нужно его установить:

npm i eslint #--save-dev is recommended

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

npx eslint --init

Но начнем с пустого файла конфигурации, достаточно запустить ESLint:

// .eslintrc.js
module.exports = {
};

Теперь мы можем запустить его, как и Prettier:

npx eslint .

Здесь следует отметить одну вещь: ESLint работает только с .js файлами (по умолчанию).

Давайте рассмотрим тот же пример, что и раньше:

// index.js
const a = 1

npx eslint index.js и получаем:

1:1  error  Parsing error: The keyword 'const' is reserved
✖ 1 problem (1 error, 0 warnings)

Это просто проблема конфигурации ESLint по умолчанию. По умолчанию он рассматривает ES5, поэтому const пока не разрешен, и некоторые старые настройки могут иметь смысл для вашего проекта, но не в целом.

Мы можем часами настраивать ESLint, но в целом мы получаем значение по умолчанию из руководства по стилю (например, AirBnB) и применяем его к нашему проекту. Если вы используете команду init, вы можете это сделать.

Давайте установим Airbnb ESLint configuration, для этого также необходимо установить eslint-plugin-import (согласно документации), поэтому:

npm i eslint-config-airbnb-base eslint-plugin-import # --save-dev is recommended

Затем мы расширяем его в нашей конфигурации, чтобы он выглядел так:

module.exports = {
  extends: [
    'eslint-config-airbnb-base', // or `airbnb-base`, you can omit `eslint-config-`
  ]
};

Запустив npx eslint index.js снова, мы получим:

1:7   error  'a' is assigned a value but never used  no-unused-vars
1:12  error  Missing semicolon                       semi
✖ 2 problems (2 errors, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

Прохладный! Теперь мы получаем ошибки, определенные руководством AirBnB. Мы можем использовать --fixoption, который работает аналогично --write от Prettier, если мы хотим исправить ошибки, когда это возможно.

ESLint позволяет вам широко настраивать его, если хотите. Здесь это выходит за рамки, и я предоставлю вам возможность изучить и поиграть с ним: https://eslint.org/docs/user-guide/configuring/

Prettier + ESLint

В Интернете есть множество руководств о том, как подключить и то, и другое. Я хочу использовать другой подход и попытаться рассуждать о каждом инструменте и о том, как они связаны.

Я предполагаю, что у нас есть следующая конфигурация Prettier:

// .prettierrc
{
  "semi": false
}

Я предполагаю, что у нас есть следующая конфигурация ESLint:

// .eslintrc.js
module.exports = {
  extends: [
    'eslint-config-airbnb-base',
  ]
};

Я предполагаю, что следующий сценарий запускает оба инструмента:

// index.js
const a = 1
module.exports = { a }

Если запустить проверку Prettier, мы получим:

Checking formatting...
All matched files use Prettier code style!

Прохладный! Если мы запустим ESLint, мы получим:

1:12  error  Missing semicolon  semi
3:23  error  Missing semicolon  semi
✖ 2 problems (2 errors, 0 warnings)
  2 errors and 0 warnings potentially fixable with the `--fix` option.

Не так уж и круто! Запуск ESLint с --fix устранит эти проблемы. Теперь, если мы снова запустим Prettier, мы получим:

Checking formatting...
[warn] index.js
[warn] Code style issues found in the above file(s). Forgot to run Prettier?

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

Prettier предоставляет два пакета, которые интегрируются с ESLint.

Пойдем шаг за шагом. Сначала давайте установим eslint-config-prettier:

npm i eslint-config-prettier # --save-dev recommended

Наш новый .eslintrc.js будет выглядеть так:

module.exports = {
  extends: [
    'eslint-config-airbnb-base',
    'eslint-config-prettier',
  ]
};

Рассматривая файл ниже, снова:

const a = 1
module.exports = { a }

Это был допустимый файл для Prettier, но недопустимый для ESLint. Используя новую конфигурацию, она становится действительной, поскольку конфликтующее правило semi было отключено.
Это нормально, если мы хотим игнорировать правила Prettier, но в целом мы хотим, чтобы правила Prettier переопределяли правила ESLint.
В случае, если мы удалим файл конфигурации Prettier и воспользуемся его значениями по умолчанию (для чего требуется ;), выполнение проверки Prettier приведет к:

Checking formatting...
[warn] index.js
[warn] Code style issues found in the above file(s). Forgot to run Prettier?

Файл больше недействителен, так как в нем отсутствует ;, но запуск ESLint не завершится ошибкой, так как правила Prettier были отключены при запуске ESLint.

Здесь следует отметить одну важную вещь: порядок, используемый extends в конфигурации ESLint, имеет значение. Если мы воспользуемся следующим порядком, мы получим ошибку, поскольку правила AirBnB переопределят отключенные правила Prettier при запуске ESLint:

module.exports = {
  extends: [
    'eslint-config-prettier',
    'eslint-config-airbnb-base',
  ]
};

Запуск npx eslint index.js:

1:12  error  Missing semicolon  semi
3:23  error  Missing semicolon  semi
✖ 2 problems (2 errors, 0 warnings)
  2 errors and 0 warnings potentially fixable with the `--fix` option.

Чтобы решить эту проблему, давайте установим плагин:

npm i eslint-plugin-prettier # --save-dev recommended

Затем мы можем обновить наш .eslintrc.js файл до:

module.exports = {
  extends: [
    'eslint-config-airbnb-base',
    'plugin:prettier/recommended',
  ]
};

Мы заменили eslint-config-prettier на plugin:prettier/recommended. Ознакомьтесь с документацией ESLint о расширении плагина: https://eslint.org/docs/user-guide/configuring/configuration-files#using-a-configuration-from-a-plugin
Я также рекомендую вам проверьте, что eslint-plugin-prettier делает с нашей конфигурацией ESLint: «https://github.com/prettier/eslint-plugin-prettier/blob/a3d6a2259cbda7b2b4a843b6d641b298f03de5ad/eslint-plugin-prettier.js#L66-L

Снова запустив ESLint, мы получим:

1:12  error  Insert `;`  prettier/prettier
3:23  error  Insert `;`  prettier/prettier
✖ 2 problems (2 errors, 0 warnings)
  2 errors and 0 warnings potentially fixable with the `--fix` option.

Здесь следует отметить две вещи:

  1. Мы снова получаем ; ошибок, которые ранее были отключены с помощью eslint-config-prettier;
  2. Ошибка исходит из правила prettier/prettier, которое добавлено плагином. Все более красивые проверки будут сообщаться как prettier/prettierrules.

Машинопись

Начнем с самого простого: запуск ESLint для файлов TS.
Сейчас запуск ESLint для вашей кодовой базы будет npx eslint .. Это нормально, пока вы не захотите запустить его для файлов, которые не заканчиваются на .js.

Давайте добавим эти два файла в нашу базу кода:

// index.js
const a = 1

// index.ts
const a = 1

Запустив npx eslint . получаем:

1:7   error  'a' is assigned a value but never used  no-unused-vars
1:12  error  Insert `;`                              prettier/prettier
✖ 2 problems (2 errors, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

Он работает с нашим файлом JS, но не с файлом TS. Чтобы работать с файлами TS, вам нужно добавить --ext .js,.ts в команду ESLint. По умолчанию ESLint проверяет только .js файлы.

Бег npx eslint . --ext .js,.ts

/index.js
1:7   error  'a' is assigned a value but never used  no-unused-vars
1:12  error  Insert `;`                              prettier/prettier
/index.ts
1:7   error  'a' is assigned a value but never used  no-unused-vars
1:12  error  Insert `;`                              prettier/prettier
✖ 4 problems (4 errors, 0 warnings)
  2 errors and 0 warnings potentially fixable with the `--fix` option.

Пока работает как шарм. Давайте добавим реальный код TS и запустим его снова. Файл TS будет выглядеть так:

const a: number = 1

Запуск ESLint только с файлом .ts:

1:8  error  Parsing error: Unexpected token :
✖ 1 problem (1 error, 0 warnings)

ESLint по умолчанию не знает, как анализировать файлы Typescript. С подобной проблемой мы столкнулись при первом запуске ESLint со значениями по умолчанию ES5.
ESLint имеет конфигурацию, в которой вы можете указать парсер, который хотите использовать. Как вы могли догадаться, существует также пакет, который выполняет этот синтаксический анализ за нас. Он называется @typescript-eslint/parser.

Установим:

npm i @typescript-eslint/parser # --save-dev recommended

Теперь давайте настроим ESLint для использования нового парсера:

module.exports = {
  parser: "@typescript-eslint/parser",
  extends: [
    'eslint-config-airbnb-base',
    'plugin:prettier/recommended',
  ]
};

Повторный запуск ESLint (npx eslint index.ts):

1:7   error  'a' is assigned a value but never used  no-unused-vars
1:20  error  Insert `;`                              prettier/prettier
✖ 2 problems (2 errors, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

Прохладный! Теперь мы можем запускать ESLint для файлов TS. Тем не менее, у нас нет каких-либо правил, поэтому нам нужно настроить или использовать какое-нибудь руководство по стилю, подобное тому, которое мы использовали ранее в AirBnB.
Есть @typescript-eslint/eslint-plugin, который предлагает нам некоторые значения по умолчанию. Пойдем с этим пока:

npm i @typescript-eslint/eslint-plugin # --save-dev recommended

Добавляем его в нашу конфигурацию:

module.exports = {
  parser: "@typescript-eslint/parser",
  extends: [
    'eslint-config-airbnb-base',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
  ]
};

Сейчас выполняется npx eslint index.ts:

1:7   error    Type number trivially inferred from a number literal, remove type annotation  @typescript-eslint/no-inferrable-types
1:7   warning  'a' is assigned a value but never used                                        @typescript-eslint/no-unused-vars
1:20  error    Insert `;`                                                                    prettier/prettier
✖ 3 problems (2 errors, 1 warning)
  2 errors and 0 warnings potentially fixable with the `--fix` option.

Прохладный! Теперь у нас также есть правильный линтинг в нашем файле Typescript. Мы также можем видеть, что правило Prettier все еще применяется, как и ожидалось.

Имейте в виду, что typescript-eslint в этом случае имеет приоритет над eslint-config-airbnb-base. Это означает, что некоторые правила не будут работать в файлах TS, которые все еще действительны для файлов JS. Давайте посмотрим на файлы ниже, чтобы увидеть это в действии:

// index.js and index.ts
const a = 1;
a = 2;

Оба файла идентичны. Запустив npx eslint . --ext .js,.ts получаем:

/index.js
  2:1  error    'a' is constant                         no-const-assign
  2:1  warning  'a' is assigned a value but never used  @typescript-eslint/no-unused-vars
/index.ts
  2:1  warning  'a' is assigned a value but never used  @typescript-eslint/no-unused-vars
✖ 3 problems (1 error, 2 warnings)

Правило no-const-assign перезаписано на typescript-eslint для .ts файлов, поэтому мы не получаем одинаковой ошибки для обоих файлов.
Чтобы преодолеть это, нам нужно изменить порядок расширенных конфигураций, сначала идет typescript-eslint, затем eslint-config-airbnb-base . Если мы это сделаем:

module.exports = {
  parser: "@typescript-eslint/parser",
  extends: [
    "plugin:@typescript-eslint/recommended",
    "eslint-config-airbnb-base",
    "plugin:prettier/recommended"
  ]
};

Запуск npx eslint . --ext .js,.ts:

/index.js
  2:1  error    'a' is constant                         no-const-assign
  2:1  error    'a' is assigned a value but never used  no-unused-vars
  2:1  warning  'a' is assigned a value but never used  @typescript-eslint/no-unused-vars
/index.ts
  2:1  error    'a' is constant                         no-const-assign
  2:1  error    'a' is assigned a value but never used  no-unused-vars
  2:1  warning  'a' is assigned a value but never used  @typescript-eslint/no-unused-vars
✖ 6 problems (4 errors, 2 warnings)

Прохладный! Теперь мы получаем одинаковую ошибку для обоих файлов.

Одно замечание: в этом примере у меня есть кодовая база с JS / TS, возможно, это не ваш случай, и вы также можете использовать другое руководство по стилю, где конфликтов не будет.

Вот и все, ребята!

Я надеюсь, что эта статья помогла вам изучить или прояснить некоторые концепции совместной игры ESLint, Prettier и Typescript.

Короче говоря, вы должны понимать, какие файлы будет анализировать ESLint, и какой порядок конфигураций вам нужен. Изображение, добавляющее сейчас это в проект Vue, например, вам нужно добавить .vue в --ext .js,.ts,.vue и добавить (или настроить) руководство по стилю, которое добавит некоторые правила в ваш проект.

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

Вот и все! Удачного линтинга!