Создание собственного shareable config

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


Базовая структура shareable-конфига

Традиционно shareable config оформляется как npm-пакет с именем, начинающимся с префикса:

  • eslint-config-<name>

Пример структуры пакета:

eslint-config-my-config/
├── index.js
├── package.json
├── README.md

Файл index.js содержит экспорт конфигурации ESLint.


Экспорт конфигурации

Классический формат (legacy config)

Shareable config в классическом формате представляет собой объект, соответствующий ESLint Configuration Schema:

module.exports = {
  env: {
    browser: true,
    node: true,
    es2022: true
  },
  extends: [
    "eslint:recommended"
  ],
  parserOptions: {
    ecmaVersion: "latest",
    sourceType: "module"
  },
  rules: {
    "no-unused-vars": "warn",
    "no-console": "off"
  }
};

Такая конфигурация может быть расширена другими проектами через поле extends.


Использование плагинов внутри shareable config

Shareable config часто инкапсулирует плагины, чтобы пользователю не требовалось вручную их подключать.

Установка зависимостей

В package.json плагины указываются как peerDependencies:

{
  "name": "eslint-config-my-config",
  "version": "1.0.0",
  "peerDependencies": {
    "eslint": ">=8.0.0",
    "eslint-plugin-import": ">=2.0.0"
  }
}

Подключение плагина в конфигурации

module.exports = {
  plugins: ["import"],
  rules: {
    "import/no-unresolved": "error",
    "import/order": "warn"
  }
};

Важно: сам пакет eslint-plugin-import не должен устанавливаться как dependency, если предполагается использование в составе проектов — он объявляется как peer dependency.


Наследование и композиция конфигураций

Shareable config часто строится поверх базовых конфигураций ESLint:

module.exports = {
  extends: [
    "eslint:recommended",
    "plugin:import/recommended"
  ],
  rules: {
    "import/no-cycle": "error"
  }
};

Механизм extends позволяет комбинировать несколько слоёв конфигурации:

  • базовые правила ESLint
  • конфигурации плагинов
  • кастомные корпоративные стандарты

Многоуровневая архитектура конфигов

В сложных системах создаётся несколько уровней конфигурации:

eslint-config-base
eslint-config-react
eslint-config-node
eslint-config-typescript
eslint-config-app

Каждый слой расширяет предыдущий:

module.exports = {
  extends: [
    "eslint-config-base",
    "plugin:react/recommended"
  ],
  rules: {
    "react/react-in-jsx-scope": "off"
  }
};

Поддержка overrides

Shareable config может включать переопределения для отдельных файлов:

module.exports = {
  rules: {
    "no-console": "warn"
  },
  overrides: [
    {
      files: ["*.test.js"],
      rules: {
        "no-console": "off"
      }
    }
  ]
};

Overrides позволяют разделять правила по контексту:

  • тесты
  • конфигурационные файлы
  • серверный код
  • фронтенд

Flat config (ESLint 9+)

Современный формат ESLint основан на flat configuration, где shareable config экспортирует массив конфигурационных объектов.

Пример flat shareable config

export default [
  {
    files: ["**/*.js"],
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module"
    },
    rules: {
      "no-unused-vars": "warn"
    }
  }
];

Подключение flat config

import myConfig from "eslint-config-my-config";

export default [
  ...myConfig
];

Flat config исключает необходимость extends, заменяя его композиционным объединением массивов.


Подключение парсеров

Shareable config может фиксировать использование парсера:

module.exports = {
  parser: "@babel/eslint-parser",
  parserOptions: {
    requireConfigFile: false,
    ecmaFeatures: {
      jsx: true
    }
  }
};

Для TypeScript:

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

Организация правил

Крупные shareable configs часто группируют правила по категориям:

Стиль кода

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

Потенциальные ошибки

rules: {
  "no-undef": "error",
  "no-unused-vars": "warn",
  "no-implicit-globals": "error"
}

Архитектурные ограничения

rules: {
  "no-restricted-imports": [
    "error",
    {
      patterns: ["../*"]
    }
  ]
}

Публикация пакета

package.json

{
  "name": "eslint-config-company",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "peerDependencies": {
    "eslint": ">=8.0.0"
  }
}

Публикация в npm

Стандартный процесс публикации:

npm publish

Версионирование

Shareable config требует строгого semver-подхода:

  • MAJOR — несовместимые изменения правил
  • MINOR — добавление новых правил без breaking changes
  • PATCH — исправления конфигурации

Изменение поведения правила ESLint считается breaking change, даже если формально конфиг остаётся валидным.


Документирование конфигурации

README shareable config обычно фиксирует:

  • назначение пакета
  • список включённых правил
  • зависимости
  • примеры подключения
  • рекомендации по расширению

Пример подключения:

module.exports = {
  extends: ["eslint-config-company"]
};

Интеграция с несколькими средами

Shareable config может разделять конфигурации:

module.exports = {
  extends: ["./base"],
  overrides: [
    {
      files: ["src/server/**/*.js"],
      env: {
        node: true
      }
    },
    {
      files: ["src/client/**/*.js"],
      env: {
        browser: true
      }
    }
  ]
};

Расширяемость конфигурации

Для гибкости часто используется паттерн слоёв:

module.exports = {
  extends: [
    "./rules/base",
    "./rules/imports",
    "./rules/best-practices"
  ]
};

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


Типичные ошибки при создании shareable config

Неправильное использование dependencies:

"dependencies": {
  "eslint-plugin-import": "*"
}

Корректный подход:

"peerDependencies": {
  "eslint-plugin-import": ">=2.0.0"
}

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


Совместимость версий ESLint

Shareable config обязан учитывать:

  • версию ESLint
  • изменения в схеме конфигурации
  • переход legacy → flat config

Некоторые правила или поля могут быть deprecated, что требует адаптации структуры экспорта и зависимостей.