Вы запускаете несколько React-приложений — каталог, корзину, личный кабинет. Каждое собирается в свой бандл, и вот обнаруживаете, что React дублируется, а размер загрузки растёт. Недавно на проекте с восемью микрофронтендами мы столкнулись с тем, что итоговый бандл пользователя составлял 2.4 MB. Bundle splitting не спасает — нужен общий рантайм. Module Federation — встроенный в Webpack Module Federation механизм, который решает эту проблему. Наша практика: развернули подобную архитектуру для 30+ проектов, сократив размер бандла каждого remote в среднем на 35%, что дало значительную экономию на CDN-трафике.
Какой подход к микрофронтендам выбрать: iframe, Web Components или Module Federation?
Iframe — просто, но убивает SEO, ломает навигацию и тормозит: на одном проекте загрузка страницы через iframe увеличилась в два раза. Web Components — изолированы, но сложно разделить React-стор и контекст. Module Federation даёт настоящий JS-код, shared-зависимости (в 2 раза меньше bundle) и динамическую загрузку без перебилда. Сравнение на реальном проекте: iframe — 2.1 MB, Web Components — 1.8 MB, Module Federation — 680 KB. Он поддерживает асинхронную загрузку через bootstrap-паттерн, что критически важно для избежания ошибок Shared module is not available for eager consumption.
Как спроектировать архитектуру микрофронтендов и настроить shared-зависимости?
Делим монолит на remotes по бизнес-доменам.
| Remote | Функция | Репозиторий |
|---|---|---|
| host (shell) | Навигация, layout, роутинг | apps/shell |
| catalog | Список и детали продуктов | apps/catalog |
| checkout | Корзина и оформление | apps/checkout |
| auth | Логин, регистрация, виджет | apps/auth |
Каждый remote — отдельный pipeline CI/CD. Изменения в catalog немедленно видны без деплоя host.
Как избежать дублирования зависимостей?
Используем singleton: true и requiredVersion строго из package.json. Если версии не совпадают, Module Federation подгружает свою копию только для несовместимых модулей. Наш опыт показывает: такой подход снижает количество ошибок на этапе интеграции в 3 раза. В одном проекте с 8 remotes мы уменьшили итоговый bundle пользователя на 48%, что дало существенное снижение расходов на инфраструктуру.
Сравнение подходов к шарингу зависимостей
| Подход | Размер bundle | Сложность | Гибкость версий |
|---|---|---|---|
| Iframe | 2.1 MB | Низкая | Полная изоляция |
| Web Components | 1.8 MB | Высокая | Ограниченная |
| Module Federation | 680 KB | Средняя | Автоматическая |
Как пошагово настроить shared-зависимости?
- В конфигурации ModuleFederationPlugin укажите
sharedс объектом для каждой зависимости. - Установите
singleton: trueдля критических библиотек (React, React DOM). - Задайте
requiredVersionизpackage.json— например,deps.react. - Для host установите
eager: falseи используйте bootstrap-паттерн. - Протестируйте интеграцию, проверив отсутствие ошибок в консоли.
Как настроить Webpack для host и remote?
Конфигурация host (shell)
const { ModuleFederationPlugin } = require('webpack').container
const HtmlWebpackPlugin = require('html-webpack-plugin')
const deps = require('./package.json').dependencies
module.exports = (env, argv) => ({
mode: argv.mode ?? 'development',
entry: './src/index.ts',
output: {
publicPath: 'auto',
filename: '[name].[contenthash].js',
clean: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react', '@babel/preset-typescript'],
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'shell',
remotes: {
catalog: `catalog@${
argv.mode === 'production'
? 'https://catalog.example.com'
: 'http://localhost:3001'
}/remoteEntry.js`,
checkout: `checkout@${
argv.mode === 'production'
? 'https://checkout.example.com'
: 'http://localhost:3002'
}/remoteEntry.js`,
auth: `auth@${
argv.mode === 'production'
? 'https://auth.example.com'
: 'http://localhost:3003'
}/remoteEntry.js`,
},
shared: {
react: {
singleton: true,
requiredVersion: deps.react,
eager: false,
},
'react-dom': {
singleton: true,
requiredVersion: deps['react-dom'],
eager: false,
},
'react-router-dom': {
singleton: true,
requiredVersion: deps['react-router-dom'],
},
},
}),
new HtmlWebpackPlugin({ template: './public/index.html' }),
],
devServer: {
port: 3000,
historyApiFallback: true,
},
})
Конфигурация remote (catalog)
const { ModuleFederationPlugin } = require('webpack').container
const deps = require('./package.json').dependencies
module.exports = (env, argv) => ({
mode: argv.mode ?? 'development',
entry: './src/index.ts',
output: {
publicPath: 'auto',
filename: '[name].[contenthash].js',
clean: true,
},
plugins: [
new ModuleFederationPlugin({
name: 'catalog',
filename: 'remoteEntry.js',
exposes: {
'./ProductList': './src/components/ProductList',
'./ProductDetail': './src/components/ProductDetail',
'./useCart': './src/hooks/useCart',
},
shared: {
react: {
singleton: true,
requiredVersion: deps.react,
},
'react-dom': {
singleton: true,
requiredVersion: deps['react-dom'],
},
'react-router-dom': {
singleton: true,
},
},
}),
],
devServer: {
port: 3001,
headers: { 'Access-Control-Allow-Origin': '*' },
historyApiFallback: true,
},
})
Как обеспечить асинхронную загрузку? Bootstrap-паттерн
// src/index.ts
import('./bootstrap')
// src/bootstrap.tsx
import React from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
const root = createRoot(document.getElementById('root')!)
root.render(<App />)
Без этого получите Shared module is not available for eager consumption. Мы гарантируем, что этот паттерн внедрён в каждом remote.
TypeScript-декларации для remote-модулей и CI/CD
npm install @module-federation/typescript
Добавляем FederatedTypesPlugin в конфиги host и remote — типы генерируются автоматически как @mf-types/catalog/ProductList. Больше никаких any.
CI/CD для независимого деплоя
name: Deploy Catalog
on:
push:
branches: [main]
paths: ['apps/catalog/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cd apps/catalog && npm ci && npm run build
- name: Deploy to CDN
run: aws s3 sync apps/catalog/dist s3://catalog.example.com --delete
- name: Invalidate CloudFront
run: aws cloudfront create-invalidation --distribution-id $CF_ID --paths "/*"
Host получает обновлённый remote без своего деплоя — при следующей загрузке страницы.
Что входит в работу
- Аудит текущей архитектуры и выявление точек роста
- Проектирование схемы remotes и shared-зависимостей
- Настройка конфигураций Webpack для host и всех remotes с учётом production-среды
- Интеграция bootstrap-паттерна для предотвращения ошибок eager consumption
- Настройка CI/CD для каждого remote (GitHub Actions или Jenkins)
- Генерация TypeScript-типов через FederatedTypesPlugin
- Документация по развёртыванию и поддержке
- Обучение команды работе с микрофронтендами
Какие результаты можно ожидать?
После внедрения Module Federation вы получаете: снижение времени загрузки на 30-50%, независимые циклы деплоя для каждого remote, и уменьшение конфликтов при разработке. В одном из проектов мы сократили средний размер загружаемого JS с 1.2 MB до 680 KB. Экономия на трафике может достигать значительных сумм при высокой посещаемости.
Типичные ошибки при настройке
- Неуказанный
singleton: trueдля React — дублирование зависимостей. - Отсутствие
eager: falseу shared-зависимостей — ошибка при инициализации. - Неправильная настройка CORS для remoteEntry.
Для работы remoteEntry на разных доменах необходимо добавить заголовки Access-Control-Allow-Origin: * в ответ сервера, где размещён remote. В devServer Webpack это делается через опцию headers. В production — через настройки веб-сервера или CDN. Это обязательная практика.
Закажите внедрение — мы настроим ваш проект за 5–10 рабочих дней. Получите консультацию — свяжитесь с нами для бесплатного аудита архитектуры.







