Микро-фронтенды React с использованием Webpack Module Federation
Замените обходные решения с использованием iframe на Webpack 5 Module Federation, чтобы хост-приложения и удаленные React-приложения использовали один и тот же движок выполнения, могли развертываться независимо, но при этом оставались частью одного продукта.
Большие поверхности продукта редко являются единым фронтендом. Функции оформления заказа, панели управления, настройки и элементы интерфейса вокруг них часто принадлежат разным командам, у каждой из которых есть собственный список задач, технический долг и график выпуска. Такая структура обычно называется микро-фронтендами: независимо разрабатываемые фрагменты интерфейса, которые в совокупности представляют собой единый продукт, аналог микросервисов с клиентской стороны.
Долгое время инструментарий React для реализации такой архитектуры был неудобен. Компании либо использовали один огромный пакет SPA, либо встраивали отдельные приложения в iframes, соглашаясь с связанными с этим проблемами. Механизм Module Federation в Webpack 5 открыл третий путь: независимо разрабатываемые и развертываемые JavaScript-приложения, которые во время выполнения объединяются в один документ браузера. Понимание того, что делает эта функция и почему она заменила более старые решения, важно для всех, кто разрабатывает React-системы с участием нескольких команд.
Проблема до появления Module Federation
До появления Federation у команд, желавших независимой доставки фронтенда, был ограниченный выбор.
Стандартным решением был монолитный SPA: один репозиторий, одна цепочка обработки и одно развертывание. Такая модель подходит для небольшой группы. По мере расширения числа ответственных лиц возрастает количество проблем. Каждая функция использует одну и ту же сборку кода. Время компиляции увеличивается по мере роста объема кодовой базы. Регрессия в одной области может заблокировать процесс выпуска кода у другой команды. Согласование развертываний между множеством групп превращается в отдельную задачу управления проектом.
Другим широко распространенным решением были iFrame. Встраивание полноценного дочернего приложения в родительскую страницу обеспечивало истинную независимость развертывания, поэтому ими пользовались многие корпорации. Однако быстро накапливались связанные с этим недостатки:
- Изоляция абсолютна. Контексты стилей, DOM и JavaScript не смешиваются. Обмен состоянием, координация данных или применение единого языка проектирования между родительским и дочерним элементами превращаются в сложные инженерные задачи вместо простой передачи свойств.
- Зависимости дублируются. Каждый фрейм часто загружает собственные версии React, общих библиотек и CSS. Пользователи неоднократно скачивают одни и те же данные.
- Качество пользовательского опыта снижается. Прокрутка, фокусировка, изменение размера, глубокие ссылки и работа с историей переходов между фреймами требуют специальных решений, что делает их использование неудобным.
- SEO и доступность ухудшаются. Содержимое в фреймах труднее индексировать, а для средств помощи пользователям оно менее стабильно.
- Коммуникация осуществляется только через сообщения. Для обмена данными между фреймами используются метод
postMessageи ручно разработанные протоколы — нет общей памяти и общего контекста React.
Iframes решили проблему независимой доставки, но создали ещё худшую проблему чистой интеграции. Недоставало независимости при сборке и развертывании без потери пользовательского опыта, основанного на одном документе.
Что такое Module Federation?
Module Federation, введённый с Webpack 5, позволяет отдельно скомпилированным и развернутым JavaScript-приложениям обмениваться кодом во время выполнения, а не на этапе компиляции.
На практике можно запускать несколько приложений — от разных команд, процессов сборки и версионных линеек — которые всё равно объединяются в браузере в один продукт. Одно приложение предоставляет компонент, маршрут или вспомогательную функцию; другое использует их так, будто они находятся в том же пакете, без необходимости пересборки потребителя при изменении поставщика.
Именно такая композиция во время выполнения является сегодня основой для микро-фронтендов на React.
Как это работает: хосты, удаленные компоненты и общие зависимости
В федерации выделяются две роли:
- Хост загружает код, опубликованный в других местах. Часто это оболочка, которая подключает интерфейсы других команд.
- Удаленный компонент публикует модули для других: страницы, компоненты, хуки или утилиты.
Одно приложение может выполнять обе роли: предоставлять некоторые модули и в то же время использовать другие.
Удаленные компоненты указывают на экспортируемые элементы в конфигурации Webpack; хосты указывают, какие удаленные компоненты загружать и какие символы импортировать. Загрузка происходит в браузере по URL входной точки удаленного компонента. Для сборки хоста не требуется исходный код удаленного компонента — достаточно стабильной входной точки, которую можно загрузить при запуске приложения.
Общие зависимости дополняют картину. Когда и хост, и удаленный компонент нуждаются в React, Federation позволяет использовать одну инстанцию React вместо двух. Это устраняет дублирование в стиле iframe, при этом командам по-прежнему разрешается использовать разные версии при необходимости.
Module Federation против Iframes
Именно это сравнение стало причиной того, что многие команды отказались от iframes по мере совершенствования Federation. Вы сохраняете независимость развертывания, которая делала iframes привлекательными, не жертвуя качеством интеграции. Удаленные компоненты встраиваются в DOM хоста, используют один общий мир JavaScript и могут повторно использовать пакеты с провайдерами, состоянием и элементами дизайн-системы — что раньше было сложно или невозможно при работе через границы iframe.
Почему его используют крупные команды
Небольшие проекты редко нуждаются в такой сложной инфраструктуре. Организации с множеством команд фронтенда используют Federation для устранения структурных проблем:
- Независимая развертка. Отдельный сервер может внедрить исправление, не пересоздавая artefакты всех остальных команд.
- Автономия команд. Каждая группа сохраняет собственный ритм работы, систему CI и, в определённых пределах, выбор инструментов.
- Более быстрая сборка. Наличие отдельных серверов означает, что небольшие изменения не требуют пересборки всей системы.
- Поэтапная модернизация. Существующие структуры могут постепенно добавлять новые серверы вместо одномоментного перехода на современную версию.
- Гибкость стека технологий. Самое простое — использовать общую фреймворк-среду, но команды иногда соединяют разные версии или даже разные фреймворки через механизмы Federation.
Практические примеры использования
На сайтах электронной коммерции команды, отвечающие за каталоги, процесс оформления заказов и управление аккаунтами, часто используют отдельные инструменты управления. Продукты типа SaaS предоставляют виджеты для панели управления или панели настроек от команд, разрабатывающих функции, без необходимости изменения основной структуры при каждой правке. При миграции части устаревшего SPA выделяются в отдельные компоненты, при этом старая версия продолжает работать.
Краткий обзор ключевых преимуществ
Преимущества подхода федерации сводятся к нескольким пунктам: возможность независимой развертки, совместная среда выполнения, которая исключает дублирование библиотек и проблемы с обменом сообщениями между приложениями, а также пользовательский интерфейс, сохраняющий ощущение единого приложения. Этот подход обеспечивает обещанную автономность без дополнительных сложностей с интеграцией и снижения производительности.
Заключение
Переход от iframes к Module Federation является частью более высокого уровня зрелости архитектуры фронтенда: независимость развертывания и целостный пользовательский интерфейс больше не обязательно должны противоречить друг другу. Webpack 5 сделал такое сочетание возможным для организаций, активно использующих React и уже не могущих обходиться одним бандлом. По мере роста популярности этого подхода и с появлением инструментов вроде Rspack и Module Federation 2.0, расширяющих концепции совместного использования рантайма, понимание причин такого сдвига помогает тем, кто разрабатывает крупные React-системы, осознанно определять границы ответственности, вместо того чтобы автоматически использовать iframes или постоянно растущий монолит.
Попробуйте сами
Минимальный пример хоста/удаленного компонента доступен по адресу react_module_federation.
Клонируйте его локально:
git clone https://github.com/ModithaM/react_module_federation.git
cd react_module_federation
Сначала запустите удаленный компонент, чтобы его входная точка начала обслуживание до того, как хост запросит модули:
cd remote
npm install
npm start
В другом терминале запустите хост:
cd host
npm install
npm start
Откройте хост в браузере; он должен загружать удалённые компоненты во время выполнения и демонстрировать описанные выше взаимосвязи. Порядок имеет значение: хост, запущенный отдельно, не имеет чего загружать до тех пор, пока удалённый компонент не будет доступен, что служит полезным напоминанием о том, что независимость Federation по-прежнему зависит от доступности удалённых компонентов при запуске оболочки.