Skip to content

Conversation

@ScriptedAlchemy
Copy link
Member

🎯 Overview

This PR implements the standardized unload/teardown API for remote modules as requested in issue #4160.

🔧 Changes Made

1. Enhanced RemoteHandler Hook System

  • Added beforeUnloadRemote and afterUnloadRemote hooks for extensibility
  • Allows plugins to extend unload behavior if needed

2. Public RemoteHandler.unloadRemote() Method

  • Added comprehensive public method with proper error handling and logging
  • Validates remote existence before attempting unload
  • Emits hooks for plugin integration
  • Delegates to existing battle-tested removeRemote() cleanup logic

3. ModuleFederation Core Class Integration

  • Added unload(remoteName: string): Promise<void> method
  • Follows existing architectural patterns
  • Delegates to RemoteHandler for consistency

4. Runtime Package API

  • Added global unloadRemote() function following the same pattern as other runtime functions
  • Provides the exact API requested in the issue

🚀 API Usage

The implementation provides exactly what was requested in the issue:

// Global API usage (as requested in the issue)
import { unloadRemote } from '@module-federation/runtime';

// After navigating away from the remote component
await unloadRemote('myWonderfulModule');
// Instance-based API usage
import { createInstance } from '@module-federation/runtime';

const federationInstance = createInstance({ name: 'host' });
await federationInstance.unload('myWonderfulModule');

🧹 Comprehensive Cleanup Process

The unload API leverages the existing comprehensive cleanup functionality that handles:

  1. Module Cache Cleanup: Removes cached Module instances
  2. Global State Cleanup: Deletes global container references and loading promises
  3. Shared Dependencies Cleanup: Removes unused shared dependencies and updates tracking
  4. Instance Management: Removes from federation instances registry
  5. Manifest Cleanup: Clears cached manifest data
  6. Snapshot Cleanup: Removes remote info from host snapshots
  7. DOM Cleanup: Removes script tags and nullifies global references

✅ Quality Assurance

  • TypeScript Compilation: All packages compile successfully with no errors
  • Build Verification: Both nx build runtime-core and nx build runtime pass
  • Architectural Consistency: Follows existing codebase patterns and conventions
  • Hook System Integration: Extensible through the plugin system
  • Error Handling: Proper logging and error management

🎉 Benefits Delivered

  • ✅ Solves the memory leak problem described in issue Implement standardized unload/teardown API for remote modules #4160
  • ✅ Provides official, stable API for module unloading
  • ✅ Eliminates need for fragile workarounds with private Webpack APIs
  • ✅ Maintains architectural consistency with existing codebase
  • ✅ Includes comprehensive cleanup (cache, DOM, shared dependencies, etc.)
  • ✅ Extensible through hook system for advanced use cases

Fixes #4160

- Add unload hooks (beforeUnloadRemote, afterUnloadRemote) to RemoteHandler
- Add public unloadRemote method to RemoteHandler with comprehensive error handling
- Add unload method to ModuleFederation core class
- Expose unloadRemote function in runtime package for global API access
- Leverage existing comprehensive cleanup functionality in removeRemote
- Provides official API to address memory leaks in long-running SPAs
- Eliminates need for fragile workarounds with private Webpack APIs

Fixes #4160
@ScriptedAlchemy ScriptedAlchemy self-assigned this Nov 3, 2025
@changeset-bot
Copy link

changeset-bot bot commented Nov 3, 2025

⚠️ No Changeset found

Latest commit: b1b8a60

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@netlify
Copy link

netlify bot commented Nov 3, 2025

Deploy Preview for module-federation-docs ready!

Name Link
🔨 Latest commit b1b8a60
🔍 Latest deploy log https://app.netlify.com/projects/module-federation-docs/deploys/6908e65871bf93000837a674
😎 Deploy Preview https://deploy-preview-4180--module-federation-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +483 to +489
async unloadRemote(remoteName: string): Promise<void> {
const { host } = this;
const remote = host.options.remotes.find(
(item) => item.name === remoteName,
);

if (!remote) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve remotes by alias when unloading

The new unload API searches host.options.remotes using only remote.name. Many remotes are registered with an alias and all load requests are issued via that alias (loadRemote('alias/...')). Callers that only know the alias will invoke unloadRemote('alias') and hit the warning path, leaving the remote’s modules, cached state, and script tags intact. To keep the API symmetric with loadRemote and avoid leaked resources, the lookup should handle aliases (or reuse matchRemoteWithNameAndExpose) before deciding that a remote is unknown.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement standardized unload/teardown API for remote modules

2 participants