PassFront
  1. PassFront
  2. База знаний
  3. Продвинутые темы

Что такое циклические зависимости между модулями и как их устранять?

Продвинутые темы

Циклическая зависимость возникает, когда модуль A импортирует B, а B прямо или через цепочку импортирует A. Такой цикл усложняет код и может приводить к ошибкам при загрузке.

Пример

// a.js
import { b } from './b.js';
export const a = () => b();

// b.js
import { a } from './a.js';
export const b = () => a();

Чем это опасно

  • В ES-модулях привязки живые, но значение может быть недоступно до выполнения модуля: обращение до инициализации даёт ReferenceError (TDZ) или undefined.
  • В CommonJS при цикле возвращается частично заполненный exports.
  • Сложнее читать код и тестировать модули по отдельности.
  • Ломается tree shaking и ухудшается разбиение на чанки.
  • Возможны неожиданные побочные эффекты порядка загрузки.

Как находить

Инструменты madge, dpdm, плагин ESLint import/no-cycle, предупреждения сборщиков.

npx madge --circular src

Как устранять

  1. Выделить общий код в третий модуль, от которого зависят оба.
  2. Инвертировать зависимость: передавать функцию или интерфейс параметром (внедрение зависимости) вместо прямого импорта.
  3. Объединить тесно связанные модули в один.
  4. Отложить импорт до момента использования (динамический import()) — как временная мера.
  5. Соблюдать слои архитектуры: верхние слои знают о нижних, но не наоборот (FSD, Clean Architecture).

Профилактика

Единые правила импортов, публичный API модуля через index.ts, проверка циклов в CI.

Коротко для собеседования

Цикл — когда модули зависят друг от друга. Он приводит к недоинициализированным значениям и усложняет сопровождение. Лечится выделением общего модуля, инверсией зависимостей и правилами слоёв, а находят его через madge или import/no-cycle.

Другие вопросы раздела