Micro-Frontends
Micro-Frontends — архитектурный подход, при котором крупный фронтенд разбивается на независимые приложения (micro apps), разрабатываемые и деплоящиеся отдельными командами.
Зачем нужно
Монолитный фронтенд при росте команды становится узким местом: долгие CI/CD, конфликты при мёрже, невозможность независимого деплоя фич. Micro-Frontends переносят принципы микросервисов на фронтенд: каждая команда владеет своим приложением, выбирает технологический стек и деплоит независимо. Это решение для организационной проблемы, а не технической — не применяйте его в малых командах.
Где используется
- Крупные e-commerce платформы (корзина, каталог, профиль — отдельные команды)
- Корпоративные порталы с десятками продуктов
- Постепенная миграция с legacy-монолита на современный стек
- Организации с несколькими независимыми командами на одном продукте
Подходы к интеграции
1. Build-time Integration
─ npm-пакеты для каждого micro app
─ Всё собирается в одном pipeline
─ Нет независимого деплоя — минус подхода
2. Run-time Integration (iframe)
─ Каждый micro app в отдельном iframe
─ Полная изоляция, но плохой UX и производительность
3. Run-time Integration (JavaScript)
─ Container загружает JS-бандлы micro app динамически
─ Module Federation (Webpack 5) — самый популярный способ
4. Web Components
─ Каждый micro app экспортирует custom element
─ Работает с любым фреймворком
Module Federation (Webpack 5)
// Приложение-хост (container): webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'container',
remotes: {
// Загружает продуктовый каталог с отдельного сервера
catalog: 'catalog@http://localhost:3001/remoteEntry.js',
cart: 'cart@http://localhost:3002/remoteEntry.js',
},
shared: ['react', 'react-dom'], // общие зависимости
}),
],
};
// Использование в container
const CatalogApp = React.lazy( => import('catalog/App'));
function Shell() {
return (
<Suspense fallback="Загрузка каталога...">
<CatalogApp />
</Suspense>
);
}
// Micro app (catalog): webpack.config.js
new ModuleFederationPlugin({
name: 'catalog',
filename: 'remoteEntry.js',
exposes: {
'./App': './src/App', // экспортирует App для container
},
shared: ['react', 'react-dom'],
});
Коммуникация между micro apps
// Через CustomEvent — слабая связанность
// Micro app 1: генерирует событие
window.dispatchEvent(new CustomEvent('cart:item-added', {
detail: { productId: '42', quantity: 1 }
}));
// Micro app 2: подписывается
window.addEventListener('cart:item-added', (event) => {
const { productId, quantity } = event.detail;
addToCart(productId, quantity);
});
Частые ошибки
- Micro-Frontends для малых команд — накладные расходы на координацию, DevOps и shared-зависимости не оправданы при 1-2 командах.
- Дублирование зависимостей — если React загружается несколько раз (разные версии), размер растёт и возникают конфликты; нужна настройка
sharedв Module Federation. - Отсутствие дизайн-системы — без общих UI-компонентов разные micro apps выглядят по-разному.
- Плохая UX при независимых деплоях — несовместимые версии micro apps могут вызвать runtime-ошибки.