Отладка и обработка ошибок загрузки Remote

В Webpack Module Federation загрузка remote модулей опирается на асинхронное получение remoteEntry.js, его выполнение в рантайме и последующее разрешение экспозированных модулей через контейнер федерации. Ошибки могут возникать на каждом из этих этапов: от сетевого запроса до выполнения фабрики модуля.

Классическая цепочка загрузки выглядит следующим образом:

  1. Формирование URL до remoteEntry.js
  2. Загрузка скрипта через динамический <script> или import()
  3. Инициализация контейнера (init)
  4. Обращение к get(module)
  5. Выполнение фабрики модуля
  6. Возврат экспортов в host-приложение

Любой сбой на этом пути требует различного подхода к обработке.


Ошибки загрузки remoteEntry.js на уровне сети

Наиболее частая категория проблем связана с невозможностью загрузить remoteEntry.js.

Причины:

  • недоступный сервер remote-приложения
  • неверный publicPath
  • CORS-блокировка
  • DNS или сетевые ограничения
  • неправильная версия или путь к файлу

Типичный симптом в консоли:

  • Loading script failed
  • Failed to fetch dynamically imported module
  • Script error

Особенность поведения браузера

Динамически загруженные скрипты через <script> не всегда возвращают детализированную ошибку. В большинстве случаев доступна только общая информация о падении загрузки, без HTTP-статуса.


Обработка ошибок загрузки remoteEntry через onError

Webpack Module Federation позволяет перехватывать ошибку загрузки через кастомную обёртку динамического импорта.

Пример базового механизма:

function loadRemote(url) {
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");

    script.src = url;
    script.type = "text/javascript";
    script.async = true;

    script.onl oad = () => resolve(true);

    script.oner ror = () => {
      reject(new Error(`Remote loading failed: ${url}`));
    };

    document.head.appendChild(script);
  });
}

В реальных конфигурациях Module Federation аналогичная логика встроена в runtime, но может быть расширена через кастомные загрузчики.


Ошибки инициализации контейнера (init failure)

После загрузки remoteEntry.js происходит инициализация контейнера:

  • проверка shared scope
  • синхронизация зависимостей
  • регистрация модулей

Ошибки на этом этапе часто связаны с:

  • несовместимостью версий shared библиотек
  • отсутствием обязательных зависимостей
  • конфликтом singleton-модулей

Типичные сообщения:

  • Container initialization failed
  • Shared module is not available
  • Uncaught Error: Shared module version mismatch

Конфликт singleton-зависимостей

При использовании singleton: true Webpack требует строгого соблюдения версии зависимости. Несовпадение может привести к отказу инициализации контейнера.

Пример проблемной конфигурации:

shared: {
  react: { singleton: true, requiredVersion: "^18.0.0" }
}

Если host использует React 18.2, а remote — 17.x, поведение зависит от стратегии разрешения версий и может привести к runtime-ошибке.


Ошибки получения модуля через get()

После успешной инициализации контейнера происходит вызов:

container.get("./module")

На этом этапе возможны следующие проблемы:

Модуль не экспортирован

Причина:

  • отсутствует exposes в remote
  • неправильный путь экспорта
  • опечатка в имени модуля

Ошибка:

  • Module not found
  • Cannot read properties of undefined

Несовместимость форматов экспорта

Module Federation ожидает корректный ESM-like интерфейс. Ошибки возникают при:

  • смешивании CommonJS и ESM
  • некорректном default export
  • транспиляции без interop

Ошибки выполнения фабрики модуля

После получения модуля выполняется его фабрика. Это уже обычный runtime JavaScript-код, и ошибки здесь похожи на стандартные application errors.

Причины:

  • обращение к undefined зависимостям
  • side effects при инициализации
  • ошибки React/Vue рендера
  • отсутствие shared dependency

Пример:

export default function Module() {
  return React.createElement("div", null, window.nonExisting.value);
}

Такие ошибки не отличаются от обычных runtime exceptions, но сложнее диагностируются из-за асинхронной природы загрузки.


Отладка через Webpack runtime hooks

Webpack предоставляет runtime hooks, позволяющие вмешиваться в процесс загрузки remote.

override console ошибок

Можно перехватывать глобальные ошибки:

window.addEventListener("error", (e) => {
  console.log("Global error:", e.message);
});

Однако этого недостаточно для федерации модулей.


container init hook

Расширенный подход — обёртка вокруг init:

async function safeInit(container, shareScope) {
  try {
    await container.init(shareScope);
  } catch (e) {
    console.error("Init failed", e);
    return null;
  }
}

Это позволяет изолировать падение remote и предотвратить крах host-приложения.


Retry-механизм загрузки remote

Проблемы сети требуют повторных попыток загрузки remoteEntry.js.

Базовая стратегия retry:

async function loadWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      await loadRemote(url);
      return;
    } catch (e) {
      if (i === retries - 1) throw e;
    }
  }
}

При промышленной эксплуатации добавляются:

  • экспоненциальная задержка
  • fallback URL
  • переключение на CDN

Fallback remote и деградация функциональности

Архитектура Module Federation позволяет задавать альтернативные источники remote.

Пример стратегии:

  • primary remote: CDN A
  • fallback remote: CDN B
  • локальный stub: заглушка функциональности

Логика выбора:

  1. попытка загрузки primary
  2. при ошибке переход на fallback
  3. при полном отказе использование stub

Stub может выглядеть как:

export const fallbackModule = {
  render: () => "Service unavailable"
};

Проблемы версионирования remoteEntry

Отдельная категория ошибок связана с кэшированием remoteEntry.js.

Сценарии:

  • браузер загружает старую версию
  • host ожидает новый интерфейс
  • mismatch chunk ids
  • несовместимость shared scope

Симптомы

  • случайные runtime ошибки
  • нестабильное поведение после деплоя
  • ошибки только у части пользователей

Решения на уровне инфраструктуры

  • добавление hash в имя файла remoteEntry.[hash].js
  • отключение агрессивного cache-control
  • использование manifest-файлов
  • version pinning в runtime

Инструменты диагностики

Для анализа загрузки remote используются следующие подходы:

Network tab

Проверка:

  • статус remoteEntry.js
  • CORS headers
  • cache headers
  • корректность URL

Webpack logs

В dev-режиме:

  • логирование container init
  • вывод shared resolution
  • предупреждения version mismatch

Runtime instrumentation

Добавление логов:

const originalGet = container.get;

container.get = async (module) => {
  console.log("Loading module:", module);
  return originalGet(module);
};

Изоляция ошибок remote в архитектуре host

Ключевой принцип устойчивой федерации — недопущение падения host-приложения из-за remote.

Подходы:

  • React Error Boundaries
  • try/catch вокруг dynamic import
  • lazy loading с fallback UI
  • sandbox execution

Пример React-изоляции:

class RemoteBoundary extends React.Component {
  state = { error: null };

  static getDerivedStateFromError(error) {
    return { error };
  }

  render() {
    if (this.state.error) {
      return "Remote module failed";
    }
    return this.props.children;
  }
}

Типовые цепочки диагностики

При возникновении ошибки загрузки remote последовательность анализа обычно сводится к следующему:

  1. Проверка доступности remoteEntry.js
  2. Проверка CORS и заголовков
  3. Проверка версии контейнера
  4. Проверка shared dependencies
  5. Проверка экспозиций exposes
  6. Анализ runtime stack trace
  7. Проверка кэша и CDN

Поведение при частичной деградации remote

Module Federation допускает частичную работоспособность системы:

  • часть модулей может загружаться
  • часть может падать
  • shared scope может быть частично доступен

Это требует разделения ошибок:

  • критические (block host)
  • некритические (block feature)
  • деградационные (fallback UI)

Контроль стабильности remote в продакшене

Стабильность обеспечивается сочетанием:

  • строгого versioning shared dependencies
  • мониторинга загрузки remoteEntry
  • логирования init/get ошибок
  • CDN failover
  • runtime fallback стратегий

Основной принцип: remote не должен становиться единой точкой отказа для host-приложения.