Arjun RW
Arjun RW

Reputation: 11

Cannot load a MFE Angular app created with NX on host angular integrated with module-federation

I have created an application with:

npx create-nx-workspace@latest angular -monorepo --preset=angular-monorepo

adding a host and a remote application with the Nx extension available in VS Code.

Both are working as expected: running the host will automatically run the remote (at localhost:4204) and in the Nx workspace accessing the host on localhost:4203 and routing to localhost:4203/remote1 will display the remote content in the host.

Host configurations:

app.routes.ts

import { authGuard } from './auth.guard';
import { NxWelcomeComponent } from './nx-welcome.component';
import { Route } from '@angular/router';

export const appRoutes: Route[] = [
  {
    path: 'remote1',
    loadChildren: () => import('remote1/Routes').then((m) => m.remoteRoutes),
    canActivate: [authGuard],
  },
  {
    path: '',
    component: NxWelcomeComponent,
  },
];

module-federation.config.ts

import { ModuleFederationConfig } from '@nx/webpack';

const config: ModuleFederationConfig = {
  name: 'host',
  remotes: ['remote1'],
};
export default config;

Host app:

app.component.html

<ul class="remote-menu">
  <li><a routerLink="/">Home</a></li>
  <li><a routerLink="remote1">Remote1</a></li>
</ul>
<router-outlet></router-outlet>

Remote1 configurations:

app.routes.ts

import { Route } from '@angular/router';

export const appRoutes: Route[] = [
  {
    path: '',
    loadChildren: () =>
      import('./remote-entry/entry.routes').then((m) => m.remoteRoutes),
  },
];

module-federation.config.ts

import { ModuleFederationConfig } from '@nx/webpack';

const config: ModuleFederationConfig = {
  name: 'remote1',
  exposes: {
    './Routes': 'apps/remote1/src/app/remote-entry/entry.routes.ts',
    './RemoteComponent' : 'apps/remote1/src/app/remote-entry/entry.component.ts'
  },
};

export default config;

These are my Nx workspace remote and host app. I need to access remote1 in my Angular application created with ng new host. I added module federation with:

ng add @angular-architects/module-federation --project host --port 4200

webpack.config.js

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: "hostApp",
    publicPath: "auto",
    scriptType: "text/javascript"
  },
  optimization: {
    runtimeChunk: false
  },
  resolve: {
    alias: {
      ...sharedMappings.getAliases(),
    }
  },
  experiments: {
    outputModule: true
  },
  plugins: [
    new ModuleFederationPlugin({
        // library: { type: "Routes" },

        // For remotes (please adjust)
        // name: "hostApp",
        // filename: "remoteEntry.js",
        // exposes: {
        //     './Component': './/src/app/app.component.ts',
        // },

        // For hosts (please adjust)
        remotes: {
            "remote1": "remote1@http://localhost:4204/remoteEntry.mjs",
        },

        // 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()
  ],
};

app.routes.ts

import { loadRemoteModule } from '@angular-architects/module-federation';
import { Routes, RouterModule } from '@angular/router';
import { AppComponent } from './app.component';

export const routes: Routes = [
{ path: "",component: AppComponent},

{path: "remote1", loadChildren: () =>{
    return loadRemoteModule({
    remoteEntry : "http://localhost:4204/remoteEntry.mjs",
    remoteName : "remote1",
    exposedModule: "remote1/RemoteComponent"
    }).then(m => m.RemoteComponentModule).catch(err => console.log(err))
}  
},

];

app.component.html

<ul class="remote-menu">
  <li><a routerLink="/">Home</a></li>
  <li><a routerLink="/remote1">Remote1</a></li>
</ul>
Home Works
<router-outlet></router-outlet>

When I tried running only remote1 with nx serve remote1 on localhost:4204 and running the Angular application with ng serve on localhost:4200 I got these 2 errors and remote1 was not printed:

Error Typerror: container is undefined

For the first one I tried to add the

scriptType: 'text/javascript' 

but that section is not available on the remote app created with Nx.

Upvotes: 0

Views: 188

Answers (1)

Arjun RW
Arjun RW

Reputation: 11

Error Typerror: container is undefined

This error was coming in the console because the components from the remote was actually not actually taken correctly, what I have changed to get the remote nx mfe on native angular module federation I have changed some files in the host app

main.ts file

declare module 'remote/RemoteComponent';
declare module 'remote/Routes';

import('./bootstrap')

    .catch(err => console.error(err));

app.route.ts

{
        path: 'remote',
        loadChildren: () =>
            import('remote2/RemoteComponent')
                .then(() => import('remote/Routes')
                    .then((m) => m.remoteRoutes).catch(err => console.log(err)))
    }

The remoteComponent was taken via the route.

Upvotes: 0

Related Questions