מיקרופרונטאנדים עם Module Federation: תלויות משותפות ו-CI/CD

כאשר מספר יישומי React מתקיימים בתוך מוצר אחד, תלויות כפולות מנפחות את ה-bundles ומאטות את הטעינה. אנו מגדירים micro-frontends עם Module Federation כדי לחלץ קוד משותף לתלויות משותפות ולהאיץ את הממשק. הצוות שלנו מספק את הפרויקט במפתח מלא—מארכיטקטורה ועד CI/CD—תוך הבטחת פעילות יציבה ותמיכה מתמשכת.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
מיקרופרונטאנדים עם Module Federation: תלויות משותפות ו-CI/CD
מורכב
~3-5 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1365
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113
  • פיתוח אתר עבור SBH Partners
    פיתוח אתר עבור SBH Partners
    1201
  • פיתוח אתר עבור Red Pear
    פיתוח אתר עבור Red Pear
    619

אתה מריץ מספר אפליקציות React — קטלוג, סל קניות, חשבון אישי. כל אחת בונה את ה-bundle שלה, ואתה מגלה ש-React משוכפל, מה שמגדיל את גודל הטעינה. לאחרונה בפרויקט עם שמונה microfrontends, נתקלנו ב-bundle משתמש סופי של 2.4 MB. פיצול ה-bundle לא עוזר — אתה צריך runtime משותף. Module Federation — מנגנון המובנה בתוך Webpack Module Federation — פותר את זה. הניסיון שלנו: פרסנו ארכיטקטורה כזו עבור 30+ פרויקטים, והקטנו את גודל ה-bundle של כל remote ב-35% בממוצע, מה שהוביל לחיסכון משמעותי בתעבורת CDN.

באיזו גישת microfrontend לבחור: iframe, Web Components, או Module Federation?

Iframe פשוט אבל הורג SEO, שובר ניווט, ומאט: בפרויקט אחד, טעינת עמוד דרך iframe הוכפלה. Web Components מבודדים אבל מקשים על שיתוף state ו-context של React. Module Federation מספק קוד JS אמיתי, תלויות משותפות (bundle קטן פי 2), וטעינה דינמית ללא rebuild. השוואה בפרויקט אמיתי: iframe — 2.1 MB, Web Components — 1.8 MB, Module Federation — 680 KB. הוא תומך בטעינה אסינכרונית דרך תבנית bootstrap, קריטית כדי להימנע משגיאות Shared module is not available for eager consumption.

איך לתכנן ארכיטקטורת microfrontend ולהגדיר תלויות משותפות?

פיצלנו את המונולית ל-remotes לפי תחום עסקי.

Remote פונקציה מאגר קוד
host (shell) ניווט, layout, ניתוב apps/shell
catalog רשימת מוצרים ופרטים apps/catalog
checkout סל קניות ותשלום apps/checkout
auth התחברות, הרשמה, widget apps/auth

לכל remote יש pipeline CI/CD משלו. שינויים בקטלוג נראים מיד ללא פריסה מחדש של ה-host.

איך להימנע משכפול תלויות?

השתמש ב-singleton: true וב-requiredVersion אך ורק מ-package.json. אם הגרסאות לא תואמות, Module Federation טוען עותק משלו רק עבור מודולים לא תואמים. הניסיון שלנו מראה שגישה זו מפחיתה שגיאות אינטגרציה פי 3. בפרויקט אחד עם 8 remotes, הקטנו את ה-bundle המשתמש הסופי ב-48%, מה שהוריד משמעותית את עלויות התשתית.

השוואת גישות לשיתוף תלויות

גישה גודל bundle מורכבות גמישות גרסאות
Iframe 2.1 MB נמוכה בידוד מלא
Web Components 1.8 MB גבוהה מוגבלת
Module Federation 680 KB בינונית אוטומטית

איך להגדיר תלויות משותפות צעד אחר צעד?

  1. בקונפיגורציית ModuleFederationPlugin, ציין shared עם אובייקט עבור כל תלות.
  2. הגדר singleton: true עבור ספריות קריטיות (React, React DOM).
  3. הגדר requiredVersion מ-package.json — לדוגמה, deps.react.
  4. עבור ה-host, הגדר eager: false והשתמש בתבנית bootstrap.
  5. בדוק את האינטגרציה, וודא שאין שגיאות console.

איך להגדיר Webpack עבור host ו-remote?

קונפיגורציית host (shell)

const { ModuleFederationPlugin } = require('webpack').container
const HtmlWebpackPlugin = require('html-webpack-plugin')
const deps = require('./package.json').dependencies

module.exports = (env, argv) => ({
  mode: argv.mode ?? 'development',
  entry: './src/index.ts',
  output: {
    publicPath: 'auto',
    filename: '[name].[contenthash].js',
    clean: true,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-react', '@babel/preset-typescript'],
        },
      },
    ],
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        catalog: `catalog@${ argv.mode === 'production' ? 'https://catalog.example.com' : 'http://localhost:3001' }/remoteEntry.js`,
        checkout: `checkout@${ argv.mode === 'production' ? 'https://checkout.example.com' : 'http://localhost:3002' }/remoteEntry.js`,
        auth: `auth@${ argv.mode === 'production' ? 'https://auth.example.com' : 'http://localhost:3003' }/remoteEntry.js`,
      },
      shared: {
        react: {
          singleton: true,
          requiredVersion: deps.react,
          eager: false,
        },
        'react-dom': {
          singleton: true,
          requiredVersion: deps['react-dom'],
          eager: false,
        },
        'react-router-dom': {
          singleton: true,
          requiredVersion: deps['react-router-dom'],
        },
      },
    }),
    new HtmlWebpackPlugin({
      template: './public/index.html'
    }),
  ],
  devServer: {
    port: 3000,
    historyApiFallback: true,
  },
})

קונפיגורציית remote (catalog)

const { ModuleFederationPlugin } = require('webpack').container
const deps = require('./package.json').dependencies
module.exports = (env, argv) => ({
  mode: argv.mode ?? 'development',
  entry: './src/index.ts',
  output: {
    publicPath: 'auto',
    filename: '[name].[contenthash].js',
    clean: true,
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'catalog',
      filename: 'remoteEntry.js',
      exposes: {
        './ProductList': './src/components/ProductList',
        './ProductDetail': './src/components/ProductDetail',
        './useCart': './src/hooks/useCart',
      },
      shared: {
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        'react-dom': {
          singleton: true,
          requiredVersion: deps['react-dom'],
        },
        'react-router-dom': {
          singleton: true,
        },
      },
    }),
  ],
  devServer: {
    port: 3001,
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    historyApiFallback: true,
  },
})

איך להבטיח טעינה אסינכרונית? תבנית Bootstrap

// src/index.ts
import('./bootstrap')

// src/bootstrap.tsx
import React from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'

const root = createRoot(document.getElementById('root')!)
root.render(<App />)

בלי זה, אתה מקבל const { ModuleFederationPlugin } = require('webpack').container const HtmlWebpackPlugin = require('html-webpack-plugin') const deps = require('./package.json').dependencies module.exports = (env, argv) => ({ mode: argv.mode ?? 'development', entry: './src/index.ts', output: { publicPath: 'auto', filename: '[name].[contenthash].js', clean: true, }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.(ts|tsx)$/, loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-typescript'], }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'shell', remotes: { catalog: `catalog@${ argv.mode === 'production' ? 'https://catalog.example.com' : 'http://localhost:3001' }/remoteEntry.js`, checkout: `checkout@${ argv.mode === 'production' ? 'https://checkout.example.com' : 'http://localhost:3002' }/remoteEntry.js`, auth: `auth@${ argv.mode === 'production' ? 'https://auth.example.com' : 'http://localhost:3003' }/remoteEntry.js`, }, shared: { react: { singleton: true, requiredVersion: deps.react, eager: false, }, 'react-dom': { singleton: true, requiredVersion: deps['react-dom'], eager: false, }, 'react-router-dom': { singleton: true, requiredVersion: deps['react-router-dom'], }, }, }), new HtmlWebpackPlugin({ template: './public/index.html' }), ], devServer: { port: 3000, historyApiFallback: true, }, }) . אנו מבטיחים שתבנית זו מיושמת בכל remote.

הצהרות TypeScript עבור מודולי remote ו-CI/CD

npm install @module-federation/typescript 

הוסף const { ModuleFederationPlugin } = require('webpack').container const deps = require('./package.json').dependencies module.exports = (env, argv) => ({ mode: argv.mode ?? 'development', entry: './src/index.ts', output: { publicPath: 'auto', filename: '[name].[contenthash].js', clean: true, }, plugins: [ new ModuleFederationPlugin({ name: 'catalog', filename: 'remoteEntry.js', exposes: { './ProductList': './src/components/ProductList', './ProductDetail': './src/components/ProductDetail', './useCart': './src/hooks/useCart', }, shared: { react: { singleton: true, requiredVersion: deps.react, }, 'react-dom': { singleton: true, requiredVersion: deps['react-dom'], }, 'react-router-dom': { singleton: true, }, }, }), ], devServer: { port: 3001, headers: { 'Access-Control-Allow-Origin': '*' }, historyApiFallback: true, }, }) לקונפיגורציות של host ו-remote — הטיפוסים נוצרים אוטומטית כ-// src/index.ts import('./bootstrap') // src/bootstrap.tsx import React from 'react' import { createRoot } from 'react-dom/client' import App from './App' const root = createRoot(document.getElementById('root')!) root.render(<App />) . אין יותר Shared module is not available for eager consumption.

CI/CD לפריסה עצמאית

---
name: Deploy Catalog
on:
  push:
    branches: [main]
    paths: ['apps/catalog/**']
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cd apps/catalog && npm ci && npm run build
      - name: Deploy to CDN
        run: aws s3 sync apps/catalog/dist s3://catalog.example.com --delete
      - name: Invalidate CloudFront
        run: aws cloudfront create-invalidation --distribution-id $CF_ID --paths "/*" 
---

ה-host מקבל את ה-remote המעודכן ללא פריסה משלו — בטעינת העמוד הבאה.

מה כלול בעבודה

  • ביקורת על הארכיטקטורה הנוכחית וזיהוי נקודות צמיחה
  • תכנון סכמת remotes ותלויות משותפות
  • קונפיגורציית Webpack עבור host וכל ה-remotes תוך התחשבות בסביבת production
  • אינטגרציית תבנית bootstrap למניעת שגיאות צריכה מוקדמת
  • הגדרת CI/CD עבור כל remote (GitHub Actions או Jenkins)
  • יצירת טיפוסי TypeScript דרך FederatedTypesPlugin
  • תיעוד לפריסה ותמיכה
  • הכשרת צוות בנושא microfrontends

אילו תוצאות אפשר לצפות?

לאחר יישום Module Federation, אתה מקבל: הפחתה של 30-50% בזמן הטעינה, מחזורי פריסה עצמאיים לכל remote, ופחות קונפליקטים בפיתוח. בפרויקט אחד, הקטנו את גודל ה-JS הממוצע מ-1.2 MB ל-680 KB. חיסכון בעלויות תעבורה יכול להיות משמעותי עם תעבורה גבוהה.

טעויות קונפיגורציה נפוצות

  • חוסר npm install @module-federation/typescript עבור React — שכפול תלויות.
  • חוסר FederatedTypesPlugin על תלויות משותפות — שגיאת אתחול.
  • קונפיגורציית CORS שגויה עבור remoteEntry.

כדי ש-remoteEntry יעבוד בין דומיינים שונים, הוסף כותרות @mf-types/catalog/ProductList בשרת המארח את ה-remote. ב-Webpack devServer, זה נעשה דרך אפשרות any. ב-production, דרך שרת האינטרנט או הגדרות CDN. זה חובה.

הזמן יישום — נגדיר את הפרויקט שלך תוך 5–10 ימי עבודה. קבל ייעוץ — צור קשר לביקורת ארכיטקטורה חינמית.