DEV Community

Ruben
Ruben

Posted on

How to load an MFE module from a shell app (Using Angular + Webpack + Module Federation)?

Hi everyone, I have question for you. Do you know how load an MFE (micro front end) remote app, as a module from a shell app? when I try to do so there is an infinite loop. and the module from the MFE does not show. Any tips or ideas on how to accomplish this issue? (Using Angular + Webpack + Module Federation)

// webpack.config.js--SHELL APP 

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const path = require("path");

module.exports = {
    output: {
        uniqueName: "portalWebApp",
        publicPath: "auto",
        scriptType: "text/javascript",
    },
    optimization: {
        runtimeChunk: false,
    },
    resolve: {
        alias: {},
    },
    module: {
        rules: [{
            test: /\.html$/,
            use: ["html-loader"],
        }, ],
    },
    experiments: {
        outputModule: true,
    },
    plugins: [
        new ModuleFederationPlugin({
            // For remotes (please Add this 5 Line)
            name: "portalWebApp",
            filename: "remoteEntry.js",
            remotes: {
                astrPortFolioMasterWebApp: "astrPortFolioMasterWebApp@http://localhost:3002/remoteEntry.js",
                mfe1: "mfe1@http://localhost:4001/remoteEntry.js",
            },

            shared: {
                "@angular/core": {
                    singleton: true,
                    strictVersion: true,
                    eager: true
                },
                "@angular/common/": {
                    singleton: true,
                    strictVersion: true,
                    eager: true,
                },
                "@angular/router": {
                    singleton: true,
                    strictVersion: true,
                    eager: true,
                }
                // react: { singleton: true, eager: true },
                // "react-dom": { singleton: true, eager: true },
            },
        }),
    ],
};

// webpack.config.js--SHELL APP--END

// SHELL APP - Route

import { loadRemoteModule } from '@angular-architects/module-federation';
import { WebComponentWrapper, WebComponentWrapperOptions } from '@angular-architects/module-federation-tools';
import { Routes } from '@angular/router';
import { MsalGuard } from '@azure/msal-angular';
// import { MsalGuard } from '@azure/msal-angular';
// import { UserNotAllowedComponent } from './layout/user-not-allowed/user-not-allowed.component';
// import { ServerErrorComponent } from './layout/server-error/server-error.component';

export const routes: Routes = [{
        path: '',
        pathMatch: 'full',
        loadChildren: () =>
            import('./content-providers/content-provider.module').then(
                (m) => m.ContentProviderModule
            ),
        canActivate: [MsalGuard],
    },
    {
        path: 'mfe1',
        loadChildren: () => {
            return loadRemoteModule({
                    type: 'module',
                    remoteEntry: 'http://localhost:4001/remoteEntry.js',
                    exposedModule: './OrderModule',
                })
                .then((m) => m.OrderModule)
                .catch((e) => console.log(e));
        },
    },
    {
        path: 'astrPortFolioMasterWebApp',
        loadChildren: () => {
            return loadRemoteModule({
                    type: 'module',
                    remoteEntry: 'http://localhost:3002/remoteEntry.js',
                    exposedModule: './astrPortFolioMasterWebAppModule',
                })
                .then((m) => m.astrPortFolioMasterWebAppModule)
                .catch((e) => console.log(e));
        },
    },
    {
        path: 'angular1',
        component: WebComponentWrapper,
        data: {
            remoteEntry: 'https://nice-grass-018f7d910.azurestaticapps.net/remoteEntry.js',
            remoteName: 'angular1',
            exposedModule: './web-components',
            elementName: 'angular1-element',
        }
        as WebComponentWrapperOptions,
    },
    {
        path: 'react1',
        component: WebComponentWrapper,
        data: {
            remoteEntry: 'https://witty-wave-0a695f710.azurestaticapps.net/remoteEntry.js',
            remoteName: 'react',
            exposedModule: './web-components',
            elementName: 'react-element',
        }
        as WebComponentWrapperOptions,
    },
    {
        path: 'vue',
        component: WebComponentWrapper,
        data: {
            remoteEntry: 'https://mango-field-0d0778c10.azurestaticapps.net/remoteEntry.js',
            remoteName: 'vue',
            exposedModule: './web-components',
            elementName: 'vue-element',
        }
        as WebComponentWrapperOptions,
    },
];


// SHELL APP - Route 

// webpack.config.js--MFE / REMOTE APP 

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const { shareAll, SharedMappings } = require("@angular-architects/module-federation/webpack");
const Path = require("path");
const sharedMappings = new SharedMappings();

sharedMappings.register(
    Path.join(__dirname, 'tsconfig.json'), []
)
module.exports = {
    output: {
        uniqueName: "astrPortFolioMasterWebApp",
        publicPath: "auto",
        scriptType: "text/javascript",
    },
    optimization: {
        runtimeChunk: false
    },
    resolve: {
        alias: {
            ...sharedMappings.getAliases(),
        }
    },
    experiments: {
        outputModule: true
    },
    plugins: [
        new ModuleFederationPlugin({

            // For remotes (please Add this 5 Line)
            name: "astrPortFolioMasterWebApp",
            filename: "remoteEntry.js",
            exposes: {
                './astrPortFolioMasterWebAppModule': './src/app/layout/layout.module.ts',
            },

            shared: {
                "@angular/core": {
                    singleton: true,
                    strictVersion: true,
                    eager: true
                },
                "@angular/common/": {
                    singleton: true,
                    strictVersion: true,
                    eager: true
                },
                "@angular/router": {
                    singleton: true,
                    strictVersion: true,
                    eager: true
                },
            }
        }),
        sharedMappings.getPlugin()
    ]
};

// webpack.config.js--MFE / REMOTE APP - END 

// MFE - Remote - Route 

import { Routes } from '@angular/router';
import { MsalGuard } from '@azure/msal-angular';
import { UserNotAllowedComponent } from './layout/user-not-allowed/user-not-allowed.component';
import { ServerErrorComponent } from './layout/server-error/server-error.component';

export const routes: Routes = [
    // {
    //   path: '',
    //   pathMatch: 'full',
    //   redirectTo: 'portfolio'
    // },
    {
        path: 'portfolio',
        loadChildren: () =>
            import('./layout/layout.module').then((m) => m.MainLayoutModule),
        canActivate: [MsalGuard]
    },

    {
        path: 'usernotallowed',
        component: UserNotAllowedComponent,
    },

    {
        path: '**',
        component: ServerErrorComponent,
    },
];

// MFE - Remote - Route - END 
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay