Frontend Development

ساخت میکرو-فرانت‌اند‌های مقیاس‌پذیر با استفاده از Module Federation در Webpack 5

در چشم‌انداز در حال تحول توسعه فرانت‌اند، برنامه‌های مونولیتیک اغلب به گلوگاه برای تیم‌های مهندسی بزرگ تبدیل می‌شوند. با رشد برنامه‌ها، پیچیدگی مدیریت وابستگی‌ها، چرخه‌های استقرار و مالکیت کد نیز افزایش می‌یابد. اینجاست که معماری میکرو-فرانت‌اند درخشش خود را نشان می‌دهد و به تیم‌ها اجازه می‌دهد برنامه‌های فرانت‌اند مستقل را بسازند، تست کنند و مستقر نمایند. در حالی که پیاده‌سازی‌های اولیه به شیم‌های iframe پیچیده یا راه‌حل‌های بسته‌بندی زمان اجرا متکی بودند، Webpack 5 یک راه‌حل بومی و قدرتمند معرفی کرد: Module Federation.

این پست بررسی می‌کند که چگونه می‌توان از پلاگین Module Federation در Webpack 5 برای ایجاد میکرو-فرانت‌اند‌های واقعاً مقیاس‌پذیر و مستقل استفاده کرد که می‌توانند بدون بار اضافی سنتی، بین برنامه‌های مختلف به اشتراک گذاشته و مصرف شوند.

Module Federation چیست؟

Module Federation مفهومی است که به برنامه‌های جاوااسکریپت اجازه می‌دهد کد را به صورت پویا از زمان‌های اجرای دیگر (مرورگرها، سرورها یا Web Workers) در زمان اجرا وارد کنند. برخلاف بسته‌بند‌های سنتی که وابستگی‌ها را در زمان ساخت حل می‌کنند، Module Federation آن‌ها را در زمان اجرا حل می‌کند. این بدان معناست که برنامه A می‌تواند کدی را که در برنامه B نوشته شده است اجرا کند، گویی که کد محلی است، به شرطی که هر دو برنامه در حال اجرا باشند.

مزایای کلیدی عبارتند از:

  • استقرار مستقل: تیم‌ها می‌توانند میکرو-فرانت‌اند خاص خود را به‌روزرسانی و مستقر کنند بدون اینکه برنامه میزبان را لمس کنند.
  • وابستگی‌های مشترک: کتابخانه‌های حیاتی مانند React یا Redux می‌توانند بین برنامه‌ها به اشتراک گذاشته شوند تا اندازه بسته کاهش یابد و یکپارچگی تضمین شود.
  • بی‌طرفی فناوری: اگرچه Webpack ابزار اصلی است، اما پروتکل اجازه یکپارچه‌سازی با سیستم‌های ساخت دیگر را می‌دهد، اگرچه Webpack بالغ‌ترین پیاده‌سازی را ارائه می‌دهد.

تنظیم برنامه‌های میزبان و ریموت

برای نمایش Module Federation، بیایید سناریویی با دو برنامه را فرض کنیم:

  1. برنامه میزبان (Host App): برنامه پوسته اصلی که رابط کاربری را هماهنگ می‌کند.
  2. برنامه ریموت (Remote App): یک ماژول خاص ویژگی (مانند داشبورد کاربر یا کامپوننت چت) که توسط میزبان مصرف خواهد شد.

مرحله ۱: نمایان‌سازی ماژول‌ها در برنامه ریموت

اولین قدم این است که برنامه ریموت را پیکربندی کنیم تا کامپوننت‌های خود را نمایان کند. در فایل webpack.config.js برنامه ریموت، ما ModuleFederationPlugin را وارد کرده و فیلد exposes را تعریف می‌کنیم.

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  // ... other config
  plugins: [
    new ModuleFederationPlugin({
      name: 'remoteApp',
      filename: 'remoteEntry.js',
      exposes: {
        './UserProfile': './src/components/UserProfile',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
      }
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ]
};

در اینجا، ما ./UserProfile را نمایان می‌کنیم. ما همچنین وابستگی‌های shared را پیکربندی می‌کنیم. با تنظیم singleton: true، اطمینان حاصل می‌کنیم که تنها یک نمونه از React در هر دو برنامه بارگذاری می‌شود که از عدم تطابق حالت جلوگیری کرده و اندازه پیکربندی را کاهش می‌دهد.

مرحله ۲: مصرف ماژول‌ها در برنامه میزبان

در مرحله بعد، برنامه میزبان را پیکربندی می‌کنیم تا ماژول نمایان‌شده را مصرف کند. ما پیکربندی remote را در ModuleFederationPlugin برنامه میزبان اضافه می‌کنیم.

new ModuleFederationPlugin({
  name: 'hostApp',
  remotes: {
    remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
  },
  shared: {
    react: { singleton: true, requiredVersion: '^18.0.0' },
    'react-dom': { singleton: true, requiredVersion: '^18.0.0' }
  }
})

فیلد remotes به Webpack می‌گوید که فایل ورودی ریموت را کجا پیدا کند. می‌توانید از یک URL ثابت یا یک نقطه پایانی پویا که پیکربندی را بر اساس محیط برمی‌گرداند، استفاده کنید. توجه داشته باشید که پیکربندی shared باید با برنامه ریموت مطابقت داشته باشد تا از سازگاری اطمینان حاصل شود.

وارد کردن پویا در React

با پیکربندی انجام شده، می‌توانید کامپوننت ریموت را به صورت پویا با استفاده از API System.import (که توسط Webpack پلی‌فیل شده است) یا وارد کردن‌های پویای استاندارد وارد کنید. در اینجا یک مثال در یک کامپوننت React آورده شده است:

import React, { lazy, Suspense } from 'react';

// Lazily load the remote component
const UserProfile = lazy(() => import('remoteApp/UserProfile'));

const HostComponent = () => {
  return (
    
Loading...
}>
); }; export default HostComponent;

استفاده از lazy و Suspense در اینجا حیاتی است. این اطمینان حاصل می‌کند که کد ریموت تنها زمانی دانلود می‌شود که نیاز باشد و یک رابط کاربری جایگزین در طول درخواست شبکه ارائه می‌دهد.

بهترین شیوه‌ها و چالش‌ها

در حالی که Module Federation معماری میکرو-فرانت‌اند را ساده می‌کند، چالش‌های جدیدی را نیز ایجاد می‌کند:

سازگاری نسخه

وابستگی‌های مشترک باید نسخه‌های سازگار داشته باشند. اگر میزبان از React 18 و ریموت از React 17 استفاده کند، برنامه به احتمال زیاد شکست می‌خورد. همیشه از شماره‌گذاری معنایی استفاده کنید و محدودیت‌های وابستگی مشترک را به وضوح مستند کنید.

مرزهای خطا (Error Boundaries)

اگر یک برنامه ریموت دچار خطا شود، نباید کل پوسته میزبان را خراب کند. کامپوننت‌های ریموت را در مرزهای خطای React بپیچید تا خطاها را تشخیص داده و پیام‌های خطای ظریف را نمایش دهند.

ارتباط بین برنامه‌ها

میکرو-فرانت‌اند‌ها شل‌بسته هستند. ارتباط باید از طریق رویدادهای سفارشی، کتابخانه‌های مدیریت حالت (مانند Redux یا Zustand) یا کامپوننت‌های وب انجام شود. از دستکاری مستقیم DOM در مرزهای برنامه خودداری کنید.

نتیجه‌گیری

Module Federation در Webpack 5 یک بازی‌ساز برای معماری فرانت‌اند است. این مفهوم میکرو-فرانت‌اند را دموکراتیک می‌کند با ارائه یک راه‌حل استاندارد و یکپارچه‌شده در زمان ساخت که به راه‌اندازی پیچیده زمان اجرا نیاز ندارد. با امکان استقرار مستقل و وابستگی‌های مشترک، به سازمان‌های بزرگ اجازه می‌دهد تا تیم‌های مهندسی فرانت‌اند خود را به طور مؤثر مقیاس‌دهی کنند.

چه در حال مهاجرت یک مونولیت قدیمی باشید و چه در حال ساخت یک پلتفرم جدید از صفر، Module Federation مجموعه ابزار قدرتمندی را برای دستیابی به چابکی، تاب‌آوری و مقیاس‌پذیری در برنامه‌های جاوااسکریپت شما ارائه می‌دهد.

Share: