קודקודייל
  • קודקודייל
  • מי אתם קודקודייל?
  • קורסים בחינם
  • צרו קשר
  • בניית אתרים
    • וורדפרס
  • נגישות אתרים
  • כל הקטגוריות
    • אנגולר
    • HTML
    • CSS
    • Javascript
    • Typescript
    • NodeJs
    • בלוקציין
  • קודקודייל
  • מי אתם קודקודייל?
  • קורסים בחינם
  • צרו קשר
  • בניית אתרים
    • וורדפרס
  • נגישות אתרים
  • כל הקטגוריות
    • אנגולר
    • HTML
    • CSS
    • Javascript
    • Typescript
    • NodeJs
    • בלוקציין
קודקודייל
  • קודקודייל
  • מי אתם קודקודייל?
  • קורסים בחינם
  • צרו קשר
  • בניית אתרים
    • וורדפרס
  • נגישות אתרים
  • כל הקטגוריות
    • אנגולר
    • HTML
    • CSS
    • Javascript
    • Typescript
    • NodeJs
    • בלוקציין
  • קודקודייל
  • מי אתם קודקודייל?
  • קורסים בחינם
  • צרו קשר
  • בניית אתרים
    • וורדפרס
  • נגישות אתרים
  • כל הקטגוריות
    • אנגולר
    • HTML
    • CSS
    • Javascript
    • Typescript
    • NodeJs
    • בלוקציין
ראשי ♦ אנגולר ♦ Angular Microfrontend Module Federation Tutorial – Part 3

Angular Microfrontend Module Federation Tutorial – Part 3

עידן יצחקי 17 ביוני 2022 אין תגובות

בחלק זה נראה איך למשוך רכיב מפרויקט אחד ולהטמיע אותו בפרויקט שני ללא צורך בשינוי ניתוב.

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

הפיתרון הראשון והפחות טוב הוא להקים קובץ declaration ולעדכן שם כל רכיב ומודול שמגיע מבחוץ 😂…

כן… אנחנו לא הולכים לעשות משהו כזה, אנחנו מפתחים משמע אנחנו "עצלנים" וצריכים שמשהו יעשה את זה בשבילנו.

הפיתרון השני זה להקים directive והוא יטפל בכל התהלך ויחזיר את הרכיב ל-HTML שלנו.

MFE2

בתוך ספרית APP ניצור ספריה חדשה בשם component ונפתח טרמינל בספריה הזו (CMD).

ניצור 2 רכיבים בספריה :

ng g c main-content
ng g c side-content

נחשוף אותם:

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const mf = require("@angular-architects/module-federation/webpack");
const path = require("path");
const share = mf.share;

const sharedMappings = new mf.SharedMappings();
sharedMappings.register(
  path.join(__dirname, 'tsconfig.json'),
  [/* mapped paths to share */]);

module.exports = {
  output: {
    uniqueName: "mfe2",
    publicPath: "auto"
  },
  optimization: {
    runtimeChunk: false
  },
  resolve: {
    alias: {
      ...sharedMappings.getAliases(),
    }
  },
  experiments: {
    outputModule: true
  },
  plugins: [
    new ModuleFederationPlugin({
      library: { type: "module" },

      // For remotes (please adjust)
      name: "mfe2",
      filename: "mfe2.js",
      exposes: {
        './MainContentComponent': path.resolve(__dirname, './src/app/component/main-content/main-content.component.ts'),
        './SideContentComponent': path.resolve(__dirname, './src/app/component/side-content/side-content.component.ts'),
      },


      shared: share({
        "@angular/core": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
        "@angular/common": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
        "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: 'auto' },
        "@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' },

        ...sharedMappings.getDescriptors()
      })

    }),
    sharedMappings.getPlugin()
  ],
};

הקובץ הזה כבר קיים לכם, צריך רק להוסיף את שורה 35 ו-36.

סיימנו את הצד הזה, עכשיו נעבור לצד שמושך את הרכיבים.

SHELL

בתוך APP ניצור ספריה בשם directives ובתוכה נפתח טרמינל (CMD) ונריץ את הפקודה הבאה:

ng g d creator

נעדכן את הדיירקטיב שלנו כך:

import { loadRemoteModule } from '@angular-architects/module-federation';
import { Directive, Input, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appCreator]'
})
export class CreatorDirective {

  private componentData: ICompData = {} as ICompData;

  @Input('appCreator') set data(value: ICompData) {
    this.componentData = value;
  }

  constructor(private viewContainerRef: ViewContainerRef) { }

  ngOnInit() {
    return this.componentInit()
  }

  private async componentInit() {
    Promise.all([
      loadRemoteModule({
        type: 'module',
        remoteEntry: this.componentData.mfLink,
        exposedModule: './' + this.componentData.module
      }).then(m => {
        console.log('m', m);
        return this.viewContainerRef.createComponent(m[this.componentData.module]);
      }).catch(e => {
        console.log(e);
      })
    ]).catch(e => {
      console.log(e);
    })

  }

}
export interface ICompData {
  module: string,
  mfLink: string
}

שורה 9 – 13: לא חובה לכתוב את זה כך, אפשר להשתמש ב-data בשורה 11 כאינפוט שהוא גם המשתנה שעלה עובדים ואז אין צורך בשורה 9 ואין צורך לבצע SET.

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

שורה 21: בגלל ששורה 23 מחזירה פרומיס אנחנו צריכים לעדכן את הפונקציה שלנו כמשהו לא סינכרוני.

שורה 22: ממתין שכל התהליכים יסתיימו לפני שתחזור תשובה.

שורה 23: פונקציה באדיבות module federation , מקבלת את הנתונים שאנחנו כבר מכירים כדי למשוך את המודול המתאים.

  • type במקרה שלנו תמיד מודול
  • remoteEntry המיקום של הקובץ והשם שלו
  • exposedModule שם המודול שכתבנו ב-MFE2 בקובץ webpack.config.js (שורות 35+36).

שורה 29: אחרי שמשכנו את המודול הנכון, אנחנו רוצים להוציא את הרכיב מתוכו. שם הרכיב הוא לא השם שכתוב ב-exposes אלא שם ה-CLASS ברכיב עצמו שיש עליו export

MFE2

export class MainContentComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

שורה 1: זה השם של הרכיב שלו נקרא ב-SHELL.

ולכן, אם שם ה-expos ושם ה-export אותו דבר אנחנו יכולים לבצע את שורה 29 כמו שהיא כתובה.

במידה שנרצה לנתק את הקשר הזה, אפשר להוסיף לאינטרפייס ערך חדש בשם name ולשנות את שורה 29

מ- m[this.componentData.module] ל- m[this.componentData.name].

כרגע נמשיך כמו שזה כתוב למעלה.

שורה 40 – 43: הגדרה של אינטרפייס, לא לשכוח לשים אותו ב-export כדאי שמקומות אחרים ימשכו אותו.

ב-SHELL, תחת APP ניצור ספריה בשם components, נפתח CMD בתוך components ונריץ את הפקודה:

ng g c content

לאחר מכן נבצע את השינויים הבאים:

import { Component, Input, OnInit } from '@angular/core';
import { ICompData } from 'src/app/directives/creator.directive';

@Component({
  selector: 'app-content',
  templateUrl: './content.component.html',
  styleUrls: ['./content.component.scss']
})
export class ContentComponent implements OnInit {
  private _componentData: ICompData = {} as ICompData;
  @Input() set componentData(value: ICompData) {
    this._componentData = value;
  }
  get componentData() {
    return this._componentData;
  }
  constructor() { }

  ngOnInit(): void {
  }

}
<div class="border">
    <p>content works!</p>
    <ng-template [appCreator]="componentData" *ngIf="componentData.mfLink">
    </ng-template>
</div>
.border {
    border: 1px solid rebeccapurple;
    margin: 5px;
}

אפשר להגיד שהכל מוכן, עכשיו כל מה שאנחנו צריכים זה לשים את content באיזה html שנרצה וניתן לו את המידע שהוא צריך.

בפרויקט SHELL נפתח בתוך ספרית APP, ספריה נוספת בשם PAGES ובתוכה נפעיל טרמינל

ng g c home

את הרכיב home נשנה כך:

import { Component, OnInit } from '@angular/core';
import { ICompData } from 'src/app/directives/creator.directive';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
  public main: ICompData = { module: 'MainContentComponent', mfLink: 'http://localhost:3001/mfe2.js' };
  public side: ICompData = { module: 'SideContentComponent', mfLink: 'http://localhost:3001/mfe2.js' };
  constructor() { }

  ngOnInit(): void {
  }

}
<p>home works!</p>
<app-content [componentData]="main"></app-content>
<app-content [componentData]="side"></app-content>

דבר אחרון, נעדכן את הראוט שלנו כדי שיעלה את HOME

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'lazy', loadChildren: () => import('mfe1/MainModule').then(m => {
      console.log(m);
      
      return m.MainModule;
    })
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

כאשר הפרויקט יעלה, אנחנו נראה את דף הבית עם עוד 2 רכיבים שהגיעו מ-MFE2.

בחלק הבא נשנה את הדיירקטיב כך שידע להתמודד עם רכיב או עם מודול לבד (נעשה אותו קצת יותר חכם).😵

פוסטים קשורים:

angular micro-frontendAngular Microfrontend Module Federation Tutorial – Part 2 angular micro-frontendAngular Microfrontend Module Federation Tutorial – Part 1 אפשרויותAngular nested routes תמונת אווירה של אותיות צבעוניותSEO| שינוי כותרת של הדף באנגולר
angular אנגולר לימודי אנגולר מדריך אנגולר

אודות המחבר

עידן יצחקי להציג את כל הפוסטים של עידן יצחקי


« פוסט קודם
פוסט הבא »

השארת תגובה

ביטול

חיפוש באתר
בחירת העורכים
29 בדצמבר 2023 עידן יצחקי

שדה טקסט עשיר עם תמונות

אתם הולכים להיות מופתעים עד כמה HTML יכול להיות חכם ולבצע משהו כל כך מורכב, שאם אנחנו היינו רוצים ליצור

1 באוקטובר 2021 עידן יצחקי

איך למשוך דינמית favicon של אתרים אחרים ב-JS

בפוסט זה נראה איך אפשר על פי לינקים בדף למשוך את ה-favicon מהדומיין שלהם באופן דינמי, בדיקה של תקינות התמונה

פופולרי
Javascript functions – היכרות עם סוגי פונקציות
Javascript
21 בדצמבר 2024 אין תגובות
Nested routing in angular standalone component
Typescript
15 בנובמבר 2024 תגובה אחת
בחרו לפי תגיות
angular blockchain css ethers express front-end fullstack GQL html javascript next js nextjs nodejs react hooks reactjs solidity webgl אנגולר בלוקציין וורדפרס לימודי אנגולר לימודי וורדפרס לימוד ריאקט מדריך front-end מדריך GQL מדריך אנגולר מדריך וורדפרס מדריך חינם react מדריך ריאקט מפתח בלוק מפתח בלוקציין מתכנת front-end מתכנת בלוקציין מתכנת פרונט סולידיטי קורס front end קורס fullstack קורס nextjs קורס אנגולר קורס בלוקציין קורס בלוקציין בחינם קורס סולידיטי קורס ריאקט קורס תכנות קורס תכנות בחינם
סינון על פי קטגוריות
CSS fullstack HTML IIS Javascript nodeJs SEO Typescript אנגולר בלוקציין בניית אתרים וורדפרס חיפוש עבודה כלים נוספים כללי נגישות קורסים ריאקט תלת מימד תקלות ופתרונות
צור קשר
כל הזכויות שמורות לקודקודייל
ליצירת קשר: @ קודקודייל
גלילה לראש העמוד