Ответ
В FSD кросс-импорты между слоями - это антипаттерн. Решаю проблему так:
-
Выношу общую логику на уровень выше - если модуль из одного слоя нужен в другом, поднимаю его в shared или переношу в нужный слой.
-
Использую Public API - в каждом слое есть index.ts, который экспортирует только разрешенные модули:
// features/profile/public-api.ts
export { ProfileCard } from './ui/ProfileCard';
- Применяю Dependency Injection - если нужно взаимодействие между слоями, передаю зависимости через props/context:
// widgets/UserList
<UserList profileCard={<ProfileCard />} />
-
Использую паттерны Event Bus или State Management для связи между несвязанными модулями.
-
Настраиваю линтеры с правилами no-relative-imports и restricted-imports для автоматической проверки.
Ответ 18+ 🔞
Ах ты ж ёпта, ну и тема у нас сегодня — про эти ваши кросс-импорты между слоями! Это ж классический пиздец, когда всё начинает друг на друга ссылаться, как мартышки в зоопарке. Короче, это антипаттерн, и если его не остановить, проект превращается в спагетти, где хуй разберёшь, кто от кого зависит.
Вот как я с этим воюю, чтобы не охуеть с утра от ошибок сборки:
-
Вынос общей логики нахуй повыше. Если модуль из
featuresвдруг понадобился вentities, аentitiesлезет вwidgets— это пизда. Значит, надо эту общую хуйню вынести либо вshared, либо вообще перетащить в тот слой, где она теперь по праву живёт. Нечего шастать по чужим квартирам! -
Public API — наш бро. В каждом слое заводим файлик
public-api.ts(илиindex.ts), который работает как швейцар в дорогом отеле. Он решает, кого пускать на выход. Всё внутреннее говно остаётся внутри, а наружу торчит только красивая, разрешённая морда.
// features/profile/public-api.ts
export { ProfileCard } from './ui/ProfileCard'; // Можно
// А вот сюда всякие internal/private-модули — нихуя!
- Dependency Injection, ёбана! Если один слой реально должен работать с другим, не надо лезть к нему в окно. Передаём зависимость явно, как порядочные люди — через пропсы или контекст.
// widgets/UserList
<UserList profileCard={<ProfileCard />} /> // Вот, держи, что тебе нужно. Больше ни хуя не проси.
-
Event Bus или State Management для особо ебучих случаев. Когда модули в разных концах архитектуры должны общаться, но видеть друг друга им западло — пусть общаются через события или глобальное состояние. Как два соседа через забор: крикнул — и всё, не надо в гости ходить.
-
Линтеры — наш надёжный ёбарь. Настраиваем правила
no-relative-importsиrestricted-imports, чтобы эта гребанная проверка была автоматической. Запушил хуйню — получи ошибку в CI, и иди, мудак, исправляй. Волшебно, пиздец!
Короче, суть в том, чтобы зависимости текли в одну сторону, как вода с горы. Сверху вниз: app → pages → widgets → features → entities → shared. Как только пошло обратно — это пизда, alarm bells, надо решать. Иначе потом разгребать этот пиздец будет овердохуища больно.