Skip to content

Feature Request: Lifecycle Hooks / Events for Remote Module Loading (Angular Native Federation) #8

@shankaryadavy9

Description

@shankaryadavy9

When using loadRemoteModule() in Angular routing (loadChildren / loadComponent), the entire navigation is blocked until the remote's remoteEntry.json and subsequent ES modules are fetched and evaluated.

Currently, this loading process happens outside Angular's Router lifecycle and Zone, making it impossible to reliably show a loading indicator (spinner/skeleton/shimmer) while the remote microfrontend is being fetched.

A lifecycle hook or observable event system would allow host applications to display proper loading states during remote module resolution.


Problem

When using loadRemoteModule() inside Angular router configuration:

{
  path: 'mfe',
  loadChildren: () =>
    loadRemoteModule({
      type: 'module',
      remoteEntry: 'https://remote.app/remoteEntry.json',
      exposedModule: './Module'
    }).then(m => m.RemoteModule)
}

Navigation fully blocks until:

  1. remoteEntry.json is fetched
  2. Remote container is initialized
  3. All required chunks are loaded via native import()

During this period:

  • The host shell component does not render
  • No Angular router events correspond to this loading phase
  • Native import() calls cannot be intercepted
  • There is no place to render a loading UI

As a result, users experience blank screen delays during MFE loading.


What We Tried

1. Router Events

router.events.subscribe(...)

Events like:

  • NavigationStart
  • NavigationEnd

do not correlate with actual MFE loading time, since the router waits internally for loadChildren() to resolve.


2. Patching window.fetch

const originalFetch = window.fetch;
window.fetch = (...args) => {
  if (args[0].includes('remoteEntry')) {
    showLoading();
  }
  return originalFetch(...args);
};

Problem:

  • Only captures remoteEntry.json
  • The slowest part is the subsequent import() calls
  • Native import() cannot be intercepted

Core Issue

The host shell component does not render until loadChildren() resolves.

Since the remote module loading happens before Angular renders anything:

  • There is no DOM available to show loading placeholders
  • Even if we intercept remoteEntry.json, Angular renders only after all import() calls finish, making the loading state useless.

Proposed Feature

Provide lifecycle events for remote module loading.


Option 1 — Global Observable

import { federationEvents$ } from '@angular-architects/native-federation';

federationEvents$.subscribe(event => {
  if (event.type === 'loadStart') showShimmer(event.remoteName);
  if (event.type === 'loadEnd')   hideShimmer(event.remoteName);
});

Example event payload:

type FederationEvent =
  | { type: 'loadStart'; remoteName: string; exposedModule: string }
  | { type: 'loadEnd'; remoteName: string; exposedModule: string }
  | { type: 'loadError'; remoteName: string; error: unknown };

Option 2 — Hook inside loadRemoteModule

loadRemoteModule({
  remoteEntry,
  exposedModule,
  onLoadStart: () => showLoader(),
  onLoadEnd: () => hideLoader()
});

Option 3 — Angular Router Integration

Expose a router-compatible event:

RouterEvent: RemoteModuleLoadStart
RouterEvent: RemoteModuleLoadEnd

Similar to Angular's:

  • RouteConfigLoadStart
  • RouteConfigLoadEnd

Expected Benefits

This feature would allow:

  • Showing spinners/skeletons/shimmer placeholders
  • Performance tracking of remote loading
  • Error handling for remote module failures
  • Better UX when loading microfrontends

Environment

Angular: 21
Native Federation: latest
Usage: loadRemoteModule() with loadChildren and loadComponent


If useful, I can also provide a reproduction repository demonstrating the issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions