وقتی درباره میکروسرویس صحبت میکنیم، ذهنمون میره سمت بکاند. ولی در فرانتاند هم چیزی داریم به نام Micro Frontends (میکرو فرانتاند).
Micro Frontends یه معماریه که میگه:
«همونطور که توی بکاند، اپلیکیشن بزرگ رو به چند میکروسرویس کوچیک تقسیم میکنیم، توی فرانتاند هم میتونیم رابط کاربری رو به چند تکه مستقل تقسیم کنیم که هرکدوم مستقل توسعه، تست و دیپلوی بشن.»
چرا از Micro Frontends استفاده میکنن؟
- پروژه بزرگه و چند تیم موازی روش کار میکنن
- نیاز به استقلال تیمها در تکنولوژی و زمان دیپلوی دارن
- اپلیکیشن Legacy دارن که میخوان کمکم migrate کنن
- میخوان چند فریمورک مختلف کنار هم استفاده کنن (مثلاً React + Angular)
معماری Micro Frontends چطوریه؟
- Shell / Container App
یه اپلیکیشن اصلی که مسئول route کردن و لود کردن بخشهای دیگهست. - Feature Apps / Remote Apps
اپلیکیشنهای کوچکتر مستقل که داخل shell لود میشن.
تکنولوژیهایی که برای Micro Frontends استفاده میشن:
- Module Federation (Webpack 5) ← خیلی معروفه
- Single-SPA ← فریمورکی برای مدیریت Micro Frontends
- Web Components ← برای جداسازی و قابل استفاده بودن
- Iframe (در موارد خاص)
مثال واقعی:
فرض کن یه اپلیکیشن فروشگاهی داریم:
- بخش پرداخت توسط تیم A با React توسعه داده میشه
- بخش محصولات توسط تیم B با Angular
- هرکدوم میتونن جداگانه تست و دیپلوی بشن
- shell با کمک module federation اینا رو با هم لود میکنه
مزایا:
استقلال تیمها
راحتی در مهاجرت تکنولوژی
توسعه و دیپلوی جداگانه
مقیاسپذیری بالا
معایب:
پیچیدگی در راهاندازی اولیه
اندازه بیشتر فایلها (bundle size)
سختتر شدن ارتباط بین بخشها
به چالش کشیده شدن تجربه کاربری یکپارچه (UX consistency)
نمونه پروژه ساده Micro Frontend با React
Micro Frontend با React که از Webpack 5 Module Federation استفاده میکنه.
سناریو:
ما دو اپلیکیشن داریم:
- Host App (Shell) → اپ اصلی که قراره Micro Frontendها رو لود کنه
- Remote App → یه کامپوننت ساده React (مثلاً “سلام دنیا”) که از بیرون import میشه
ساختار پروژه:
microfrontend-example/
│
├── host-app/ ← اپ اصلی
└── remote-app/ ← اپ فرعی
1. تنظیمات Remote App
cd remote-app
npx create-react-app .
ویرایش webpack.config.js
:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container.ModuleFederationPlugin;
module.exports = {
entry: "./src/index.js",
mode: "development",
devServer: {
port: 3001,
},
plugins: [
new ModuleFederationPlugin({
name: "remoteApp",
filename: "remoteEntry.js",
exposes: {
"./Hello": "./src/Hello", // این کامپوننت رو export میکنیم
},
shared: { react: { singleton: true }, "react-dom": { singleton: true } },
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
src/Hello.js
:
import React from 'react';
const Hello = () => {
return <h2>سلام از ریموت اپلیکیشن 🎉</h2>;
};
export default Hello;
2. تنظیمات Host App
cd ../host-app
npx create-react-app .
ویرایش webpack.config.js
:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container.ModuleFederationPlugin;
module.exports = {
entry: "./src/index.js",
mode: "development",
devServer: {
port: 3000,
},
plugins: [
new ModuleFederationPlugin({
name: "hostApp",
remotes: {
remoteApp: "remoteApp@http://localhost:3001/remoteEntry.js", // اینو از ریموت میخونه
},
shared: { react: { singleton: true }, "react-dom": { singleton: true } },
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
src/App.js
:
import React from 'react';
// کامپوننت رو از ریموت لود میکنیم
const Hello = React.lazy(() => import("remoteApp/Hello"));
function App() {
return (
<div>
<h1>اپلیکیشن اصلی</h1>
<React.Suspense fallback="در حال لود...">
<Hello />
</React.Suspense>
</div>
);
}
export default App;
اجرای پروژه:
# ترمینال ۱
cd remote-app
npm start
# ترمینال ۲
cd host-app
npm start
الان اگر بری به http://localhost:3000
، میبینی که اپلیکیشن اصلی داره یه کامپوننت React رو از http://localhost:3001
لود میکنه!