Skip to content

feat(plugin_mf): Module Hoisting, Entry initialization via __webpack_require__.x, Custom Hooks #10524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 37 commits into
base: main
Choose a base branch
from

Conversation

ScriptedAlchemy
Copy link
Contributor

@ScriptedAlchemy ScriptedAlchemy commented May 30, 2025

Summary

This pull request introduces significant enhancements to the Module Federation system by implementing new runtime modules, plugins, and dependency management features. The changes focus on enabling runtime dependency tracking, improving federation runtime initialization, and adding new hooks for better plugin communication.

Module Federation Enhancements:

  • Embed Federation Runtime Module: Added a new runtime module, EmbedFederationRuntimeModule, which ensures federation runtime dependencies execute before other modules by wrapping the startup function. This module generates a startup wrapper pattern to manage execution order. (crates/rspack_plugin_mf/src/container/embed_federation_runtime_module.rs)

  • Embed Federation Runtime Plugin: Introduced EmbedFederationRuntimePlugin to manage federation runtime initialization. It adds runtime requirements to federation-enabled chunks, injects the EmbedFederationRuntimeModule into runtime chunks, and handles explicit startup calls for entry chunks. (crates/rspack_plugin_mf/src/container/embed_federation_runtime_plugin.rs)

  • Federation Runtime Dependency: Implemented a new dependency type, FederationRuntimeDependency, to track runtime dependencies for federation modules. This dependency is cacheable and integrates with the existing dependency system. (crates/rspack_plugin_mf/src/container/federation_runtime_dependency.rs)

Plugin Communication and Hooks:

  • Federation Modules Plugin: Added FederationModulesPlugin, a central hook management system for Module Federation. It provides hooks for plugins to share dependency information and communicate through a publish-subscribe pattern. (crates/rspack_plugin_mf/src/container/federation_modules_plugin.rs)

  • Runtime Module for Federation: Added FederationRuntimeModule, a runtime module that initializes the federation runtime environment. It includes a chunk matcher and root output directory logic to support federation runtime initialization. (crates/rspack_plugin_mf/src/container/federation_runtime_module.rs)

Additional Changes:

  • New Options for Module Federation Runtime Plugin: Added RawModuleFederationRuntimePluginOptions to support custom configurations like entry_runtime and runtime_chunk. These options are used to initialize the ModuleFederationRuntimePlugin. (crates/node_binding/src/raw_options/raw_builtins/raw_mf.rs)

  • Dependency Updates: Updated Cargo.toml to include new dependencies such as rspack_plugin_javascript and rspack_sources, which are required for the new runtime modules and plugins. (crates/rspack_plugin_mf/Cargo.toml)

Checklist

Other notes

Should reduce bundle size by 70kb per entrypoint when there are multiple entrypoints with runtimeChunk: single

  • Tests updated (or not required).
  • Documentation updated (or not required).

…bedFederationRuntimePlugin with startup logic injection, FederationRuntimeModule for initialization, and proper runtime requirements handling. Migrated from JS to Rust for better performance and webpack compatibility.
…move all dbg! macros, debug_runtime_globals function, and related debug code - Code now runs cleanly without verbose debug output while maintaining full functionality - Federation runtime initialization and startup logic injection still work correctly
…gs - Convert multiple-entrypoints, multiple-runtime-chunk, and multiple-entrypoints-1 test cases - Update import statements to use @rspack/core.container instead of webpack dist - Add proper TypeScript type annotations for rspack Configuration - Remove deprecated webpack.config.js files after verification - Maintain identical functionality and configuration options
…ntime initialization - Core implementation with oldStartup wrapper pattern - Handles all federation chunk scenarios - Fixed container-1-5 test dependencies
…s and options field from EmbedFederationRuntimePlugin
… field - Remove unused ChunkGraph import from embed_federation_runtime_plugin - Fix needless borrows by removing & from string literals - Replace unwrap() calls with expect() calls with descriptive messages - Remove unnecessary #[allow(dead_code)] annotations where appropriate - Add #[derive(Default)] instead of manual Default implementation - Add missing runtime_chunk field to RawModuleFederationRuntimePluginOptions - Update node binding conversion to include runtime_chunk field All clippy warnings resolved and tests passing (2337/2338)
…er plugins - Remove all println! debugging statements from embed_federation_runtime_plugin.rs - Remove all println! debugging statements from embed_federation_runtime_module.rs - Clean up console output for production readiness
… - Add detailed module-level documentation for EmbedFederationRuntimeModule explaining runtime initialization - Add comprehensive plugin documentation for EmbedFederationRuntimePlugin covering chunk handling strategy - Document FederationModulesPlugin as the central hook management system - Explain HoistContainerReferencesPlugin optimization features and processing strategy - Document ModuleFederationRuntimePlugin as the main orchestration plugin - Update ContainerPlugin documentation to reflect federation hook integration - All documentation includes key features, responsibilities, and usage patterns
…ith detailed chunk handling - Update top-level documentation to clearly explain what gets added to different chunk types - Add detailed explanations for Runtime Chunks, Entry Chunks (Delegating), and Entry Chunks (With Own Runtime) - Include activation conditions and when the plugin processes chunks - Add comprehensive inline comments explaining the three scenarios in render_startup - Document the specific purpose of EmbedFederationRuntimeModule injection in runtime chunks - Clarify when explicit startup calls are added vs when JavaScript plugin handles them naturally
…Fix misunderstanding about STARTUP runtime requirement purpose - STARTUP signals creation of __webpack_require__.startup function for entry module execution - Not specifically for federation initialization, but for webpack startup mechanism - Update comments to reflect that STARTUP enables callable startup function creation - Clarify that our plugin wraps the startup function rather than creating federation-specific logic - Explain the relationship between startup function creation and entry module execution deferral
…tation - Remove verbose explanations and keep only essential information - Simplify module-level documentation to concise descriptions - Streamline inline comments to be brief and relevant - Remove redundant sections like detailed feature lists and usage patterns - Keep only core functionality descriptions and necessary technical details - Maintain clarity while reducing documentation verbosity
Copy link

netlify bot commented May 30, 2025

Deploy Preview for rspack canceled.

Name Link
🔨 Latest commit f50ac94
🔍 Latest deploy log https://app.netlify.com/projects/rspack/deploys/683a39749fc65b00085d5b8c

@github-actions github-actions bot added the release: feature release: feature related release(mr only) label May 30, 2025
…hange 'Federation runtime initialization call' to 'Federation startup call' - Keep comment concise and to the point
…in - Simplify 'Add the original FederationRuntimeModule' to 'Add base FederationRuntimeModule' - Remove verbose TokioMutex comments and keep only essential code - Add concise 'Apply supporting plugins' comment for clarity - Remove unnecessary import comments
…Remove detailed documentation sections to keep only essential code - Align with simplified documentation approach for container plugins
}

// Generate oldStartup wrapper pattern
let result = format!(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

patch webpack_require.x which is entry startup function.

first initialize federation, then call previous startup if exists - if it exists, it will be webpack require of entrypoint module.

If startup doesnt exist in entrypoint bootstrap, like in single runtime chunk, another plugin will manually add require.x() to the entrypoint chunks at the begenning of startup

@@ -0,0 +1,244 @@
//! # EmbedFederationRuntimePlugin
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Embeds the module federation runtime module into runtime chunks, handles management of startup calls and rendering the startup of entrypoints.

define_hook!(AddRemoteDependencyHook: Series(dependency: &dyn Dependency));

// Struct to hold instances of the hooks for a specific compilation
pub struct FederationModulesPluginCompilationHooks {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

adds compilation hooks module federation so that communication between all plugins and modules can be simplified.

For instance we need to know when container plugin is added, we need to know when federation runtime dependency is injected, and have to track various modules in the graph throughout the compilation.

}

#[plugin_hook(CompilerFinishMake for ModuleFederationRuntimePlugin)]
async fn finish_make(&self, compilation: &mut Compilation) -> Result<()> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

instead of injecting a entrypoint or patching entry dependencies into each entrypoint. We will use a dependency to addInclude the module.

This will inject it with no require calls, so that our runtime module can handle startup of federation ahead of the entrypoint.

@@ -0,0 +1,388 @@
//! # HoistContainerReferencesPlugin
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Due to a bug in webpack, when using runtime chunk single, container reference modules which are external modules, as well as the federation runtime are injected into each entrypoint.

This causes initialization to fail because not all container reference modules exist in the module tree at initialization, to correct this - we will hoist these modules into the runtime chunks and remove / clean up the modules from whatever chunk they were in - we also hoist the federation runtime entry module and any referencing modules found - so that even after split chunks, these modules are always in runtime chunks for eager startup ahead of entry - also removes duplication of runtime code in all entrypoints.

… - Remove all references to "matching TypeScript implementation" - Simplify verbose comments about module collection and runtime chunks - Streamline comments about dependency processing and chunk hoisting - Remove redundant explanations while keeping essential information - Make comments more concise and focused on functionality
Copy link

codspeed-hq bot commented May 30, 2025

CodSpeed Performance Report

Merging #10524 will not alter performance

Comparing hoist-container-references (f50ac94) with main (ac67c6b)

🎉 Hooray! codspeed-rust just leveled up to 2.7.2!

A heads-up, this is a breaking change and it might affect your current performance baseline a bit. But here's the exciting part - it's packed with new, cool features and promises improved result stability 🥳!
Curious about what's new? Visit our releases page to delve into all the awesome details about this new version.

Summary

✅ 12 untouched benchmarks

let has_runtime = chunk.has_runtime(&compilation.chunk_group_by_ukey);
if has_runtime {
// Collect federation dependencies snapshot
let collected_ids_snapshot = self
Copy link
Contributor Author

Choose a reason for hiding this comment

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

hooks work a little different, since i cannot nest hooks easily, i am passing the tap results from the parent

Ok(())
}

#[plugin_hook(CompilationOptimizeChunks for HoistContainerReferencesPlugin, stage = Compilation::OPTIMIZE_CHUNKS_STAGE_ADVANCED + 1)]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

perform this after split chunks plugin runs to correct the results.

@ScriptedAlchemy ScriptedAlchemy marked this pull request as ready for review May 30, 2025 09:32
@chenjiahan chenjiahan requested a review from ahabhgk June 3, 2025 01:17
@ahabhgk
Copy link
Contributor

ahabhgk commented Jun 3, 2025

This seems fix #7417 since the federation runtime is injected by runtime module instead of entry

Copy link
Contributor

@ahabhgk ahabhgk left a comment

Choose a reason for hiding this comment

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

LGTM

@ScriptedAlchemy
Copy link
Contributor Author

Yeah this fixed workers in v1 webpack
V2 may need some extra adjustment but it'll likely fix the bundler side and if theres any remaining issue it'll be that I need to add importScript to my runtime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release: feature release: feature related release(mr only)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants