Дослідіть JavaScript Module Federation — революційну техніку для створення масштабованих та підтримуваних мікрофронтенд-архітектур. Дізнайтеся про її переваги, деталі реалізації та найкращі практики.
JavaScript Module Federation: Повний посібник з мікрофронтенд-архітектури
У світі веброзробки, що постійно розвивається, створення великих і складних застосунків може швидко стати надскладним завданням. Традиційні монолітні архітектури часто призводять до сильно зв'язаних кодових баз, що ускладнює масштабованість, підтримку та незалежне розгортання. Мікрофронтенди пропонують переконливу альтернативу, розбиваючи застосунок на менші, незалежно розгортані модулі. Серед різноманітних технік мікрофронтенду, JavaScript Module Federation виділяється як потужне та елегантне рішення.
Що таке JavaScript Module Federation?
JavaScript Module Federation, представлена у Webpack 5, дозволяє JavaScript-застосункам динамічно обмінюватися кодом та залежностями під час виконання. На відміну від традиційних методів спільного використання коду, що покладаються на залежності на етапі збірки, Module Federation дозволяє застосункам завантажувати та виконувати код з інших застосунків, навіть якщо вони були створені з використанням різних технологій або версій однієї бібліотеки. Це створює справді розподілену та роз'єднану архітектуру.
Уявіть собі сценарій, де кілька команд працюють над різними розділами великого вебсайту електронної комерції. Одна команда може відповідати за каталог товарів, інша — за кошик для покупок, а третя — за аутентифікацію користувачів. З Module Federation кожна команда може розробляти, збирати та розгортати свій мікрофронтенд незалежно, не турбуючись про конфлікти чи залежності з іншими командами. Основний застосунок ("хост") може динамічно завантажувати та рендерити ці мікрофронтенди ("віддалені") під час виконання, створюючи безшовний користувацький досвід.
Ключові концепції Module Federation
- Хост (Host): Основний застосунок, який споживає та рендерить віддалені модулі.
- Віддалений (Remote): Незалежний застосунок, який надає модулі для використання іншими застосунками.
- Спільні модулі (Shared Modules): Залежності, які є спільними для хоста та віддалених застосунків. Це дозволяє уникнути дублювання та забезпечити узгоджені версії в усьому застосунку.
- Плагін Module Federation: Плагін для Webpack, який вмикає функціональність Module Federation.
Переваги Module Federation
1. Незалежні розгортання
Кожен мікрофронтенд можна розгортати незалежно, не впливаючи на інші частини застосунку. Це дозволяє прискорити цикли випусків, зменшити ризики та підвищити гнучкість. Команда в Берліні може розгортати оновлення для каталогу товарів, тоді як команда кошика для покупок у Токіо продовжує незалежно працювати над своїми функціями. Це значна перевага для глобально розподілених команд.
2. Підвищена масштабованість
Застосунок можна масштабувати горизонтально, розгортаючи кожен мікрофронтенд на окремих серверах. Це дозволяє краще використовувати ресурси та покращити продуктивність. Наприклад, сервіс аутентифікації, який часто є вузьким місцем продуктивності, можна масштабувати незалежно для обробки пікових навантажень.
3. Покращена підтримка
Мікрофронтенди менші та легші в управлінні, ніж монолітні застосунки, що спрощує їх підтримку та налагодження. Кожна команда володіє власною кодовою базою, що дозволяє їм зосередитися на своїй конкретній галузі знань. Уявіть собі глобальну команду, що спеціалізується на платіжних шлюзах; вони можуть підтримувати цей конкретний мікрофронтенд, не впливаючи на інші команди.
4. Технологічна незалежність
Мікрофронтенди можна створювати з використанням різних технологій або фреймворків, що дозволяє командам вибирати найкращі інструменти для роботи. Один мікрофронтенд може бути створений на React, а інший — на Vue.js. Ця гнучкість особливо корисна при інтеграції застарілих застосунків або коли різні команди мають різні вподобання чи досвід.
5. Повторне використання коду
Спільні модулі можна повторно використовувати в кількох мікрофронтендах, зменшуючи дублювання коду та покращуючи узгодженість. Це особливо корисно для загальних компонентів, допоміжних функцій або систем дизайну. Уявіть собі глобально узгоджену систему дизайну, яка використовується в усіх мікрофронтендах, забезпечуючи єдиний досвід бренду.
Реалізація Module Federation: Практичний приклад
Давайте розглянемо спрощений приклад реалізації Module Federation за допомогою Webpack 5. Ми створимо два застосунки: хост-застосунок і віддалений застосунок. Віддалений застосунок надаватиме простий компонент, який буде використовувати хост-застосунок.
Крок 1: Налаштування хост-застосунку
Створіть новий каталог для хост-застосунку та ініціалізуйте новий npm-проєкт:
mkdir host-app
cd host-app
npm init -y
Встановіть Webpack та його залежності:
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev
Створіть файл `webpack.config.js` у корені хост-застосунку з такою конфігурацією:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: 'http://localhost:3000/', // Important for Module Federation
},
devServer: {
port: 3000,
hot: true,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
remoteApp: 'remote@http://localhost:3001/remoteEntry.js',
},
shared: ['react', 'react-dom'],
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
Ця конфігурація визначає точку входу, вихідний каталог, налаштування сервера розробки та плагін Module Federation. Властивість `remotes` вказує на розташування файлу `remoteEntry.js` віддаленого застосунку. Властивість `shared` визначає модулі, які є спільними для хоста та віддалених застосунків. У цьому прикладі ми ділимося 'react' та 'react-dom'.
Створіть файл `index.html` у каталозі `public`:
<!DOCTYPE html>
<html>
<head>
<title>Host Application</title>
</head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html>
Створіть каталог `src` та файл `index.js` всередині нього. Цей файл завантажуватиме віддалений компонент і рендеритиме його в хост-застосунку:
import React from 'react';
import ReactDOM from 'react-dom/client';
import RemoteComponent from 'remoteApp/RemoteComponent';
const App = () => (
<div>
<h1>Host Application</h1>
<p>This is the host application consuming a remote component.</p>
<RemoteComponent />
</div>
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
Встановіть babel-loader та його пресети
npm install -D babel-loader @babel/core @babel/preset-env @babel/preset-react style-loader css-loader
Крок 2: Налаштування віддаленого застосунку
Створіть новий каталог для віддаленого застосунку та ініціалізуйте новий npm-проєкт:
mkdir remote-app
cd remote-app
npm init -y
Встановіть Webpack та його залежності:
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev
Створіть файл `webpack.config.js` у корені віддаленого застосунку з такою конфігурацією:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const path = require('path');
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: 'http://localhost:3001/', // Important for Module Federation
},
devServer: {
port: 3001,
hot: true,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'remote',
filename: 'remoteEntry.js',
exposes: {
'./RemoteComponent': './src/RemoteComponent.js',
},
shared: ['react', 'react-dom'],
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
Ця конфігурація схожа на конфігурацію хост-застосунку, але з кількома ключовими відмінностями. Властивість `name` встановлена на `remote`, а властивість `exposes` визначає модулі, які надаються іншим застосункам. У цьому випадку ми надаємо `RemoteComponent`.
Створіть файл `index.html` у каталозі `public`:
<!DOCTYPE html>
<html>
<head>
<title>Remote Application</title>
</head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html>
Створіть каталог `src` та файл `RemoteComponent.js` всередині нього. Цей файл міститиме компонент, який надається хост-застосунку:
import React from 'react';
const RemoteComponent = () => (
<div style={{ border: '2px solid red', padding: '10px', margin: '10px' }}>
<h2>Remote Component</h2>
<p>This component is loaded from the remote application.</p>
</div>
);
export default RemoteComponent;
Створіть каталог `src` та файл `index.js` всередині нього. Цей файл буде рендерити `RemoteComponent`, коли віддалений застосунок запускається незалежно (необов'язково):
import React from 'react';
import ReactDOM from 'react-dom/client';
import RemoteComponent from './RemoteComponent';
const App = () => (
<div>
<h1>Remote Application</h1>
<RemoteComponent />
</div>
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
Крок 3: Запуск застосунків
Додайте скрипти запуску до обох файлів `package.json`:
"scripts": {
"start": "webpack serve"
}
Запустіть обидва застосунки за допомогою `npm start`. Відкрийте браузер і перейдіть за адресою `http://localhost:3000`. Ви повинні побачити, як хост-застосунок рендерить віддалений компонент. Віддалений компонент матиме червону рамку, що вказує на те, що він завантажений з віддаленого застосунку.
Розширені концепції та міркування
1. Управління версіями та сумісність
При спільному використанні залежностей між мікрофронтендами важливо враховувати версіонування та сумісність. Module Federation надає механізми для вказівки діапазонів версій та вирішення конфліктів. Інструменти, такі як семантичне версіонування (semver), стають вирішальними в управлінні залежностями та забезпеченні сумісності між різними мікрофронтендами. Неправильне управління версіями може призвести до помилок під час виконання або неочікуваної поведінки, особливо в складних системах з численними мікрофронтендами.
2. Аутентифікація та авторизація
Реалізація аутентифікації та авторизації в мікрофронтенд-архітектурі вимагає ретельного планування. Поширені підходи включають використання спільного сервісу аутентифікації або реалізацію аутентифікації на основі токенів. Безпека є першочерговою, і вкрай важливо дотримуватися найкращих практик для захисту конфіденційних даних. Наприклад, платформа електронної комерції може мати виділений мікрофронтенд для аутентифікації, відповідальний за перевірку облікових даних користувача перед наданням доступу до інших мікрофронтендів.
3. Комунікація між мікрофронтендами
Мікрофронтендам часто потрібно спілкуватися один з одним для обміну даними або запуску дій. Можна використовувати різні патерни комунікації, такі як події, спільне управління станом або прямі виклики API. Вибір правильного патерну комунікації залежить від конкретних вимог застосунку. Інструменти, такі як Redux або Vuex, можуть використовуватися для спільного управління станом. Кастомні події можуть використовуватися для слабкого зв'язку та асинхронної комунікації. Виклики API можуть використовуватися для більш складних взаємодій.
4. Оптимізація продуктивності
Завантаження віддалених модулів може вплинути на продуктивність, особливо якщо модулі великі або мережеве з'єднання повільне. Оптимізація розміру модулів, використання розділення коду та кешування віддалених модулів можуть покращити продуктивність. Ліниве завантаження (Lazy loading) модулів лише тоді, коли вони потрібні, є ще однією важливою технікою оптимізації. Також, розгляньте можливість використання мережі доставки контенту (CDN) для обслуговування віддалених модулів з географічно ближчих до кінцевих користувачів місць, тим самим зменшуючи затримку.
5. Тестування мікрофронтендів
Тестування мікрофронтендів вимагає іншого підходу, ніж тестування монолітних застосунків. Кожен мікрофронтенд слід тестувати незалежно, а також в інтеграції з іншими мікрофронтендами. Контрактне тестування може використовуватися для забезпечення сумісності мікрофронтендів один з одним. Юніт-тести, інтеграційні тести та наскрізні тести є важливими для забезпечення якості мікрофронтенд-архітектури.
6. Обробка помилок та моніторинг
Реалізація надійної обробки помилок та моніторингу є вирішальною для виявлення та вирішення проблем у мікрофронтенд-архітектурі. Централізовані системи логування та моніторингу можуть надати уявлення про стан та продуктивність застосунку. Інструменти, такі як Sentry або New Relic, можуть використовуватися для відстеження помилок та метрик продуктивності в різних мікрофронтендах. Добре розроблена стратегія обробки помилок може запобігти каскадним збоям та забезпечити стійкий користувацький досвід.
Сценарії використання Module Federation
Module Federation добре підходить для різноманітних сценаріїв використання, зокрема:
- Великі платформи електронної комерції: Розбиття вебсайту на менші, незалежно розгортані модулі для каталогу товарів, кошика, аутентифікації користувачів та оформлення замовлення.
- Корпоративні застосунки: Створення складних панелей інструментів та порталів, де різні команди відповідають за різні розділи.
- Системи управління контентом (CMS): Дозволяє розробникам створювати та розгортати власні модулі або плагіни незалежно.
- Мікросервісні архітектури: Інтеграція фронтенд-застосунків з мікросервісними бекендами.
- Прогресивні веб-застосунки (PWA): Динамічне завантаження та оновлення функцій у PWA.
Наприклад, розглянемо багатонаціональний банківський застосунок. За допомогою module federation, основні банківські функції, інвестиційна платформа та портал підтримки клієнтів можуть розроблятися та розгортатися незалежно. Це дозволяє спеціалізованим командам зосередитися на конкретних напрямках, забезпечуючи при цьому єдиний та узгоджений користувацький досвід у всіх сервісах.
Альтернативи Module Federation
Хоча Module Federation пропонує переконливе рішення для мікрофронтенд-архітектур, це не єдиний варіант. Інші популярні техніки включають:
- iFrames: Простий, але часто менш гнучкий підхід, який вбудовує один застосунок в інший.
- Веб-компоненти (Web Components): Кастомні HTML-елементи для повторного використання, які можна застосовувати в різних застосунках.
- Single-SPA: Фреймворк для створення односторінкових застосунків з кількома фреймворками.
- Інтеграція на етапі збірки: Об'єднання всіх мікрофронтендів в один застосунок під час процесу збірки.
Кожна техніка має свої переваги та недоліки, і найкращий вибір залежить від конкретних вимог застосунку. Module Federation вирізняється своєю гнучкістю під час виконання та здатністю динамічно ділитися кодом, не вимагаючи повної перебудови та повторного розгортання всіх застосунків.
Висновок
JavaScript Module Federation — це потужна техніка для створення масштабованих, підтримуваних та незалежних мікрофронтенд-архітектур. Вона пропонує численні переваги, включаючи незалежні розгортання, підвищену масштабованість, покращену підтримку, технологічну незалежність та повторне використання коду. Розуміючи ключові концепції, реалізуючи практичні приклади та враховуючи розширені концепції, розробники можуть використовувати Module Federation для створення надійних та гнучких вебзастосунків. Оскільки складність вебзастосунків продовжує зростати, Module Federation надає цінний інструмент для управління цією складністю та дозволяє командам працювати більш ефективно та результативно.
Відкрийте для себе силу децентралізованої веброзробки з JavaScript Module Federation та розкрийте потенціал для створення справді модульних та масштабованих застосунків. Незалежно від того, чи створюєте ви платформу електронної комерції, корпоративний застосунок чи CMS, Module Federation може допомогти вам розбити застосунок на менші, більш керовані одиниці та забезпечити кращий користувацький досвід.