Создание общей конфигурации для команды

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

Общая конфигурация ESLint решает эти проблемы за счёт единого набора правил, который автоматически применяется ко всем участникам проекта. В результате:

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

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


Принципы построения командной конфигурации

При создании общей конфигурации необходимо учитывать несколько ключевых принципов.

Предсказуемость

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

Пример понятного ограничения:

{
  "eqeqeq": "error"
}

Такое правило требует использовать только строгое сравнение:

if (value === 5) {
}

вместо:

if (value == 5) {
}

Минимизация субъективности

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

Например, правило:

{
  "curly": ["error", "all"]
}

не связано со вкусом разработчика, а улучшает читаемость и снижает риск ошибок.

Автоматическая исправляемость

Предпочтение следует отдавать правилам, которые могут автоматически исправляться через параметр --fix.

Например:

{
  "semi": ["error", "always"]
}

или

{
  "quotes": ["error", "single"]
}

Большинство нарушений таких правил исправляются автоматически.

Практическая ценность

Каждое правило должно приносить реальную пользу проекту.

Полезное правило:

{
  "no-unused-vars": "error"
}

Малополезное правило:

{
  "id-length": ["error", {
    "min": 3
  }]
}

которое может запрещать вполне нормальные переменные вроде:

i
j
x
y

Выбор формата конфигурации

Современные версии ESLint рекомендуют использовать Flat Config.

Пример файла:

// eslint.config.js

export default [
  {
    rules: {
      semi: ["error", "always"]
    }
  }
];

Ранее широко использовались файлы:

.eslintrc.js
.eslintrc.json
.eslintrc.yml

Например:

module.exports = {
  rules: {
    semi: ["error", "always"]
  }
};

Для новых проектов предпочтительным считается Flat Config благодаря более простой архитектуре и лучшей расширяемости.


Базовая структура командной конфигурации

Типичная конфигурация включает несколько групп настроек.

Настройки языка

export default [
  {
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module"
    }
  }
];

Здесь определяются:

  • версия ECMAScript;
  • использование модулей;
  • глобальные переменные;
  • парсер.

Глобальные правила

export default [
  {
    rules: {
      eqeqeq: "error",
      curly: "error",
      semi: ["error", "always"]
    }
  }
];

Эти правила действуют во всём проекте.

Исключения

export default [
  {
    ignores: [
      "dist/**",
      "coverage/**",
      "node_modules/**"
    ]
  }
];

Линтер не будет анализировать автоматически сгенерированные файлы.


Использование готовых наборов правил

Создание конфигурации с нуля редко оправдано. Обычно команда опирается на уже существующие стандарты.

Наиболее распространённый вариант.

import js from "@eslint/js";

export default [
  js.configs.recommended
];

Конфигурация включает наиболее полезные правила для обнаружения ошибок.

Примеры проверок:

  • недостижимый код;
  • неиспользуемые переменные;
  • дублирование условий;
  • ошибки в конструкциях циклов.

Корпоративные стандарты

Многие компании поддерживают собственные наборы правил.

Примеры:

  • Airbnb;
  • Google;
  • StandardJS;
  • внутренние корпоративные конфигурации.

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


Создание внутреннего пакета конфигурации

Для нескольких проектов удобнее хранить настройки в отдельном npm-пакете.

Структура:

eslint-config-company/
│
├── package.json
├── index.js
└── README.md

Файл конфигурации:

export default [
  {
    rules: {
      eqeqeq: "error",
      curly: "error",
      semi: ["error", "always"]
    }
  }
];

Подключение в проекте:

npm install eslint-config-company
import companyConfig from "eslint-config-company";

export default [
  ...companyConfig
];

Преимущества подхода:

  • единый источник настроек;
  • централизованные обновления;
  • одинаковое поведение во всех проектах;
  • упрощение поддержки.

Разделение правил по категориям

Крупные команды обычно группируют правила логически.

Поиск ошибок

{
  "no-unreachable": "error",
  "no-undef": "error",
  "no-dupe-keys": "error"
}

Предназначены для выявления потенциальных дефектов.

Лучшие практики

{
  "eqeqeq": "error",
  "no-eval": "error"
}

Снижают вероятность появления проблемного кода.

Читаемость

{
  "curly": "error",
  "dot-notation": "error"
}

Улучшают восприятие исходного кода.

Стилистика

{
  "quotes": ["error", "single"],
  "semi": ["error", "always"]
}

Отвечают за единообразие оформления.


Интеграция с Prettier

В большинстве современных команд ESLint отвечает за качество кода, а Prettier — за форматирование.

Без интеграции возможны конфликты.

Например:

ESLint требует:

{
  "indent": ["error", 2]
}

а Prettier форматирует иначе.

Для предотвращения конфликтов используется:

npm install eslint-config-prettier

Затем:

import eslintConfigPrettier from "eslint-config-prettier";

export default [
  eslintConfigPrettier
];

Конфликтующие правила ESLint отключаются автоматически.

Такое разделение обязанностей считается отраслевым стандартом.


Настройка для разных частей проекта

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

Например:

  • серверная часть Node.js;
  • клиентская часть браузера;
  • тесты;
  • скрипты сборки.

Flat Config позволяет применять разные правила к разным файлам.

Конфигурация для тестов

export default [
  {
    files: ["tests/**/*.js"],
    rules: {
      "no-unused-expressions": "off"
    }
  }
];

Конфигурация для скриптов

export default [
  {
    files: ["scripts/**/*.js"],
    rules: {
      "no-console": "off"
    }
  }
];

Конфигурация для приложения

export default [
  {
    files: ["src/**/*.js"],
    rules: {
      "no-console": "error"
    }
  }
];

Создание правил для TypeScript-проектов

Во многих командах JavaScript используется совместно с TypeScript.

Подключается пакет:

npm install typescript-eslint

Пример:

import tseslint from "typescript-eslint";

export default [
  ...tseslint.configs.recommended
];

Дополнительные проверки:

{
  "@typescript-eslint/no-explicit-any": "warn",
  "@typescript-eslint/no-unused-vars": "error"
}

Такие правила помогают поддерживать качество типизации и предотвращают распространённые ошибки.


Использование переменных окружения

Команда может работать одновременно с браузером и Node.js.

Для браузера:

{
  globals: {
    window: "readonly",
    document: "readonly"
  }
}

Для Node.js:

{
  globals: {
    process: "readonly",
    __dirname: "readonly"
  }
}

Это предотвращает ложные предупреждения линтера.


Автоматическая проверка перед коммитом

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

Популярный подход — запуск ESLint перед каждым коммитом.

Установка:

npm install husky lint-staged --save-dev

Конфигурация:

{
  "lint-staged": {
    "*.js": [
      "eslint --fix"
    ]
  }
}

Перед созданием коммита будут проверяться изменённые файлы.

Преимущества:

  • ошибки обнаруживаются раньше;
  • репозиторий остаётся в согласованном состоянии;
  • уменьшается количество проблем после слияния веток.

Проверка в CI/CD

Даже при наличии локальных проверок необходимо запускать ESLint на сервере.

Пример команды:

npx eslint .

Пример этапа CI:

lint:
  stage: test
  script:
    - npm ci
    - npm run lint

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

Это гарантирует соблюдение стандартов независимо от локальных настроек разработчиков.


Версионирование общей конфигурации

При использовании общего npm-пакета важно соблюдать семантическое версионирование.

PATCH

Исправления ошибок:

1.0.0 → 1.0.1

MINOR

Добавление новых возможностей без нарушения совместимости:

1.0.0 → 1.1.0

MAJOR

Изменение правил, способное привести к большому количеству новых ошибок:

1.0.0 → 2.0.0

Такой подход помогает контролировать внедрение новых требований.


Документирование правил команды

Даже самая качественная конфигурация требует документации.

Обычно описываются:

  • цель каждого нестандартного правила;
  • причины его появления;
  • допустимые исключения;
  • порядок отключения правила.

Пример отключения для конкретной строки:

// eslint-disable-next-line no-console
console.log(data);

Пример отключения для блока:

/* eslint-disable no-console */

console.log(data);

/* eslint-enable no-console */

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


Типичный пример общей командной конфигурации

import js from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier";

export default [
  js.configs.recommended,

  {
    ignores: [
      "dist/**",
      "coverage/**",
      "node_modules/**"
    ]
  },

  {
    rules: {
      eqeqeq: "error",
      curly: "error",
      "no-unused-vars": "error",
      "no-console": "warn",
      semi: ["error", "always"],
      quotes: ["error", "single"]
    }
  },

  {
    files: ["tests/**/*.js"],
    rules: {
      "no-console": "off"
    }
  },

  eslintConfigPrettier
];

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