Стек: React, TypeScript, ESLint 9, IDE: VS Code.
Зачем организовывать импорты
Импорты в приложении – самодокументируемая шапка файла. Взглянув на неё, можно быстро сделать вывод о содержимом: какие библиотеки, компоненты, типы и стили - если речь о React-компоненте - используются в файле, и создать общее впечатление о модуле.
Хорошо, когда эта «шапка» имеет единый порядок: мы быстро можем увидеть, например, какие типы использует файл, много ли компонентов он содержит и т.п. Короче говоря – это ускоряет и точечный, и общий анализ файла. Ну и просто приятно, когда код содержится в порядке и подчиняется единым правилам.
Цели, поставленные для организации импортов
Разделить импорты на группы: библиотеки / внешние / внутренние / типы TypeScript / стили и прочее.
Типы TypeScript тоже должны быть разделены на группы, соответствующие основным группам импортов. Также необходимо использовать в файле только top-level type imports (
import type { ... }), inline type imports не использовать (мне кажется, так удобнее).Чтобы разделители (новые строки) добавлялись автоматически между определёнными группами, а не между всеми подряд.
Делать это вручную или просить команду всегда выделять импорты отдельно – можно, но сложно. Всё равно будут ошибки, что послужит поводом для комментария на ревью.
Попытка использовать только eslint-plugin-import
Первый плагин, который я попробовала – популярный eslint-plugin-import. У него есть важное правило import/consistent-type-specifier-style, которое позволяет отделить все inline-импорты типов в top-level. (Если существуют другие способы выделения типов в top-level imports – было бы интересно узнать.)
С помощью этого плагина я хотела настроить и порядок импортов, но не хватило кастомизации, а именно – выделения стилей в отдельную группу (нужно создавать кастомную с регулярными выражениями), расстановки новых строк только между определенными группами, а не между всеми. Это мелочи, которые можно было решить ручной доработкой, но хотелось добиться полной автоматической правки файла при сохранении.
Добавление плагина eslint-plugin-perfectionist
В итоге я настроила порядок импортов с помощью другого популярного плагина – eslint-plugin-perfectionist. У него больше групп по умолчанию и более гибкая настройка расположения новых строк между группами. Единственный недостаток: нет встроенного правила для автоматической группировки импортов типов в соответствии с порядком основных импортов – расстановку импортов типов нужно прописывать явно в массиве групп.
Получившийся конфиг
В итоге я использовала комбинацию двух вышеуказанных плагинов, и это позволило добиться желаемого результата - автоматической настройки без ручных доработок. И некоторого снижения количества комментариев в код-ревью)
Обратите внимание на customGroups. По задумке импорты React должны идти первыми и в основных импортах, и в типах TypeScript. Группа type-react идёт первой в массиве customGroups, поэтому при сортировке типы React отделяются первыми в отдельную группу. Если поменять порядок групп в customGroups, типы React попадут наверх вместе с обычными импортами React, а это нам не нужно.
import importPlugin from 'eslint-plugin-import'; import perfectionisPlugin from 'eslint-plugin-perfectionist'; export default { files: ['**/*.{js,ts,tsx}'], plugins: { perfectionist: perfectionisPlugin, import: importPlugin }, rules: { 'import/consistent-type-specifier-style': ['error', 'prefer-top-level'], // разрешает только top-level type import 'import/newline-after-import': ['error', { count: 1 }], // пустая строка после импортов 'perfectionist/sort-imports': [ 'error', { type: 'alphabetical', // сортировка элементов по алфавиту order: 'asc', // порядок от a к z ignoreCase: true, // игнорирование регистра при сортировке groups: [ 'side-effect', // side-effect импорты { newlinesBetween: 1 }, 'builtin', // node встроенные модули (fs, path) { newlinesBetween: 1 }, 'react', { newlinesBetween: 0 }, 'external', // npm пакеты { newlinesBetween: 1 }, 'internal', // внутренние импорты { newlinesBetween: 'ignore' }, 'parent', // ../ импорты { newlinesBetween: 'ignore' }, 'sibling', // ./ импорты { newlinesBetween: 'ignore' }, 'index', // ./index импорты { newlinesBetween: 1 }, 'import', // любые импорты { newlinesBetween: 1 }, // все импорты типов 'type-react', { newlinesBetween: 0 }, 'type-external', { newlinesBetween: 1 }, 'type-internal', { newlinesBetween: 'ignore' }, 'type-parent', { newlinesBetween: 'ignore' }, 'type-sibling', { newlinesBetween: 'ignore' }, 'type-index', { newlinesBetween: 0 }, 'type-import', { newlinesBetween: 1 }, 'side-effect-style', // side-effect импорты стилей { newlinesBetween: 0 }, 'style', // импорты стилей ], customGroups: [ { groupName: 'type-react', elementNamePattern: ['^react$', '^react-.*'], selector: 'type', }, { groupName: 'react', elementNamePattern: ['^react$', '^react-.*'], }, ], newlinesBetween: 1, // пустая строка между группами internalPattern: ['^app/.+'], // петтерны внутренних путей }, ], }, };
Результат применения
примеры до


примеры после


Если у вас есть опыт организации импортов в больших проектах или вы знаете другие способы автоматической сортировки – буду рада обсудить в комментариях!
