Когда поднимаешь ESLint до 10-й версии в проектах с React 19, старый eslint-plugin-react просто ломается. Ошибка contextOrFilename.getFilename is not a function — это не баг, а фича нового API ESLint. И вот ты сидишь с открытым issue в upstream-репозитории, который висит уже полгода, а миграцию делать надо сейчас.
Почему форк — это не failure, а contingency plan
Изначально я думал, что потерплю пару недель, пока мержится PR. Но когда стало ясно, что реакция сообщества измеряется в геологических эпохах, родился @ternaus/eslint-plugin-react.
Критерии были жёсткие:
- Только React 19+
- Только ESLint 10 с flat config
- Только то, что не покрывает Biome
- Нулевой tolerance к legacy-коду
Из 104 оригинальных правил осталось 11. Вот как я их отбирал:
- Дублирование с Biome — сразу в корзину (20 правил типа
jsx-key) - Стилевые предписания — не наш профиль (
jsx-sort-props,function-component-definition) - Сомнительные эвристики — если правило не может дать точный ответ без type-aware анализа (
no-unused-prop-types) - Устаревшие API — React 18 и классические конфиги не наш target
Остались только правила, которые:
- Ловят реальные баги в React 19 (
no-direct-mutation-state) - Предупреждают о проблемах производительности (
prefer-use-state-lazy-initialization) - Знают про специфику новой версии (
no-function-default-props)
Интеграция с Next.js: где собака порылась
Теоретически всё работало. Практически Next.js 16 упорно пытался загрузить старый eslint-plugin-react. Проблема в том, что eslint-config-next:
- Использует flat config
- Но лезет за правилами в
react.configs.recommended.rules(legacy-формат)
Решение выглядело как костыль, но работало:
// В eslint.config.js
import react from '@ternaus/eslint-plugin-react';
export default [
{
files: ['**/*.{js,jsx,mjs,cjs,ts,tsx}'],
...react.configs.flat.recommended,
// Дублируем для Next.js
rules: react.configs.recommended.rules
},
];
Плюс магия Yarn resolutions:
{
"resolutions": {
"eslint-plugin-react": "npm:@ternaus/eslint-plugin-react@8.0.0"
}
}
Что делать, если ваш проект не вписывается в матрицу
Мой форк — это opinionated выбор. Если вам нужно:
- Поддержка React 18 — остаётся только ждать upstream
- Правила для пропсов (
prop-types) — их нет в новой версии - React Native — здесь только DOM-элементы
Для остальных случаев вот рецепт:
- Ставим связку:
yarn add -D @biomejs/biome@latest eslint@10 @ternaus/eslint-plugin-react@8
- Настраиваем Biome на полный набор правил:
{
"linter": {
"rules": { "preset": "all" },
"domains": { "react": "all" }
}
}
- Добавляем ESLint только для React-специфики:
// eslint.config.js
import react from '@ternaus/eslint-plugin-react';
export default [{
files: ['**/*.{js,jsx,ts,tsx}'],
...react.configs.flat.recommended
}];
Выводы для тех, кто хочет повторить
- Не бойтесь форков — особенно когда upstream застрял в переходном периоде
- Интегрируйте с Biome — он покрывает 80% случаев, ESLint оставьте для framework-specific правил
- Тестируйте на реальных проектах — мой первый RC упал на валидных HTML-атрибутах в
<select> - Yarn resolutions — ваш друг — когда Next.js упорно тянет старую версию
Сейчас пакет стабильно работает в продакшене на трёх проектах с разными стеками. Главное — чётко определить границы поддержки и не пытаться угодить всем. Иногда меньше — значит действительно лучше.