@@ -7,11 +7,12 @@ use derive_more::Debug;
77use futures:: future:: BoxFuture ;
88use rspack_collections:: { Identifiable , IdentifierMap } ;
99use rspack_core:: {
10- BoxDependency , ChunkByUkey , ChunkNamedIdArtifact , ChunkUkey , Compilation , CompilationChunkIds ,
11- CompilationParams , CompilationRuntimeRequirementInTree , CompilerCompilation , CompilerDone ,
12- CompilerFailed , CompilerFinishMake , CompilerThisCompilation , Dependency , DependencyId ,
13- DependencyType , EntryDependency , EntryOptions , Logger , Plugin , RuntimeGlobals , RuntimeModule ,
14- RuntimeSpec , get_entry_runtime,
10+ BoxDependency , ChunkByUkey , ChunkNamedIdArtifact , ChunkUkey , Compilation ,
11+ CompilationAdditionalModuleRuntimeRequirements , CompilationChunkIds , CompilationParams ,
12+ CompilationRuntimeRequirementInTree , CompilerCompilation , CompilerDone , CompilerFailed ,
13+ CompilerFinishMake , CompilerThisCompilation , Dependency , DependencyId , DependencyType ,
14+ EntryDependency , EntryOptions , Logger , Module , ModuleIdentifier , Plugin , RuntimeGlobals ,
15+ RuntimeModule , RuntimeSpec , get_entry_runtime,
1516} ;
1617use rspack_error:: { Diagnostic , Result , ToStringResultToRspackResultExt } ;
1718use rspack_hook:: { plugin, plugin_hook} ;
@@ -21,6 +22,7 @@ use crate::{
2122 component_info:: { ClientComponentImports , collect_component_info_from_entry_dependency} ,
2223 constants:: { CSS_REGEX , LAYERS_NAMES } ,
2324 coordinator:: Coordinator ,
25+ ensure_server_actions_runtime_module:: RscEnsureServerActionsRuntimeModule ,
2426 hot_reloader:: track_server_component_changes,
2527 loaders:: action_entry_loader:: ACTION_ENTRY_LOADER_IDENTIFIER ,
2628 manifest_runtime_module:: RscManifestRuntimeModule ,
@@ -181,9 +183,77 @@ async fn runtime_requirements_in_tree(
181183 Box :: new ( RscManifestRuntimeModule :: new ( & compilation. runtime_template ) ) ,
182184 ) ) ;
183185 }
186+ if runtime_requirements. contains ( RuntimeGlobals :: RSC_ENSURE_SERVER_ACTIONS ) {
187+ runtime_modules_to_add. push ( (
188+ * chunk_ukey,
189+ Box :: new ( RscEnsureServerActionsRuntimeModule :: new (
190+ & compilation. runtime_template ,
191+ ) ) ,
192+ ) ) ;
193+ }
184194 Ok ( None )
185195}
186196
197+ #[ plugin_hook( CompilationAdditionalModuleRuntimeRequirements for RscServerPlugin , tracing=false ) ]
198+ async fn additional_module_runtime_requirements (
199+ & self ,
200+ compilation : & Compilation ,
201+ module_identifier : & ModuleIdentifier ,
202+ runtime_requirements : & mut RuntimeGlobals ,
203+ ) -> Result < ( ) > {
204+ let Some ( module) = compilation. module_by_identifier ( module_identifier) else {
205+ return Ok ( ( ) ) ;
206+ } ;
207+
208+ if module_needs_ensure_server_actions_runtime ( module. as_ref ( ) , compilation) {
209+ runtime_requirements
210+ . insert ( RuntimeGlobals :: REQUIRE | RuntimeGlobals :: RSC_ENSURE_SERVER_ACTIONS ) ;
211+ }
212+
213+ Ok ( ( ) )
214+ }
215+
216+ fn has_server_actions ( module : & dyn Module ) -> bool {
217+ module
218+ . build_info ( )
219+ . rsc
220+ . as_ref ( )
221+ . is_some_and ( |rsc| !rsc. action_ids . is_empty ( ) )
222+ }
223+
224+ fn is_rsc_layer_module ( module : & dyn Module ) -> bool {
225+ module
226+ . get_layer ( )
227+ . is_some_and ( |layer| layer == LAYERS_NAMES . react_server_components )
228+ }
229+
230+ fn module_needs_ensure_server_actions_runtime (
231+ module : & dyn Module ,
232+ compilation : & Compilation ,
233+ ) -> bool {
234+ if !is_rsc_layer_module ( module) {
235+ return false ;
236+ }
237+
238+ if has_server_actions ( module) {
239+ return true ;
240+ }
241+
242+ let Some ( concatenated_module) = module. as_concatenated_module ( ) else {
243+ return false ;
244+ } ;
245+
246+ let module_graph = compilation. get_module_graph ( ) ;
247+ concatenated_module
248+ . get_modules ( )
249+ . iter ( )
250+ . any ( |inner_module| {
251+ module_graph
252+ . module_by_identifier ( & inner_module. id )
253+ . is_some_and ( |module| has_server_actions ( module. as_ref ( ) ) )
254+ } )
255+ }
256+
187257/// Compute server manifest and server_consumer_module_map once per entry. Stored in plugin_state for
188258/// RscManifestRuntimeModule and onManifest to avoid recomputing.
189259#[ plugin_hook( CompilationChunkIds for RscServerPlugin , stage = -10000 ) ]
@@ -224,6 +294,10 @@ impl Plugin for RscServerPlugin {
224294 . compilation_hooks
225295 . runtime_requirement_in_tree
226296 . tap ( runtime_requirements_in_tree:: new ( self ) ) ;
297+ ctx
298+ . compilation_hooks
299+ . additional_module_runtime_requirements
300+ . tap ( additional_module_runtime_requirements:: new ( self ) ) ;
227301
228302 ctx. compilation_hooks . chunk_ids . tap ( chunk_ids:: new ( self ) ) ;
229303
0 commit comments