Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

Документы

Медиа

Назад
Вопрос про JavaScript: FSD, Feature-Sliced Design, cyclic dependencies, architecture, layers, modules

Как избежать циклических зависимостей в FSD?

Вопрос проверяет понимание принципов Feature-Sliced Design (FSD) и умение предотвращать циклические зависимости между слоями и слайсами архитектуры.

Короткий ответ

Циклические зависимости в FSD возникают, когда модули из разных слоев или слайсов ссылаются друг на друга напрямую или косвенно, создавая замкнутый круг. Чтобы их избежать, нужно строго соблюдать направление зависимостей: от верхних слоев (shared, entities) к нижним (features, widgets, pages). Используйте инверсию зависимостей через абстракции (интерфейсы) или публичные API каждого слайса. Регулярно проверяйте проект с помощью линтеров (например, madge) для выявления циклов на ранних этапах.

Длинный ответ

Feature-Sliced Design (FSD) — это архитектурная методология для фронтенд-приложений, которая организует код по бизнес-логике (слайсы) и техническим слоям. Циклические зависимости нарушают основное правило FSD — однонаправленный поток данных и зависимостей, что ведет к сложностям в поддержке, тестировании и переиспользовании кода.

Причины и последствия циклов

Цикл возникает, когда модуль A импортирует модуль B, а модуль B, прямо или через цепочку других модулей, импортирует модуль A. В контексте FSD это может быть между слоями (например, widget импортирует из feature, а тот импортирует что-то из того же widget) или между слайсами одной фичи. Это делает код связанным (coupling), усложняет рефакторинг и может привести к ошибкам при инициализации.

Основные стратегии предотвращения

  • Соблюдайте направление слоев: Зависимости должны идти только от верхних слоев к нижним: shared <- entities <- features <- widgets <- pages <- app. Не позволяйте модулям из нижних слоев импортировать что-либо из верхних.
  • Используйте публичные API: Каждый слайс должен экспортировать свою функциональность через файл index.ts (public API). Внутренняя реализация скрыта, а импорты из других слайсов делаются только через этот публичный интерфейс.
  • Внедряйте абстракции и инверсию зависимостей: Если двум модулям нужно взаимодействовать, вынесите общий контракт (интерфейс, тип) в слой shared или entities. Тогда оба модуля будут зависеть от этой абстракции, а не друг от друга.
  • Применяйте линтеры и статический анализ: Инструменты вроде madge или dependency-cruiser могут автоматически обнаруживать циклические зависимости в проекте и останавливать сборку.

Практический пример

Рассмотрим проблему: виджет UserCard (слой widgets) использует хук useUserData из фичи user-profile (слой features), а этот хук, в свою очередь, пытается использовать компонент Avatar из того же виджета UserCard — возникает цикл.

// НЕПРАВИЛЬНО: Циклическая зависимость
// widgets/user-card/ui/Avatar.tsx
export const Avatar = ({ src }) => ;

// widgets/user-card/ui/UserCard.tsx
import { useUserData } from 'features/user-profile';
export const UserCard = () => {
  const user = useUserData(); // Импорт из features
  return ;
};

// features/user-profile/lib/useUserData.ts
import { Avatar } from 'widgets/user-card/ui/Avatar'; // Обратный импорт!
export const useUserData = () => {
  // ... логика, использующая Avatar
};

Решение: вынести компонент Avatar в общий слой (например, shared/ui), чтобы оба модуля зависели от него, но не друг от друга.

// ПРАВИЛЬНО: Убираем цикл через общий shared слой
// shared/ui/Avatar/Avatar.tsx
export const Avatar = ({ src }) => ;

// widgets/user-card/ui/UserCard.tsx
import { useUserData } from 'features/user-profile';
import { Avatar } from 'shared/ui/Avatar';
export const UserCard = () => {
  const user = useUserData();
  return ;
};

// features/user-profile/lib/useUserData.ts
// Больше не импортирует Avatar из widgets
import { Avatar } from 'shared/ui/Avatar'; // Если нужно — импорт из shared
export const useUserData = () => {
  // ...
};

Вывод

Избегание циклических зависимостей в FSD критически важно для поддержания чистой, масштабируемой архитектуры. Строгое соблюдение направленности импортов, использование публичных API и вынос общих абстракций в нижние слои позволяют сохранить код декомпозированным и тестируемым. Применяйте эти практики с самого начала проекта и автоматизируйте проверку зависимостей.

Уровень

  • Рейтинг:

    3

  • Сложность:

    5

Навыки

  • JavaScript

    JavaScript

  • React

    React

Ключевые слова

#FSD

#Feature-Sliced Design

#cyclic dependencies

#architecture

#layers

#modules

Подпишись на React Developer в телеграм