04

Module 4: Angular Module Federation Explained (Webpack 5)

Chapter 4 • Intermediate

35 min

Angular Module Federation Explained (Webpack 5)

Module Federation is a feature of Webpack 5 that allows:

  • Runtime code sharing - Share code between applications at runtime
  • Dynamic module loading - Load modules from remote applications
  • Shared dependencies - Avoid duplicate bundles

In Angular, Module Federation is the technical foundation of Micro Frontends.


What Is Module Federation?

Module Federation enables:

  • One application to consume modules from another application
  • Applications to share dependencies
  • Runtime integration (not build-time)

Traditional Approach (Build-Time)

code
App A ──build──> Bundle A
App B ──build──> Bundle B

No connection at runtime

Module Federation (Runtime)

code
App A ──build──> Bundle A (exposes modules)
App B ──build──> Bundle B (consumes from A)

Runtime connection via Module Federation

Core Concepts

1. Host Application

The application that consumes remote modules:

  • Loads remote modules dynamically
  • Orchestrates the user experience
  • Provides the application shell

2. Remote Application

The application that exposes modules:

  • Exposes specific modules
  • Can run independently
  • Can be consumed by Host

3. Exposed Modules

Modules that Remote makes available:

  • Angular modules
  • Components
  • Services
  • Routes

4. Shared Dependencies

Libraries shared between Host and Remote:

  • Angular core
  • RxJS
  • Common libraries
  • Prevents duplicate bundles

How Module Federation Works

Step 1: Remote Exposes Module

typescript.js
// Remote App Configuration
new ModuleFederationPlugin({
  name: 'products',
  exposes: {
    './ProductsModule': './src/app/products/products.module.ts'
  }
})

Step 2: Host Consumes Remote Module

typescript.js
// Host App Configuration
new ModuleFederationPlugin({
  name: 'host',
  remotes: {
    products: 'products@http://localhost:4201/remoteEntry.js'
  }
})

Step 3: Host Loads Remote Module

typescript.js
// Host App Code
import('products/ProductsModule').then(m => {
  // Use remote module
})

Module Federation Configuration

Remote Application Config

typescript.js
// webpack.config.js (Remote)
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'products', // Unique name
      filename: 'remoteEntry.js', // Entry file
      exposes: {
        './ProductsModule': './src/app/products/products.module.ts'
      },
      shared: {
        '@angular/core': { singleton: true, strictVersion: true },
        '@angular/common': { singleton: true, strictVersion: true },
        '@angular/router': { singleton: true, strictVersion: true }
      }
    })
  ]
}

Host Application Config

typescript.js
// webpack.config.js (Host)
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      remotes: {
        products: 'products@http://localhost:4201/remoteEntry.js',
        checkout: 'checkout@http://localhost:4202/remoteEntry.js'
      },
      shared: {
        '@angular/core': { singleton: true, strictVersion: true },
        '@angular/common': { singleton: true, strictVersion: true },
        '@angular/router': { singleton: true, strictVersion: true }
      }
    })
  ]
}

Shared Dependencies

Why Share?

  • Reduce bundle size - Don't duplicate Angular core
  • Prevent version conflicts - Use same version everywhere
  • Improve performance - Load once, use everywhere

Shared Configuration

typescript.js
shared: {
  '@angular/core': {
    singleton: true,      // Only one instance
    strictVersion: true,   // Must match version exactly
    requiredVersion: '^15.0.0'
  }
}

Singleton vs Multiple Instances

  • singleton: true - One instance shared (recommended for Angular)
  • singleton: false - Each app gets its own instance

Runtime Behavior

Module Loading Flow

  1. User navigates to route
  2. Host detects route belongs to Remote
  3. Host loads remoteEntry.js from Remote
  4. Remote exposes module
  5. Host consumes module
  6. Module renders in Host's container

Network Requests

code
User Request → Host App
              ↓
Host loads: remoteEntry.js (from Remote)
              ↓
Remote exposes: ProductsModule
              ↓
Host renders: ProductsModule in container

Benefits of Module Federation

1. Independent Deployment

  • Remote apps deploy independently
  • Host doesn't need rebuild
  • Changes take effect immediately

2. Code Sharing

  • Share dependencies efficiently
  • Avoid duplicate bundles
  • Better caching

3. Technology Flexibility

  • Different Angular versions (with care)
  • Different build tools
  • Different deployment strategies

4. Team Autonomy

  • Teams work independently
  • No coordination needed
  • Faster development

Limitations

1. Version Compatibility

  • Shared dependencies must be compatible
  • Angular versions should match
  • Breaking changes require coordination

2. Network Dependency

  • Remote apps must be accessible
  • Network latency affects loading
  • Offline scenarios need handling

3. Debugging Complexity

  • Source maps across apps
  • Network debugging required
  • Error tracking more complex

Angular + Module Federation

Angular supports Module Federation through:

  • @angular-architects/module-federation - Official plugin
  • Custom Webpack configuration - Manual setup
  • Angular CLI integration - Seamless workflow

The next module explains Host and Remote application architecture.