rspack_plugin_mf/container/
module_federation_runtime_plugin.rs1use rspack_cacheable::cacheable;
7use rspack_core::{
8 AsyncModulesArtifact, BoxDependency, ChunkUkey, Compilation,
9 CompilationAdditionalTreeRuntimeRequirements, CompilationFinishModules, CompilationParams,
10 CompilerCompilation, CompilerFinishMake, DependencyType, EntryOptions, ExportsInfoArtifact,
11 Plugin, RuntimeGlobals, RuntimeModule, SideEffectsStateArtifact,
12};
13use rspack_error::Result;
14use rspack_hook::{plugin, plugin_hook};
15use serde::Deserialize;
16
17use super::{
18 container_entry_module::ContainerEntryModule,
19 embed_federation_runtime_plugin::EmbedFederationRuntimePlugin,
20 federation_data_runtime_module::FederationDataRuntimeModule,
21 federation_modules_plugin::FederationModulesPlugin,
22 federation_runtime_dependency::FederationRuntimeDependency,
23 hoist_container_references_plugin::HoistContainerReferencesPlugin,
24};
25
26#[derive(Debug, Default, Deserialize, Clone)]
27pub struct ModuleFederationRuntimePluginOptions {
28 pub entry_runtime: Option<String>,
29 #[serde(default)]
30 pub experiments: ModuleFederationRuntimeExperimentsOptions,
31}
32
33#[cacheable]
34#[derive(Debug, Default, Deserialize, Clone, Hash, PartialEq, Eq)]
35pub struct ModuleFederationRuntimeExperimentsOptions {
36 #[serde(default)]
37 pub async_startup: bool,
38}
39
40#[plugin]
41#[derive(Debug)]
42pub struct ModuleFederationRuntimePlugin {
43 options: ModuleFederationRuntimePluginOptions,
44}
45
46impl ModuleFederationRuntimePlugin {
47 pub fn new(options: ModuleFederationRuntimePluginOptions) -> Self {
48 Self::new_inner(options)
49 }
50}
51
52#[plugin_hook(CompilerCompilation for ModuleFederationRuntimePlugin)]
53async fn compilation(
54 &self,
55 compilation: &mut Compilation,
56 params: &mut CompilationParams,
57) -> Result<()> {
58 compilation.set_dependency_factory(
59 DependencyType::FederationRuntime,
60 params.normal_module_factory.clone(),
61 );
62 Ok(())
63}
64
65#[plugin_hook(CompilationAdditionalTreeRuntimeRequirements for ModuleFederationRuntimePlugin)]
66async fn additional_tree_runtime_requirements(
67 &self,
68 compilation: &Compilation,
69 _chunk_ukey: &ChunkUkey,
70 _runtime_requirements: &mut RuntimeGlobals,
71 runtime_modules: &mut Vec<Box<dyn RuntimeModule>>,
72) -> Result<()> {
73 runtime_modules.push(Box::new(FederationDataRuntimeModule::new(
75 &compilation.runtime_template,
76 )));
77
78 Ok(())
79}
80
81#[plugin_hook(CompilerFinishMake for ModuleFederationRuntimePlugin)]
82async fn finish_make(&self, compilation: &mut Compilation) -> Result<()> {
83 if let Some(entry_request) = self.options.entry_runtime.clone() {
84 let federation_runtime_dep = FederationRuntimeDependency::new(entry_request.clone());
85
86 let hooks = FederationModulesPlugin::get_compilation_hooks(compilation);
87
88 hooks
89 .add_federation_runtime_dependency
90 .lock()
91 .await
92 .call(&federation_runtime_dep)
93 .await?;
94
95 let boxed_dep: BoxDependency = Box::new(federation_runtime_dep);
96 let entry_options = EntryOptions::default();
97 let args = vec![(boxed_dep, entry_options)];
98
99 compilation.add_include(args).await?;
100 }
101
102 Ok(())
103}
104
105#[plugin_hook(CompilationFinishModules for ModuleFederationRuntimePlugin, stage = 1000)]
110async fn finish_modules(
111 &self,
112 compilation: &Compilation,
113 async_modules_artifact: &mut AsyncModulesArtifact,
114 _exports_info_artifact: &mut ExportsInfoArtifact,
115 _side_effects_state_artifact: &mut SideEffectsStateArtifact,
116) -> Result<()> {
117 if !self.options.experiments.async_startup {
118 return Ok(());
119 }
120
121 let module_graph = compilation.get_module_graph();
122 for (module_identifier, module) in module_graph.modules() {
123 if module
124 .as_ref()
125 .as_any()
126 .downcast_ref::<ContainerEntryModule>()
127 .is_some()
128 {
129 async_modules_artifact.insert(*module_identifier);
130 }
131 }
132
133 Ok(())
134}
135
136impl Plugin for ModuleFederationRuntimePlugin {
137 fn name(&self) -> &'static str {
138 "rspack.container.ModuleFederationRuntimePlugin"
139 }
140
141 fn apply(&self, ctx: &mut rspack_core::ApplyContext<'_>) -> Result<()> {
142 ctx.compiler_hooks.compilation.tap(compilation::new(self));
143
144 ctx
145 .compilation_hooks
146 .additional_tree_runtime_requirements
147 .tap(additional_tree_runtime_requirements::new(self));
148
149 ctx
150 .compilation_hooks
151 .finish_modules
152 .tap(finish_modules::new(self));
153
154 ctx.compiler_hooks.finish_make.tap(finish_make::new(self));
155
156 EmbedFederationRuntimePlugin::new(self.options.experiments.clone()).apply(ctx)?;
158 HoistContainerReferencesPlugin::default().apply(ctx)?;
159
160 Ok(())
161 }
162}