← Назад к вопросам
Должны ли микрофронтенды использовать общие данные
1.0 Junior🔥 181 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Общие данные в микрофронтендах
Ответ зависит от архитектуры, но в большинстве случаев микрофронтенды должны МИНИМИЗИРОВАТЬ общие данные, а не избегать их полностью.
Проблема совместного использования данных
// ❌ Плохая архитектура - слишком тесная связь
// host-app.js
const globalStore = new Store();
// micro-app-1 и micro-app-2 используют одно хранилище
MicroApp1.init(globalStore);
MicroApp2.init(globalStore);
// Проблемы:
// 1. Зависимость между микроприложениями
// 2. Сложный debug когда много приложений
// 3. Версионирование store сложнее
// 4. Нельзя независимо развёртывать
// 5. Конфликты в названиях данных
Принцип независимости микрофронтендов
Микрофронтенды должны быть максимально независимыми:
// ✅ Хорошая архитектура - независимые приложения
// micro-app-1 имеет свой store
const app1Store = new MobXStore();
app1.init(app1Store);
// micro-app-2 имеет свой store
const app2Store = new ZustandStore();
app2.init(app2Store);
// Host координирует между ними через события
host.listen('app1:user-updated', (userData) => {
host.notify('app2:user-changed', userData);
});
Когда нужны общие данные
1. Аутентификация и авторизация
// ✅ Разумно делать общим
// Все микроприложения нужно знать о пользователе
// host-app.js
const authService = new AuthService();
const user = await authService.getCurrentUser();
MicroApp1.init({ user, authService });
MicroApp2.init({ user, authService });
// micro-app-1.js
function UserProfile({ user, authService }) {
if (!user.isAuthenticated) {
return <LoginForm onLogin={() => authService.logout()} />;
}
return <Profile user={user} />;
}
2. Глобальные настройки и конфигурация
// ✅ Разумно делать общим
// Конфигурация должна быть единой
const config = {
apiUrl: process.env.REACT_APP_API_URL,
environment: process.env.NODE_ENV,
theme: 'dark',
locale: 'en-US'
};
MicroApp1.init(config);
MicroApp2.init(config);
// Каждое приложение использует одну конфигурацию
3. Уведомления и события (осторожно)
// ⚠️ Можно делать общим, но через слабую связь
// Event Bus для общения между микроприложениями
class EventBus {
private listeners = {};
subscribe(eventName, callback) {
if (!this.listeners[eventName]) {
this.listeners[eventName] = [];
}
this.listeners[eventName].push(callback);
}
publish(eventName, data) {
if (this.listeners[eventName]) {
this.listeners[eventName].forEach(cb => cb(data));
}
}
}
const bus = new EventBus();
// micro-app-1 публикует событие
bus.publish('user:profile-updated', { userId: 123, name: 'John' });
// micro-app-2 слушает событие
bus.subscribe('user:profile-updated', (userData) => {
updateUserInLocalCache(userData);
});
Когда НЕ нужны общие данные
1. Доменные данные (бизнес-логика)
// ❌ Никогда не делай общим
// micro-app-orders должен иметь свой state
class OrdersStore {
orders = [];
selectedOrder = null;
async fetchOrders() {
this.orders = await fetch('/api/orders').then(r => r.json());
}
selectOrder(id) {
this.selectedOrder = this.orders.find(o => o.id === id);
}
}
// micro-app-products должен иметь свой state
class ProductsStore {
products = [];
cart = [];
async fetchProducts() {
this.products = await fetch('/api/products').then(r => r.json());
}
addToCart(productId) {
const product = this.products.find(p => p.id === productId);
this.cart.push(product);
}
}
// ❌ Неправильно
const sharedState = { orders: [], products: [], cart: [] };
ordersApp.init(sharedState);
productsApp.init(sharedState);
// ✅ Правильно
const ordersStore = new OrdersStore();
const productsStore = new ProductsStore();
ordersApp.init(ordersStore);
productsApp.init(productsStore);
2. Специфичные UI состояния
// ❌ Не делай общим
const sharedUI = {
modal1IsOpen: false,
sidebarCollapsed: false,
selectedTab: 'overview',
theme: 'dark'
};
// ✅ Каждое приложение управляет своим UI
function App1() {
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedTab, setSelectedTab] = useState('overview');
return (
<div>
{isModalOpen && <Modal onClose={() => setIsModalOpen(false)} />}
<Tabs value={selectedTab} onChange={setSelectedTab} />
</div>
);
}
Правильная архитектура
// host-app.js
function HostApp() {
const [user, setUser] = useState(null);
const [notifications, setNotifications] = useState([]);
// Слой данных - аутентификация и глобальные события
useEffect(() => {
// Загружаем пользователя один раз
authService.getCurrentUser().then(setUser);
// Слушаем уведомления
notificationService.subscribe('*', (notification) => {
setNotifications(prev => [...prev, notification]);
});
}, []);
return (
<div>
{/* Передаём только НЕОБХОДИМЫЕ данные */}
<MicroApp1
user={user}
authService={authService}
config={appConfig}
onNotify={(type, data) => notificationService.publish(type, data)}
/>
<MicroApp2
user={user}
authService={authService}
config={appConfig}
onNotify={(type, data) => notificationService.publish(type, data)}
/>
{/* Уведомления - глобальный слой */}
<NotificationCenter notifications={notifications} />
</div>
);
}
// MicroApp1
function MicroApp1({ user, config, onNotify }) {
// Свой state для доменных данных
const [ordersStore] = useState(() => new OrdersStore(config.apiUrl));
const handleOrderCreated = (order) => {
// Уведомляем других об изменении
onNotify('order:created', order);
};
return (
<div>
<UserInfo user={user} />
<OrdersList
store={ordersStore}
onOrderCreated={handleOrderCreated}
/>
</div>
);
}
Паттерны коммуникации между микрофронтендами
// 1. Props drilling (для критичных данных)
function App() {
const user = useAuthUser();
return <MicroApp user={user} />; // Явная передача
}
// 2. Event-driven (для слабой связи)
const eventBus = new EventEmitter();
// Приложение A публикует
eventBus.emit('cart:updated', cartData);
// Приложение B слушает
eventBus.on('cart:updated', (cartData) => {
updateCheckout(cartData);
});
// 3. Parent-child через window (осторожно!)
window.__MICRO_FRONTEND_CONTEXT__ = {
user: currentUser,
config: appConfig
};
// Подприложение читает
const context = window.__MICRO_FRONTEND_CONTEXT__;
// 4. Shared library (для типов)
export type User = { id: string; name: string };
export type Order = { id: string; userId: string };
// Оба приложения используют одни типы (но разные данные)
Когда использовать shared state
| Сценарий | Использовать | Альтернатива |
|---|---|---|
| Пользователь | Да | - |
| Конфигурация | Да | - |
| Аутентификация | Да | Переповтор логина |
| Заказы | Нет | Собственный store |
| Корзина | Нет | Props + Event Bus |
| Уведомления | Да | Toast Service |
| Модальные окна | Нет | Собственное состояние |
| Язык интерфейса | Да | - |
Заключение
Общее правило:
- Делай общим только данные, которые нужны ВСЕМ (user, config)
- Используй Event Bus для коммуникации между приложениями
- Не делай общим доменные данные и UI состояния
- Думай о независимости - каждое приложение должно работать отдельно
Это главное отличие хороших микрофронтендов от плохых - правильное разделение ответственности.