Микрофронтенды переносят идею микросервисов на слой интерфейса. Вместо единого монолитного приложения фронтенд разбивается на меньшие самостоятельные приложения, которые разрабатываются, тестируются и выкладываются по отдельности. Каждый микрофронтенд владеет своей предметной областью и может быть построен на другой технологии, другой командой, в другом ритме выпуска.
Эта архитектура выросла из тех же трудностей, что породили микросервисы на стороне сервера. По мере усложнения веб-приложений монолитные фронтенды становились тяжёлыми в сопровождении, медленными в сборке и рискованными при выкладке. Одно изменение в любом месте кода требовало пересобрать и выложить всё приложение целиком, что тормозило команды и порождало трение между группами, желавшими двигаться с разной скоростью.
Что такое микрофронтенды?
Архитектура микрофронтендов делит веб-приложение на функциональные срезы, каждым из которых владеет самостоятельная команда. Команда отвечает за все слои своего среза: компоненты интерфейса, бизнес-логику, получение данных и связь с сервером. Пользователь видит единое цельное приложение, но за кулисами оно собрано из нескольких меньших приложений, работающих в одном окне браузера.
Такое разбиение следует принципам предметно-ориентированного проектирования. Каждый микрофронтенд соответствует ограниченному контексту — логической границе вокруг конкретной бизнес-возможности. Оформление заказа, каталог товаров, профиль пользователя и поиск могут быть отдельными микрофронтендами, принадлежащими разным командам.
Ключевое отличие микрофронтендов от простого разбиения кода на модули в том, что микрофронтенды независимы при сборке и выкладке. У каждого свой конвейер, свой репозиторий, свои тесты и свой график выпуска. Эта независимость и даёт архитектуре её преимущества — и она же создаёт её трудности.
Микрофронтенд — это не библиотека компонентов и не набор общих утилит. Это самостоятельное приложение, которое встраивается во время выполнения в более крупное приложение. Это различие существенно для понимания и сильных сторон архитектуры, и её цены.
Module Federation в Webpack 5
Module Federation — самый распространённый подход в экосистемах React и Angular. Появившись в Webpack 5, он позволяет одному JavaScript-приложению во время выполнения загружать код из другого приложения. Загруженный код исполняется в контексте приложения-хозяина и разделяет с ним зависимости, чтобы такие библиотеки, как React или Vue, не дублировались.
Механизм состоит в том, что удалённое приложение открывает наружу определённые модули, а хозяин их импортирует. Удалённое объявляет, какие модули доступны, а хозяин обращается к ним так, будто это локальные импорты. Webpack берёт на себя асинхронную загрузку, устранение дублирующихся зависимостей и разрешение версий на этапе сборки.
Совместное использование зависимостей — важнейшая возможность. Когда хозяин и удалённое приложение используют одну библиотеку, Webpack следит, чтобы в браузер попала лишь одна её копия. Это снимает потери, которые дали бы несколько копий React, Lodash или других крупных библиотек. Режим единственного экземпляра также гарантирует, что общее состояние — хранилище Redux или контекст React — действительно разделяется между микрофронтендами.
// webpack.config.js - Remote application exposing a module
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "checkout",
filename: "remoteEntry.js",
exposes: {
"./CheckoutApp": "./src/bootstrap",
},
shared: {
react: { singleton: true, requiredVersion: "^18.0.0" },
"react-dom": { singleton: true, requiredVersion: "^18.0.0" },
},
}),
],
};
// webpack.config.js - Host application consuming the remote
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "shell",
remotes: {
checkout: "checkout@http://localhost:3001/remoteEntry.js",
},
shared: {
react: { singleton: true, requiredVersion: "^18.0.0" },
"react-dom": { singleton: true, requiredVersion: "^18.0.0" },
},
}),
],
};
// Lazy loading the remote module in the host
const CheckoutApp = React.lazy(() => import("checkout/CheckoutApp"));
function Shell() {
return (
<Suspense fallback={<Spinner />}>
<CheckoutApp />
</Suspense>
);
}Хозяин загружает файл точки входа удалённого приложения, как только пользователь переходит на маршрут, где нужен микрофронтенд оформления заказа. Этот файл — небольшой JavaScript, который Webpack создаёт автоматически: он содержит перечень всех открытых модулей и адреса, где их искать. Когда хозяин запрашивает конкретный модуль, Webpack скачивает нужный фрагмент и исполняет его в контексте общих зависимостей.
Важно, что хозяин и удалённое приложение должны сойтись на версиях общих зависимостей. Если удалённому нужен React 18.2, а у хозяина только React 18.0, режим единственного экземпляра не сработает, пока версии не окажутся совместимыми. Поле requiredVersion принимает диапазоны семантического версионирования, что даёт запас гибкости и одновременно защищает от несовместимости.
Интеграция через iframe
До Module Federation и современных приёмов iframe был исходным способом. Iframe встраивает в страницу совершенно отдельный HTML-документ. У этого документа свой контекст JavaScript, своя область видимости CSS и своё дерево DOM. Такая изоляция — одновременно и сила, и слабость подхода.
Iframe даёт самые надёжные гарантии изоляции среди всех приёмов. Конфликтов CSS не возникает, потому что у каждого свой документ. Столкновений JavaScript не бывает, потому что у каждого своя глобальная область. Ни один микрофронтенд не изменит по ошибке состояние другого, поскольку деревья DOM полностью разделены. Утечка памяти в одном не обрушит другой.
За эти гарантии приходится дорого платить. Iframe тяжёл. Каждый загружает целый HTML-документ со всеми его ресурсами CSS и JavaScript. Браузер считает каждый отдельным контекстом просмотра, а значит — больше памяти, больше сетевых запросов и больше работы по отрисовке. Если встроить десять микрофронтендов в iframe, браузер по сути загрузит одиннадцать страниц.
Обмен данными между iframe и содержащей его страницей требует postMessage — механизма асинхронного и ограниченного сериализуемыми данными. Через границу нельзя передать функции, экземпляры классов или ссылки на DOM. Из-за этого iframe плохо подходит для микрофронтендов, которым нужна тесная связь: скажем, для формы оплаты, которой требуется состояние корзины со страницы-хозяина.
Страдает и доступность. Экранным дикторам и другим вспомогательным технологиям обычно тяжело даются вложенные контексты просмотра. Перемещение с клавиатуры через границы iframe работает непоследовательно. Поиск по странице не пересекает эти границы, а история просмотра считает каждый внутренний переход отдельным сеансом.
Iframe нужны прежде всего для встраивания стороннего содержимого, где изоляция важнее всего, а связность минимальна. Они плохо годятся для сборки цельного впечатления, когда микрофронтендам нужно делить состояние, согласовывать переходы и складываться в единую визуальную поверхность.
Single-spa и другие каркасы оркестровки
Single-spa — это JavaScript-каркас, который управляет несколькими микрофронтендами на одной странице. Он ведёт жизненный цикл каждого: монтирует, когда пользователь приходит на нужный маршрут, размонтирует, когда тот уходит, и держит неактивные в памяти, чтобы быстро вернуть их обратно. Он не зависит от каркаса и поддерживает React, Angular, Vue, Svelte и чистый JavaScript.
Каждый микрофронтенд регистрируется в single-spa как приложение с функциями жизненного цикла: bootstrap, mount, unmount и, по желанию, update. Корень single-spa управляет маршрутизацией и по шаблонам URL решает, какие приложения активны. Когда URL совпадает с функцией активности зарегистрированного приложения, single-spa монтирует его и размонтирует те, что перестали быть активными.
Single-spa решает одну из самых неприятных задач — сосуществование каркасов. Когда два микрофронтенда собраны на разных версиях одного каркаса или вовсе на разных каркасах, single-spa обеспечивает их совместную работу на одной странице без конфликтов. Он добивается этого, вклиниваясь в точки жизненного цикла и изолируя глобальное состояние каждого приложения.
Среди других подходов — Piral с моделью расширений, где микрофронтенды подгружаются как модули из службы раздачи, и Open Components, ориентированный на сборку на стороне сервера. Есть и путь веб-компонентов, когда каждый микрофронтенд заворачивается в пользовательский элемент и регистрируется в соответствующем интерфейсе браузера. Веб-компоненты дают встроенное разграничение HTML, CSS и JavaScript и складываются декларативно в HTML-шаблонах.
Выбор зависит от вашего набора технологий, устройства команд и требований к быстродействию. Module Federation — лучший выбор для тех, кто уже на Webpack. Single-spa оправдан в смешанных архитектурах с разными каркасами. Веб-компоненты подходят организациям, которые хотят задать границы независимо от каркаса. Iframe уместны только для встраивания стороннего содержимого.
Общие библиотеки компонентов и системы оформления
Частое опасение — потеря визуальной согласованности. Если каждая команда строит свой интерфейс сама по себе, пользователь, перемещаясь по приложению, встретит разные кнопки, шрифты и раскладки. Ответ на это — общая библиотека компонентов или система оформления, которую используют все микрофронтенды.
Общая библиотека обычно содержит представленческие компоненты: кнопки, поля ввода, диалоговые окна и элементы навигации. Они чисто визуальны и не несут бизнес-логики. Они принимают свойства для вариантов оформления, подписей и обработчиков событий, но не получают данные, не ведут состояние и не реализуют поведение предметной области. Такое разделение сохраняет библиотеку устойчивой и не даёт ей стать узким местом для скорости команд.
Версионирование библиотеки требует дисциплины. Опубликованная как пакет npm, она позволяет каждому микрофронтенду закрепить версию и обновляться в своём ритме. Это даёт самостоятельность, но может привести к расхождению версий, когда один и тот же компонент выглядит по-разному в разных микрофронтендах. Набор тестов визуальной регрессии для библиотеки помогает выявить такие расхождения до выхода в бой.
Другой путь — раздавать систему оформления как зависимость времени выполнения. Библиотека публикуется как самостоятельное приложение и загружается каждым микрофронтендом при запуске. Тогда все всегда используют последнюю версию каждого компонента, и расхождение исчезает. Взамен обновление системы теперь требует выкладки, а любое несовместимое изменение затрагивает все микрофронтенды разом.
Маркеры оформления как наименьший общий знаменатель
Маркеры оформления — именованные значения для цветов, отступов, шрифтов и теней — более лёгкая замена полноценной библиотеке. Каждый микрофронтенд реализует свои компоненты сам, но обращается к одному и тому же набору маркеров. Это даёт свободу в реализации при сохранении визуальной согласованности. Маркеры можно раздавать как пользовательские свойства CSS: их легко переопределять, и они не требуют никаких сборочных средств.
Обмен данными между микрофронтендами
Микрофронтендам нужно общаться. Оформлению заказа надо знать, что пользователь положил в корзину из каталога. Заголовку страницы надо обновить значок, когда микрофронтенд уведомлений получит новое. Микрофронтенду входа надо сообщить всем остальным, что пользователь вошёл или вышел.
Простейший механизм — общая шина событий. Каждый микрофронтенд публикует события в общий канал и подписывается на события других. Шину обычно делают как источник событий, прикреплённый к объекту window или переданный оболочкой. События несут тип и полезную нагрузку; подписчики отбирают их по типу.
// Shared event bus - shell application
// Each micro frontend receives this bus as part of its initialization.
type BusEvent = {
type: string;
payload: unknown;
};
type Listener = (event: BusEvent) => void;
class EventBus {
private listeners: Map<string, Listener[]> = new Map();
on(type: string, listener: Listener): () => void {
if (!this.listeners.has(type)) {
this.listeners.set(type, []);
}
this.listeners.get(type)!.push(listener);
return () => this.off(type, listener);
}
off(type: string, listener: Listener): void {
const listeners = this.listeners.get(type);
if (listeners) {
this.listeners.set(
type,
listeners.filter((l) => l !== listener)
);
}
}
emit(type: string, payload: unknown): void {
this.listeners.get(type)?.forEach((listener) => {
listener({ type, payload });
});
}
}
// Usage in a micro frontend
export function init(bus: EventBus) {
bus.on("item:added-to-cart", (event) => {
updateCartBadge(event.payload.quantity);
});
bus.emit("user:logged-in", { userId: "abc-123", name: "Jane" });
}Для более сложных задач общее хранилище состояния обычно лучше шины событий. Хранилище Redux или Zustand, размещённое в оболочке, можно передать каждому микрофронтенду. Каждый читает из него состояние, пересекающее границы областей, и пишет в собственное локальное хранилище то, что относится только к его области. Связанность остаётся слабой, и при этом есть единый источник истины для общих данных: текущий пользователь, содержимое корзины, активная навигация.
Слой обмена данными нужно продумать и описать явно. Командам придётся договориться об именах событий, формате нагрузки и границе между общим и локальным состоянием. Без такой договорённости микрофронтенды обзаводятся неявными зависимостями от внутреннего состояния друг друга, и получается распределённый монолит — со всеми трудностями микрофронтендов и без единого их преимущества.
Стратегии маршрутизации
Маршрутизация должна ответить на два вопроса: какому микрофронтенду принадлежит текущий маршрут и как устроены переходы между ними. Ответы зависят от того, используете ли вы централизованный маршрутизатор в оболочке, распределённый подход или смешанную стратегию.
При централизованной маршрутизации приложение-оболочка владеет маршрутизатором верхнего уровня. Оно задаёт карту маршрутов, определяет, какой микрофронтенд монтировать для каждого шаблона URL, и передаёт ему параметры. У каждого микрофронтенда есть свой внутренний маршрутизатор для перемещения внутри его области. Оболочка отвечает за переходы между областями, микрофронтенды — за пути внутри себя.
При распределённой маршрутизации маршруты принадлежат самим микрофронтендам. Оболочка по-прежнему сопоставляет URL с микрофронтендом на верхнем уровне, но каждый сам ведёт свои подмаршруты и внутренние переходы. Библиотека навигации в оболочке согласует изменения истории и следит, чтобы адресная строка отражала состояние всего приложения, а не только активного микрофронтенда.
При маршрутизации через события переходы согласует шина. Когда микрофронтенду нужно перейти на маршрут, принадлежащий другому, он испускает событие перехода. Оболочка его слышит и выполняет переход, отчего монтируется целевой микрофронтенд. Так вопросы маршрутизации выносятся за пределы микрофронтендов, а логика собирается в оболочке.
- Централизованная маршрутизация: оболочка владеет картой маршрутов, микрофронтенды ведут только внутренние переходы. Хороша для небольших команд с простыми границами.
- Распределённая маршрутизация: каждый микрофронтенд ведёт свои подмаршруты. Хороша для крупных команд с чётко разделёнными областями.
- Маршрутизация через события: переходы согласуются общей шиной. Хороша для смешанных архитектур с разными каркасами.
- Смешанная маршрутизация: оболочка ведёт маршруты областей верхнего уровня, микрофронтенды — подмаршруты. Хороша для большинства боевых приложений.
Выкладка и версионирование
Независимость выкладки — главная причина переходить на микрофронтенды. Каждая команда должна уметь выложить свой, не согласовываясь с остальными и не рискуя устойчивостью целого. Для этого нужно продуманно устроить конвейер, схему размещения и порядок версионирования.
Простейшая модель — раздельное размещение. Каждый микрофронтенд выкладывается на свой адрес или в своё хранилище. Оболочка загружает его оттуда во время выполнения. Эта модель даёт наибольшую независимость, ведь команда управляет своей инфраструктурой, своим конвейером и своим порядком отката. Оболочку не нужно перевыкладывать при обновлении микрофронтенда, поскольку она динамически берёт последнюю версию.
Раздельное размещение приносит новую трудность — согласование выкладок ради обратной совместимости. Если микрофронтенд оформления заказа ожидает от оболочки определённый набор свойств, а очередная выкладка оболочки его меняет, оформление заказа ломается, пока не обновится тоже. Выход — версионировать договор о встраивании, то есть обычно свойства, передаваемые оболочкой, и отмечать несовместимые изменения по правилам семантического версионирования.
Постепенные выкладки и проверка на малой доле пользователей становятся здесь проще, ведь каждый микрофронтенд выкладывается сам по себе. Команда может выпустить новую версию для пяти процентов пользователей, посмотреть на частоту ошибок и показатели быстродействия и постепенно расширять охват, если всё в порядке. При появлении неполадки она откатывает только свой микрофронтенд, не трогая остальное.
Закрепление версии из оболочки — запасной выход. Если выкладка принесла несовместимое изменение, проскочившее мимо тестов, оболочка может закрепить прежнюю версию и вернуть устойчивость, пока команда разбирается. Обычно это делается через файл настроек или переменную среды, сопоставляющую каждому микрофронтенду уже выложенную версию.
Единый репозиторий или отдельные
Устройство репозиториев — спорная тема во фронтенд-сообществе. Доводы и за единый репозиторий, и за отдельные заслуживают внимания, а правильный выбор зависит от размера команд, зрелости организации и предпочтений в инструментах.
Единый репозиторий хранит все микрофронтенды в одном месте, разложенные по папкам. У каждого свой package.json, своя сборочная настройка и свой каталог. Такой подход опирается на средства вроде Turborepo, Nx, Lerna или рабочих пространств pnpm, чтобы вести зависимости, запускать сборки и распределять задачи между микрофронтендами.
- Общая настройка инструментов проста: один ESLint, один TypeScript, один Prettier для всех.
- Сквозные переработки кода даются легче, ведь код всех микрофронтендов лежит в одном месте.
- Управление зависимостями централизовано, что снижает риск разнобоя версий.
- Становятся возможны неделимые фиксации через несколько микрофронтендов, когда изменение затрагивает сразу несколько областей.
Подход с несколькими репозиториями помещает каждый микрофронтенд в собственный, со своим конвейером и своими настройками. Команды сохраняют полную самостоятельность в выборе технологий и порядка выпуска. Команда, желающая перейти с React на Preact, может сделать это без согласований, лишь бы её микрофронтенд по-прежнему правильно отображался в оболочке.
- Команды полностью самостоятельны в своём порядке работы и наборе инструментов.
- Репозиторий остаётся небольшим: быстрые клонирования и скорые конвейеры.
- Не нужны особые средства для единого репозитория: хватает обычных приёмов Git и реестров npm.
- Несовместимое изменение в одном микрофронтенде не обрушит сборку другого.
Отраслевая мода склоняется к единому репозиторию, особенно там, где есть общая система оформления или общий набор утилит. Цена согласования изменений между несколькими репозиториями обычно перевешивает выигрыш в самостоятельности, особенно у команд, работающих рядом и на схожих технологиях. И всё же для организаций с разбросанными командами на разных каркасах отдельные репозитории остаются лучшим выбором.
Вопросы быстродействия
Микрофронтенды обходятся дороже по быстродействию, чем монолитное приложение. Каждый загружает свой пакет JavaScript, свой CSS и, возможно, своё окружение каркаса. Браузеру приходится скачать, разобрать и исполнить больше кода. Объём передаваемых байтов растёт, а время до готовности страницы при первой загрузке удлиняется.
Разделение зависимостей в Module Federation смягчает эту цену, обеспечивая однократную загрузку библиотеки. Но прикладной код — компоненты, утилиты и бизнес-логика каждого микрофронтенда — не разделяется. Если за сеанс пользователь пройдёт через три разных микрофронтенда, он скачает код всех трёх, даже если работал только с одним.
Разделение кода внутри каждого микрофронтенда обязательно. Каждый должен лениво подгружать свои маршруты, тяжёлые компоненты и сторонние библиотеки. Микрофронтенд панели управления, включающий библиотеку графиков, не должен загружать её, пока пользователь не дойдёт до страницы, где график рисуется. Это та же практика, что и в монолитных приложениях, применённая внутри каждой границы.
Предварительная загрузка — ценный приём. Когда пользователь заходит на маршрут микрофронтенда оформления заказа, оболочка может предположить, что дальше будет подтверждение заказа, и начать фоново получать его ресурсы. Эта стратегия должна опираться на настоящие данные о поведении, а не на догадки о путях перемещения.
Критический путь отрисовки нужно беречь. Оболочка должна появляться так же быстро, как монолитное приложение, а значит — быть лёгкой: мало JavaScript, мало CSS, мало зависимостей. Она отвечает за первую отрисовку, и медленные микрофронтенды не должны её задерживать. Каждый следует загружать асинхронно и показывать состояние загрузки, пока он не готов.
Ограничения по быстродействию надо задавать на каждый микрофронтенд, а не только на приложение целиком. Каждая команда должна знать предельный размер своего пакета, предельное время до готовности и предельный расход памяти. Их превышение должно ронять конвейер — так же, как это происходило бы в монолитном приложении.
Тестирование микрофронтендов
Тестирование этой архитектуры идёт на трёх уровнях: каждый микрофронтенд по отдельности, их связка и собранное приложение целиком. У каждого уровня свои средства, свои цели и свои ответственные.
Модульные и компонентные тесты внутри микрофронтенда следуют тем же правилам, что и в любом фронтенд-приложении. Каждая команда тестирует свой, и тесты идут в её собственном конвейере. Разница лишь в том, что тестировать стоит, считая оболочку и соседние микрофронтенды ненадёжными: на всякий случай проверять, что свой микрофронтенд изящно деградирует, когда оболочка передаёт неожиданные свойства или ожидаемое событие не приходит.
Связка — самый сложный уровень. Тест должен одновременно загрузить оболочку и несколько микрофронтендов, воспроизвести взаимодействия через границы и проверить, что собранное поведение верно. Здесь хорошо показывают себя Cypress и Playwright, потому что работают в настоящем браузере и управляют приложением целиком.
Действенный приём — держать в тестовой среде выкладку, похожую на боевую: каждый микрофронтенд на своём адресе, а оболочка настроена их загружать. Набор тестов идёт против этой выкладки и проходит настоящие пользовательские пути, пересекающие границы. Так всплывают неполадки, невидимые в изолированных тестах: сбои согласования, когда один микрофронтенд ещё не закончил запуск, а другой уже пытается с ним говорить, или сдвиги раскладки, когда изменение CSS в одном смещает разметку в другом.
Тесты визуальной регрессии здесь особенно важны. У общей системы оформления должен быть свой набор. У каждого микрофронтенда — свой для его страниц. А у собранного приложения — свой для ключевых пользовательских путей. Percy, Chromatic или Loki встраиваются в конвейер и находят расхождения сами.
Когда микрофронтенды применять НЕ стоит
Микрофронтенды — не та архитектура, что подходит всякому проекту. Приносимая ими сложность — эксплуатационная цена, цена быстродействия, потребность в согласовании и трудность разбора неполадок — оправдана лишь определёнными организационными нуждами. Применить их там, где нужды нет, значит породить трение и замедлить разработку без отдачи.
Небольшой команде, делающей одно приложение, они не нужны. Эта архитектура задумана для организаций с несколькими командами, каждая из которых владеет своей областью. Если весь ваш фронтенд посилен трём-четырём людям, монолитное приложение с хорошо разложенными модулями будет продуктивнее, быстрее в сборке и проще в сопровождении.
Приложение с сильно связанными областями — плохой кандидат. Если каждая возможность переплетена со всеми прочими, если каталог, корзина и оформление заказа сцеплены так, что чисто не разделяются, их разрезание заставит вас построить сложные слои обмена данными, повторяющие тот прямой доступ, что был в монолите. Это и есть противообразец распределённого монолита.
Организации без эксплуатационной зрелости придётся тяжело. Эта архитектура требует налаженной эксплуатации, автоматических тестов, наблюдения и работы с происшествиями. Каждая команда должна уметь выкладываться сама и быстро откатываться. Если этих основ нет, лучше сперва вложиться в них в рамках монолитного приложения.
Приложения, критичные к быстродействию, с жёсткими требованиями ко времени загрузки, могут не вынести этой цены. Если важна каждая миллисекунда — скажем, в торговой панели реального времени или в видеоинтерфейсе, — лишние сетевые запросы и лишнее время разбора JavaScript способны вывести вас за рамки бюджета.
- В вашей фронтенд-команде меньше четырёх человек.
- В приложении меньше пяти чётко различимых границ областей.
- У команды нет опыта с микросервисами или распределёнными системами.
- В организации нет автоматической непрерывной интеграции и наблюдения.
- У приложения жёсткие ограничения по быстродействию, которые и так трудно соблюдать.
- Возможности сильно связаны и чисто не делятся на области.
Микрофронтенды — это организационное решение, принимающее вид технической архитектуры. Если вам не нужна та организационная независимость, что они дают — разные команды, разные ритмы, разные технические решения, — техническая цена себя не окупает.
Заключение
Микрофронтенды — мощный образец для организаций, которым нужно масштабировать фронтенд-разработку между несколькими командами. Архитектура даёт настоящие преимущества: независимую выкладку, самостоятельность команд, свободу в технологиях и возможность выпускать в разном ритме. Эти преимущества вещественны и измеримы, когда архитектура приложена к подходящей задаче.
Залог успеха — относиться к ним прежде всего как к организационному решению и лишь затем как к техническому. Архитектура существует, чтобы сделать команды независимыми, а не чтобы породить изящно развязанный код. Каждое техническое решение — Module Federation или iframe, единый репозиторий или несколько, шина событий или общее хранилище — должно служить росту скорости команд без потери цельности впечатления.
Начинайте с малого. Возьмите один микрофронтенд с ясной границей области и команду, которой хочется вести его самостоятельно. Покажите, что конвейер работает, что быстродействие держится, что команда поставляет быстрее. Затем расширяйте постепенно. Тут нет правила «всё или ничего»: смешанный подход — один-два микрофронтенда внутри в остальном монолитного приложения — часто оказывается лучшей отправной точкой.
Самая частая ошибка — преждевременное обобщение. Команды строят замысловатые слои оркестровки, системы общего состояния и сквозную инфраструктуру, ещё не поняв своих настоящих нужд. Начните с простейшей возможной связки — оболочки, загружающей микрофронтенды через тег script или через Module Federation, — и добавляйте сложность лишь тогда, когда простое явно перестанет справляться. Верная мера обобщения выявляется в настоящем использовании, а не в проектировании заранее.
Module Federation сделал микрофронтенды доступнее, чем когда-либо, но главные вопросы остаются организационными. Нужно ли вашим командам выкладываться независимо? Потянет ли ваша организация эксплуатационную сложность? Делятся ли ваши области чисто? Тот, кто ответит «да», найдёт их преобразующими. Тот, кто ответит «нет», найдёт их раздражающими. Сама архитектура нейтральна: её ценность целиком зависит от условий, в которых она применяется.