Як обмінюватися станами між мікрофронтендами на React за допомогою Module-Federation?

Технологія мікрофронтендів пропонує революційну парадигму для створення масштабованих і зручних у підтримці веб-додатків, розбиваючи монолітну архітектуру на керовані компоненти, що розробляються незалежно.

Щоб дізнатися більше про мікрофронтенди, перегляньте цей пост:

[

Як ми будуємо мікрофронтенди

Створення мікрофронтендів для прискорення і масштабування процесу веб-розробки.

blog.bitsrc.io

](/how-we-build-micro-front-ends-d3eeeac0acfc?source=post_page-----f3762996c208--------------------------------)

Однак це не означає, що мікрофронтенди завжди корисні.

Одним із найбільших недоліків використання мікрофронтендів з React є проблема спільного стану між цими розподіленими одиницями.

На відміну від традиційних монолітних додатків, мікрофронтенди мають справу з синхронізацією стану між різними джерелами і доменами — завданням, яке браузери не призначені вирішувати.

pic

Ви можете побачити розгорнутий додаток тут: https://mf-host-sharing-state.netlify.app/

У цій статті ми розглянемо різні стратегії, які дозволяють вашим мікрофронтендам безшовно взаємодіяти між собою.

Крім того, ми використаємо Bit для побудови нашого додатку, використовуючи його гнучкість для переключення між інтеграцією під час виконання і на етапі збірки, що спрощує складність управління мікрофронтендами.

Завдання

Я створив комплексний приклад, розміщений в цьому Bit Cloud scope: learnbit-react/sharing-state-mfe.

Цей scope включає компонент host-app, який використовує webpack-transformers/mfe-host-transformer для ефективного завантаження віддалених модулів за допомогою Module Federation.

pic

Під remote-mfe ви знайдете компоненти додатків, які розгортаються незалежно на різних URL-адресах.
Кожен компонент також має окремі версії за допомогою Bit.

Ця настройка має значні переваги, такі як ізольована розробка, окремі цикли розгортання та детальне керування версіями для кожного мікрофронтенду, що відображає гнучкість і масштабованість цього архітектурного підходу.

Як поділитися станом між мікрофронтендами?

Техніка 01: Користувацькі події для обміну станом між мікрофронтендами

Користувацькі події пропонують практичне рішення для обміну станом у веб-мікрофронтендах. Цей підхід є високомасштабованим і відповідає архітектурам, орієнтованим на події, що є поширеними в мікросервісах.

Для практичного прикладу розглянемо наш Компонент погодних подій планети.

Цей компонент слухає подію planetDataChange і оновлює свій стан на основі деталей події.
Такий метод дозволяє ефективно комунікувати між компонентами, забезпечуючи синхронізовані оновлення в межах додатку.

import { useEffect, useState } from 'react';  

export const PlanetEventWeatherComponent = () =\> {  
 const [weatherData, setWeatherData] = useState({/\* початковий стан \*/});  

const handleCustomEvent = (event) =\> {  
 setWeatherData(event.detail);  
};  

 useEffect(() =\> {  
 const handleCustomEvent = (event) =\> {  
 setWeatherData(event.detail);  
 };  

 window.addEventListener('planetDataChange', handleCustomEvent);  

 return () =\> {  
 window.removeEventListener('planetDataChange', handleCustomEvent);  
 };  
 }, []);  

 // ...

(рендеринг інтерфейсу)  
};  

export default PlanetEventWeatherComponent;

Ви можете дослідити повну реалізацію і побачити цей підхід у коді компонента.

Ця техніка особливо корисна для динамічних оновлень даних і інтерактивних користувацьких інтерфейсів.

Хоча кастомні події (custom events) пропонують надійне рішення для обміну станом у веб-мікрофронтендах, вони мають свої виклики:

  1. Обмежена область застосування для мобільних мікрофронтендів: Кастомні події переважно розроблені для веб-додатків. Реалізація їх у мобільних мікрофронтендах може бути складною, оскільки вони залежать від API, специфічних для браузера.
  2. Залежність від часу підписки на події: Мікрофронтенди повинні підписуватись на події до їх публікації для ефективної передачі даних.
    Ця вимога до послідовності може ускладнити архітектуру додатка, особливо в динамічних середовищах, де компоненти часто монтуються та демонтуються.
  3. Навантаження координації: Забезпечення того, щоб всі команди дотримувались шаблону кастомних подій (custom events), вимагає координації та дотримання загальних стандартів.
    Це може стати значним навантаженням у великих організаціях, де кілька команд працюють над різними мікрофронтендами.

Незважаючи на ці труднощі, кастомні події (custom events) залишаються цінним інструментом для веб-мікрофронтендів, надаючи нативне, браузерне рішення для керування станом, орієнтованим на події.

Техніка 02: Шина повідомлень для обміну станом у мікрофронтендах

Техніка Шини повідомлень (Message Bus) відома як архітектура, орієнтована на події, в мікросервісах, і сприяє обміну станом у мікрофронтендах.

Цей шаблон включає централізовану систему повідомлень для публікації та підписки на події, що сприяє безперешкодному потоку даних між компонентами.

Наприклад, наш Planet Message Bus Weather Component є прикладом цього підходу.
Він підписується на подію ‘planetData’ через спільну шину повідомлень, що забезпечує синхронізацію даних у реальному часі між мікрофронтендами.

import { useEffect, useState } from 'react';  
import { messageBus } from '@learnbit-react/sharing-state-mfe.shared.message-bus';  

export const PlanetMessageBusWeatherComponent = () => {  
 const [weatherData, setWeatherData] = useState({/* початковий стан */});  
 useEffect(() => {  
 const handleDataUpdate = (data) => {  
 setWeatherData(data);  
 };  
 messageBus.subscribe('planetData', handleDataUpdate);  
 return () => messageBus.unsubscribe('planetData', handleDataUpdate);  
 }, []);  
 // ... (відображення UI)  
};  
export default PlanetMessageBusWeatherComponent;

У нашій реалізації як віддалені, так і хостові компоненти використовують одну й ту ж інстанцію спільного компонента message-bus.
Цей спільний компонент, створений за допомогою Bit, слугує основою для системи шини повідомлень, забезпечуючи стабільну комунікацію між мікрофронтендами.

Використовуючи Bit, ми отримуємо перевагу від його здатності створювати споживані пакети для кожного компонента.
Це спрощує інтеграцію методу шини повідомлень і гарантує, що як віддалені, так і хост-аплікації використовують одну й ту саму інстанцію, як визначено в спільній конфігурації Module Federation:

'@learnbit-react/sharing-state-mfe.shared.message-bus': {  
 singleton: true,  
 requiredVersion: '^0.0.1',  
 eager: true,  
}

Метод шини повідомлень особливо корисний для інтеграції на етапі збірки в мобільних мікрофронтендах, де відсутні кастомні події, характерні для веб-застосунків.

Крім того, необхідно забезпечити, щоб усі ваші мікрофронтенди використовували одну й ту саму інстанцію шини повідомлень, оскільки вона є єдиним реєстром для всіх опублікованих подій, що сприяє ефективній і стабільній комунікації між компонентами.

Bit значно допомагає в цьому процесі, пропонуючи модулі для споживання під час виконання і на етапі збірки. Ця гнучкість дозволяє безшовно інтегрувати спільні компоненти, такі як шина повідомлень, під час етапу збірки аплікації.
Ця адаптивність є ключовою перевагою при роботі з різноманітними архітектурами, такими як мобільні мікрофронтенди, забезпечуючи єдину та ефективну систему комунікації між різними частинами аплікації.

Виклики:

  • Потрібна послідовна реалізація в усіх мікрофронтендах.
  • Потрібність у спільній інстанції шини повідомлень може призвести до складності в певних архітектурах.
  • Координація і стандартизація є важливими для запобігання розрізненим стратегіям комунікації.

Техніка 03: Обмін станом через Props у мікрофронтендах

Обмін через props — це основний і простий метод у React мікрофронтендах. Ця техніка передбачає передачу даних безпосередньо як props до компонентів. Вона особливо ефективна для статичних даних або випадків, коли відносини між батьками і дітьми є прозорими.

Наприклад, наш Planet Weather Component ілюструє цей підхід.
Цей метод отримує планетарні дані як props і відображає відповідну інформацію про погоду.

Цей підхід інтуїтивно зрозумілий для розробників, які знайомі з основними концепціями React.

// PlanetWeather.js  
import React from 'react';  

interface PlanetWeatherProps {  
 planetName: string;  
 sol: string;  
 temperature: string;  
 imageUrl: string;  
}  

export function PlanetWeather({  
 planetName,  
 sol,  
 temperature,  
 imageUrl,  
}: PlanetWeatherProps) {  
 // Логіка компонента та рендеринг  
};  
export default PlanetWeather;

Хоча цей підхід є простим, він найбільш ефективний, коли компоненти мають безпосереднє відношення батька і дитини.

Цей метод може стати громіздким у більш складних сценаріях, що передбачають глибоке вкладення або компоненти-сиблінги, що може призвести до проблеми «прокачування props».

Однак його простота та легкість розуміння роблять його чудовим вибором для багатьох сценаріїв.

Ознайомтесь із компонентом детальніше тут.

Виклики:

  • Збільшена зв'язність: Залежність від контейнерного додатку для потоку даних може знижувати незалежність мікрофронтендів.
  • Обмеження фреймворку: Для ефективної реалізації потрібен однаковий фреймворк для всіх мікрофронтендів, що обмежує гнучкість.
  • Навантаження на продуктивність: Це може призвести до неефективних циклів рендерингу, особливо при глибокому прокачуванні props у складних додатках.

Техніка 04: API платформи для зберігання стану в мікрофронтендах

API для зберігання на платформі, такі як Local Storage, пропонують унікальний підхід до керування станом у мікрофронтендах.
Цей метод дозволяє мікрофронтендам незалежно встановлювати та зчитувати дані безпосередньо, мінімізуючи залежність від контейнерного додатку.

Наприклад, наш Planet Storage Weather Component використовує Local Storage для збереження та отримання даних про погоду, демонструючи, як мікрофронтенди можуть ефективно керувати станом в ізоляції.

// PlanetStorageWeatherComponent.js  
import { useEffect, useState } from 'react';  
import styles from './planet-weather.module.scss';  
export const PlanetStorageWeatherComponent = () => {  
const [weatherData, setWeatherData] = useState({/* початковий стан */});  

 useEffect(() => {  
 const updateFromStorage = () => {  
 const data = localStorage.getItem('planetWeatherData');  
 if (data) {  
 setWeatherData(JSON.parse(data));  
 }  
 };  

 updateFromStorage();  
 window.addEventListener('localStorageUpdated', updateFromStorage);  

 return () => {  
 window.removeEventListener('localStorageUpdated', updateFromStorage);  
 };  
 }, []);  

// ...

(rendering UI)  

};  

export default PlanetStorageWeatherComponent;

Ця техніка є універсальною та застосовною як для веб, так і для мобільних контекстів, з Local Storage для браузерів та Async Storage для мобільних додатків. Однак вона має свої обмеження:

  • Обмежена масштабованість: Більш підходить для менших наборів даних; керування великими наборами даних може стати складним і незручним.
  • Складність відлагодження: Відслідковувати, який мікрофронтенд маніпулює даними, може бути складно.
  • Проблеми безпеки: Не рекомендується для чутливих даних через потенційні ризики безпеки.

Незважаючи на ці обмеження, платформи для зберігання даних залишаються цінним інструментом, особливо в сценаріях, де мікрофронтенди працюють на окремих екранах, дозволяючи ефективно отримувати дані під час монтування. Завдяки Bit інтеграція стає зручнішою, пропонуючи безшовні рішення як на етапі складання, так і в реальному часі для різних платформ.

Підсумки

Ми продемонстрували ефективні стратегії, такі як:

  1. Користувацькі події (Custom Events)
  2. Шина повідомлень (Message Bus)
    3.
    Props
  3. Платформенні API для зберігання даних

Як і очікувалось, ми реалізували це, використовуючи React, Module Federation та Bit.

Важливо розуміти, що кожен метод має свої унікальні переваги та виклики, тому перед тим, як прийняти рішення для вашого наступного великого проєкту, необхідно врахувати всі виклики та переваги, представлені в цій статті!

Якщо ви хочете дослідити реалізований код, перегляньте повний код тут.
Additionally, the link to the demo is attached below 🙂

pic

Вибір між інтеграцією під час збірки та під час виконання простий: https://mf-host-sharing-state-build-time.netlify.app/

Сподіваюся, ця стаття була корисною.

Дякую за читання.

Дізнайтесь більше

[

Як ми будуємо мікрофронтенди

Створення мікрофронтендів для прискорення та масштабування процесу розробки веб-додатків.

blog.bitsrc.io

](/how-we-build-micro-front-ends-d3eeeac0acfc?source=post_page-----f3762996c208--------------------------------)

[

Як ми будуємо систему дизайну компонентів

Створення системи дизайну з компонентів для стандартизації та масштабування процесу розробки інтерфейсів.

blog.bitsrc.io

](/how-we-build-our-design-system-15713a1f1833?source=post_page-----f3762996c208--------------------------------)

[

Створення вебсайту для розробників з компонентами Bit

Як я створив своє портфоліо, використовуючи незалежні компоненти React.

blog.bitsrc.io

](/creating-a-developer-website-with-bit-components-3f4083a7f050?source=post_page-----f3762996c208--------------------------------)

[

5 інструментів для створення бібліотек компонентів React у 2023 році

Дізнайтеся, які варіанти є для полегшення вашої роботи при створенні власної бібліотеки компонентів

blog.bitsrc.io

](/5-tools-for-building-react-component-libraries-in-2023-d8fb8e4c13b4?source=post_page-----f3762996c208--------------------------------)

[

Початок роботи з новим проектом Vue.js у 2023 році

blog.bitsrc.io

](/getting-started-with-a-new-vue-js-project-in-2023-7ea97498ab6a?source=post_page-----f3762996c208--------------------------------)

[

Компонуємi додатки та компонентно-орієнтована розробка: посібник

Створення компонентно-орієнтованих додатків в організованому та масштабованому вигляді за допомогою платформи для компонентної розробки.

blog.bitsrc.io

](/component-driven-development-and-composable-applications-a-guide-7a0934e60936?source=post_page-----f3762996c208--------------------------------)

Перекладено з: How To Share States Between React Micro-Frontends using Module-Federation?

Leave a Reply

Your email address will not be published. Required fields are marked *