Микрофронтенды на Webpack 5

Module Federation: собирать не вместе.

Практическая памятка для host и remote приложений. Module Federation позволяет загружать части другого приложения во время выполнения, но не заменяет договорённости о границах, версиях и владении.

Модель

host

Контейнер, который импортирует и отображает удалённые модули.

remote

Приложение, которое выставляет свои модули через remoteEntry.js.

exposes

Публичный контракт remote: какие модули доступны другим приложениям.

remotes

Карта адресов remote-модулей, которые может загрузить host.

shared

Библиотеки, которые не нужно тащить отдельной копией в каждый remote.

Делите систему по доменному владению, а не по техническим папкам или страницам меню

Remote: конфигурация

new ModuleFederationPlugin({ name: 'catalog' })

Уникальное имя контейнера remote.

filename: 'remoteEntry.js'

Имя entry-файла, который host загрузит первым.

exposes: { './ProductCard': './src/ProductCard' }

Выставить компонент под стабильным публичным ключом.

output: { publicPath: 'auto' }

Webpack определяет базовый URL для дочерних чанков относительно загруженного remote entry.

devServer: { port: 3001 }

Remote должен быть доступен host во время локальной разработки.

Host: подключение

remotes: { catalog: 'catalog@https://cdn.example.com/catalog/remoteEntry.js' }

Связать имя импорта с контейнером и URL его entry-файла.

import('catalog/ProductCard')

Динамический импорт remote-модуля; он загружается во время выполнения.

React.lazy(() => import('catalog/ProductCard'))

Лениво подключить удалённый React-компонент.

<Suspense fallback={<Loader />}>

Показать безопасное состояние, пока remote загружается.

ErrorBoundary

Отделить падение удалённого компонента от остальной страницы.

Shared-зависимости

shared: { react: { singleton: true } }

Одна копия React для host и remote: важно для контекста, hooks и рендера.

react-dom: { singleton: true }

То же правило для React DOM.

requiredVersion: deps.react

Заявить совместимую версию библиотеки из package.json.

strictVersion: true

Не загружать несовместимую версию молча; ошибка лучше скрытого расхождения.

eager: true

Загружать shared-библиотеку сразу. Используйте редко: это увеличивает initial bundle.

Не делайте shared всё подряд: разделяйте только базовые рантаймы и действительно общие крупные библиотеки

Контракты

exposes: { './routes': './src/routes' }

Публикуйте узкий API: компонент, маршруты, адаптер или дизайн-систему, а не внутреннюю структуру папок.

export type ProductCardProps = ...

Держите типы props рядом с публичной точкой входа.

@org/catalog-contracts

Отдельный небольшой пакет для общих типов и схем, если их используют несколько приложений.

versioned remote URL

Публикуйте immutable-версии или хэши: host должен получать согласованный набор entry и чанков.

contract test

Проверяйте, что remote отдаёт ожидаемые экспорты и host умеет их загрузить.

Маршрутизация и состояние

host owns the shell

Host обычно владеет шапкой, аутентификацией, top-level routing и границей ошибок.

remote owns a feature

Remote владеет своими экранами, локальным состоянием и API конкретного домена.

route prefix: /catalog/*

Явно закрепите пространство URL за доменом remote.

custom events / callbacks

Для связи между приложениями предпочитайте узкие события и явные props глобальному store.

URL as shared state

Фильтры и выбранные сущности, важные для навигации, безопаснее держать в URL.

Частые поломки

ScriptExternalLoadError

Host не скачал remoteEntry.js: проверьте URL, CDN, CORS, CSP и доступность файла.

Shared module is not available

Не сходятся настройки shared, порядок загрузки или версии библиотек.

Invalid hook call

Чаще всего на странице оказались две копии React; проверьте singleton, lockfile и алиасы.

ChunkLoadError

Entry от одной версии пытается загрузить chunk от другой. Используйте atomic deploy и versioned assets.

remote works locally, fails in prod

Проверьте publicPath: 'auto', заголовки CDN, CORS и абсолютные пути к ассетам.

Перед production

fallback UI

У каждого remote есть загрузка, ошибка и деградированный режим.

observability

Добавьте имя remote и его версию в ошибки, логи и web-vitals.

independent deploy

Проверьте, что remote можно выкатить и откатить независимо, не ломая опубликованный контракт.

performance budget

Измеряйте лишние запросы, вес remote entry и время до интерактивности.

ownership

Заранее определите команду-владельца, SLA и путь эскалации для каждого remote.