DEV Community

Discussion on: Angular dynamic modules at runtime with Module Federation

Collapse
 
gr4vitonn profile image
gr4vitonn • Edited

Hello Sean,

Great article. Thank you for sharing.

I'm trying to do what you advise against: exposing AppModule and AppComponent.

So what I'm trying to achieve is the following:

  • have a host which lazily loads the remote on specific route
  • have a remote which has its own routes which lazily load modules

With your advice the code structure at remote app level will look like:
app.module.ts
|- feature.module.ts
_
_|- sub-feature1.module.ts
_
_|- sub-feature2.module.ts

By exposing tha app.module.ts and app.component.ts I would only have 1 router-outlet and flat structure at remote app level:
app.module.ts
_ |- feature1.module.ts
_ |- feature2.module.ts

Unfortunately I hit the wall with this approach (exposing the app.module.ts and app.component.ts). When the host loads the remote, the remote's sub-route gets loaded in the host's router-outlet, without running the remote's app.component.ts (nothing runs from the remote's app.component.ts and the content of app.component.html is not rendered).

So I figured I can enforce it by using named outlets. However it just breaks the app completely.

I also tried to rename the remote's app.component and app.module to avoid possible name collision, but nothing changed.

Do you know what causes the problem?

Collapse
 
seanperkins profile image
Sean Perkins

In your example, does the feature.module.ts have a component with a router outlet and a router module declaration for forChild([...])? By exposing feature.module.ts in your remote's webpack config, you should be able to something similar to this in your shell/root's app routing module:

RouterModule.forRoot([
   {
       path: 'feature-path',
       loadChildren: () => loadRemoteModule({
            remoteEntry: 'http://localhost:xxxx/remoteEntry.js',
            remoteName: 'remoteExampleName',
            exposedModule: './FeatureModule'
       }).then(m => m['FeatureModuleName'])
   }
])
Enter fullscreen mode Exit fullscreen mode

This should lazy-load your remote app's feature module contents when navigating to /feature-path and then defer to that module's structure for further nested lazy loading. I've done something similar where my shell loads different authentication experiences under the /authentication namespace and certain auth experiences have further lazy loading for forgot password & user registration screens.

If you can statically declare the module federation information, it's much easier. Otherwise, you'll have to have that information in a config and pass static tokens into the app module of the shell and override the ROUTES token as shown above.

If you eco-system is small enough or not having live reloading against the remote isn't a deal breaker, you can federate the AppModule from the remote and not run into any issues.