angular-architects / module-federation-plugin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

React MFE inside an Angular Shell

sistla001 opened this issue · comments

I have created an Angular Shell and an Angular MFE according to https://www.angulararchitects.io/en/blog/micro-frontends-with-modern-angular-part-1-standalone-and-esbuild/ which works.
Then I created a react remote app using https://dev.to/abhi0498/react-micro-frontends-using-vite-30ah#setting-up-the-remote-app

I am getting the following error in the console of the shell app when going to http://localhost:4200/react

image

Below is my setup

in vite.config.ts of the React MFE1

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import federation from "@originjs/vite-plugin-federation";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'react-vite-mfe1',
      filename: 'remoteEntry.js',
      exposes: {
        './react-vite-mfe1': './src/App',
      },
      shared: ['react','react-dom']
    })
  ],
  build: {
    target: 'esnext'
  }
})

and in angular shell project, I did the following
federation.manifest.json

{
	"mfe1": "http://localhost:4201/remoteEntry.json",
  "react-vite-mfe1": "http://localhost:4173/assets/remoteEntry.js"
}

app-wrapper component:

import { CommonModule } from '@angular/common';
import { Component, ElementRef, Input, OnInit, inject } from '@angular/core';
import { loadRemoteModule } from '@softarc/native-federation-runtime';

export interface WrapperConfig {
  remoteName: string;
  exposedModule: string;
  elementName: string;
}

export const initWrapperConfig: WrapperConfig = {
  remoteName: '',
  exposedModule: '',
  elementName: '',
}


@Component({
  selector: 'app-wrapper',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './app-wrapper.component.html',
  styleUrls: ['./app-wrapper.component.scss']
})
export class WrapperComponent implements OnInit {
  elm = inject(ElementRef);
  @Input() config = initWrapperConfig;

  async ngOnInit() {
    const { exposedModule, remoteName, elementName } = this.config;

    await loadRemoteModule(remoteName, exposedModule);
    const root = document.createElement(elementName);
    this.elm.nativeElement.appendChild(root);
  }
}

app.routes.ts

import { Routes } from '@angular/router';
import { loadRemoteModule } from '@angular-architects/native-federation';
import { WrapperComponent, WrapperConfig } from './app-wrapper/app-wrapper.component';
import { config } from 'rxjs';

export const routes: Routes = [
  {
    path: '',
    loadComponent: () =>
      loadRemoteModule('mfe1', './Component').then((m) => m.AppComponent),
  },
  {
    path: 'react',
    component: WrapperComponent,
    data: {
      config:{
        remoteName: 'react-vite-mfe1',
        exposedModule: './react-vite-mfe1',
        elementName: 'react-vite-mfe1',
      } as WrapperConfig
    }

  },
];

Any help with this regard is very much appreciated. Thanks!

Can you pls share your code?

Can you pls share your code?

@manfredsteyer - Thanks for your reply. Here is the sample repo I created to demo this - https://github.com/sistla001/mfe-poc

It has 3 projects

  1. ng-shell - Angular shell - npm start serves on localhost:4200
  2. ng-mfe1 - Angular remote - npm start serves on localhost:4201
  3. react-mfe2 - react remote built using @originjs/vite-plugin-federation - npm run preview serves on localhost:4173. I used https://dev.to/abhi0498/react-micro-frontends-using-vite-30ah#setting-up-the-remote-app as an example. remoteEntry.js is http://localhost:4173/assets/remoteEntry.js

http://localhost:4200/mfe1 works!
I am having issue with http://localhost:4200/mfe2

Thanks!

I have also created another route called mfe3 to ng-shell, this route is using app-wrapper2 instead of app-wrapper. I am passing the react_mfe2's remoteEntry.js to this and doing the following instead of using loadRemoteModule from @softarc/native-federation-runtime. This is loading the css but content is not loading, looks like some success. I will keep trying and post my research here. Thanks!

private loadRemoteModule(options: LoadRemoteModuleOptions): Promise<any> {
    return import(options.remoteEntry || '').then((module) => {
      return module.get(options.exposedModule);
    });
  }

@manfredsteyer does native federation supports a remote built using @originjs/module-federation as in this case?

also, is it possible to create a remote using native federation and load using webpack module federation host?