1
1
import type {
2
+ Chunk ,
2
3
Compiler ,
3
4
Compilation ,
4
- Chunk ,
5
5
WebpackPluginInstance ,
6
6
Module ,
7
7
Dependency ,
@@ -10,6 +10,8 @@ import { normalizeWebpackPath } from '@module-federation/sdk/normalize-webpack-p
10
10
import FederationModulesPlugin from './runtime/FederationModulesPlugin' ;
11
11
import ContainerEntryDependency from './ContainerEntryDependency' ;
12
12
import FederationRuntimeDependency from './runtime/FederationRuntimeDependency' ;
13
+ import RemoteToExternalDependency from './RemoteToExternalDependency' ;
14
+ import FallbackDependency from './FallbackDependency' ;
13
15
14
16
const { AsyncDependenciesBlock, ExternalModule } = require (
15
17
normalizeWebpackPath ( 'webpack' ) ,
@@ -18,16 +20,19 @@ const { AsyncDependenciesBlock, ExternalModule } = require(
18
20
const PLUGIN_NAME = 'HoistContainerReferences' ;
19
21
20
22
/**
21
- * This class is used to hoist container references in the code .
23
+ * This plugin hoists container-related modules into runtime chunks when using runtimeChunk: single configuration .
22
24
*/
23
- export class HoistContainerReferences implements WebpackPluginInstance {
25
+ class HoistContainerReferences implements WebpackPluginInstance {
24
26
apply ( compiler : Compiler ) : void {
25
27
compiler . hooks . thisCompilation . tap (
26
28
PLUGIN_NAME ,
27
29
( compilation : Compilation ) => {
28
30
const logger = compilation . getLogger ( PLUGIN_NAME ) ;
29
31
const hooks = FederationModulesPlugin . getCompilationHooks ( compilation ) ;
30
32
const containerEntryDependencies = new Set < Dependency > ( ) ;
33
+ const federationRuntimeDependencies = new Set < Dependency > ( ) ;
34
+ const remoteDependencies = new Set < Dependency > ( ) ;
35
+
31
36
hooks . addContainerEntryDependency . tap (
32
37
'HoistContainerReferences' ,
33
38
( dep : ContainerEntryDependency ) => {
@@ -37,7 +42,13 @@ export class HoistContainerReferences implements WebpackPluginInstance {
37
42
hooks . addFederationRuntimeDependency . tap (
38
43
'HoistContainerReferences' ,
39
44
( dep : FederationRuntimeDependency ) => {
40
- containerEntryDependencies . add ( dep ) ;
45
+ federationRuntimeDependencies . add ( dep ) ;
46
+ } ,
47
+ ) ;
48
+ hooks . addRemoteDependency . tap (
49
+ 'HoistContainerReferences' ,
50
+ ( dep : RemoteToExternalDependency | FallbackDependency ) => {
51
+ remoteDependencies . add ( dep ) ;
41
52
} ,
42
53
) ;
43
54
@@ -53,9 +64,10 @@ export class HoistContainerReferences implements WebpackPluginInstance {
53
64
this . hoistModulesInChunks (
54
65
compilation ,
55
66
runtimeChunks ,
56
- chunks ,
57
67
logger ,
58
68
containerEntryDependencies ,
69
+ federationRuntimeDependencies ,
70
+ remoteDependencies ,
59
71
) ;
60
72
} ,
61
73
) ;
@@ -67,37 +79,60 @@ export class HoistContainerReferences implements WebpackPluginInstance {
67
79
private hoistModulesInChunks (
68
80
compilation : Compilation ,
69
81
runtimeChunks : Set < Chunk > ,
70
- chunks : Iterable < Chunk > ,
71
82
logger : ReturnType < Compilation [ 'getLogger' ] > ,
72
83
containerEntryDependencies : Set < Dependency > ,
84
+ federationRuntimeDependencies : Set < Dependency > ,
85
+ remoteDependencies : Set < Dependency > ,
73
86
) : void {
74
87
const { chunkGraph, moduleGraph } = compilation ;
75
- // when runtimeChunk: single is set - ContainerPlugin will create a "partial" chunk we can use to
76
- // move modules into the runtime chunk
88
+ const allModulesToHoist = new Set < Module > ( ) ;
89
+
90
+ // Process container entry dependencies (needed for nextjs-mf exposed modules)
77
91
for ( const dep of containerEntryDependencies ) {
78
92
const containerEntryModule = moduleGraph . getModule ( dep ) ;
79
93
if ( ! containerEntryModule ) continue ;
80
- const allReferencedModules = getAllReferencedModules (
94
+ const referencedModules = getAllReferencedModules (
81
95
compilation ,
82
96
containerEntryModule ,
83
97
'initial' ,
84
98
) ;
99
+ referencedModules . forEach ( ( m : Module ) => allModulesToHoist . add ( m ) ) ;
100
+ const moduleRuntimes = chunkGraph . getModuleRuntimes ( containerEntryModule ) ;
101
+ const runtimes = new Set < string > ( ) ;
102
+ for ( const runtimeSpec of moduleRuntimes ) {
103
+ compilation . compiler . webpack . util . runtime . forEachRuntime (
104
+ runtimeSpec ,
105
+ ( runtimeKey ) => {
106
+ if ( runtimeKey ) {
107
+ runtimes . add ( runtimeKey ) ;
108
+ }
109
+ } ,
110
+ ) ;
111
+ }
112
+ for ( const runtime of runtimes ) {
113
+ const runtimeChunk = compilation . namedChunks . get ( runtime ) ;
114
+ if ( ! runtimeChunk ) continue ;
115
+ for ( const module of referencedModules ) {
116
+ if ( ! chunkGraph . isModuleInChunk ( module , runtimeChunk ) ) {
117
+ chunkGraph . connectChunkAndModule ( runtimeChunk , module ) ;
118
+ }
119
+ }
120
+ }
121
+ }
85
122
86
- const allRemoteReferences = getAllReferencedModules (
123
+ // Federation Runtime Dependencies: use 'initial' (not 'all')
124
+ for ( const dep of federationRuntimeDependencies ) {
125
+ const runtimeModule = moduleGraph . getModule ( dep ) ;
126
+ if ( ! runtimeModule ) continue ;
127
+ const referencedModules = getAllReferencedModules (
87
128
compilation ,
88
- containerEntryModule ,
89
- 'external ' ,
129
+ runtimeModule ,
130
+ 'initial ' ,
90
131
) ;
91
-
92
- for ( const remote of allRemoteReferences ) {
93
- allReferencedModules . add ( remote ) ;
94
- }
95
-
96
- const containerRuntimes =
97
- chunkGraph . getModuleRuntimes ( containerEntryModule ) ;
132
+ referencedModules . forEach ( ( m : Module ) => allModulesToHoist . add ( m ) ) ;
133
+ const moduleRuntimes = chunkGraph . getModuleRuntimes ( runtimeModule ) ;
98
134
const runtimes = new Set < string > ( ) ;
99
-
100
- for ( const runtimeSpec of containerRuntimes ) {
135
+ for ( const runtimeSpec of moduleRuntimes ) {
101
136
compilation . compiler . webpack . util . runtime . forEachRuntime (
102
137
runtimeSpec ,
103
138
( runtimeKey ) => {
@@ -107,19 +142,49 @@ export class HoistContainerReferences implements WebpackPluginInstance {
107
142
} ,
108
143
) ;
109
144
}
110
-
111
145
for ( const runtime of runtimes ) {
112
146
const runtimeChunk = compilation . namedChunks . get ( runtime ) ;
113
147
if ( ! runtimeChunk ) continue ;
148
+ for ( const module of referencedModules ) {
149
+ if ( ! chunkGraph . isModuleInChunk ( module , runtimeChunk ) ) {
150
+ chunkGraph . connectChunkAndModule ( runtimeChunk , module ) ;
151
+ }
152
+ }
153
+ }
154
+ }
114
155
115
- for ( const module of allReferencedModules ) {
156
+ // Process remote dependencies
157
+ for ( const remoteDep of remoteDependencies ) {
158
+ const remoteModule = moduleGraph . getModule ( remoteDep ) ;
159
+ if ( ! remoteModule ) continue ;
160
+ const referencedRemoteModules = getAllReferencedModules (
161
+ compilation ,
162
+ remoteModule ,
163
+ 'initial' ,
164
+ ) ;
165
+ referencedRemoteModules . forEach ( ( m : Module ) => allModulesToHoist . add ( m ) ) ;
166
+ const remoteModuleRuntimes = chunkGraph . getModuleRuntimes ( remoteModule ) ;
167
+ const remoteRuntimes = new Set < string > ( ) ;
168
+ for ( const runtimeSpec of remoteModuleRuntimes ) {
169
+ compilation . compiler . webpack . util . runtime . forEachRuntime (
170
+ runtimeSpec ,
171
+ ( runtimeKey ) => {
172
+ if ( runtimeKey ) remoteRuntimes . add ( runtimeKey ) ;
173
+ } ,
174
+ ) ;
175
+ }
176
+ for ( const runtime of remoteRuntimes ) {
177
+ const runtimeChunk = compilation . namedChunks . get ( runtime ) ;
178
+ if ( ! runtimeChunk ) continue ;
179
+ for ( const module of referencedRemoteModules ) {
116
180
if ( ! chunkGraph . isModuleInChunk ( module , runtimeChunk ) ) {
117
181
chunkGraph . connectChunkAndModule ( runtimeChunk , module ) ;
118
182
}
119
183
}
120
184
}
121
- this . cleanUpChunks ( compilation , allReferencedModules ) ;
122
185
}
186
+
187
+ this . cleanUpChunks ( compilation , allModulesToHoist ) ;
123
188
}
124
189
125
190
// Method to clean up chunks by disconnecting unused modules
@@ -129,31 +194,17 @@ export class HoistContainerReferences implements WebpackPluginInstance {
129
194
for ( const chunk of chunkGraph . getModuleChunks ( module ) ) {
130
195
if ( ! chunk . hasRuntime ( ) ) {
131
196
chunkGraph . disconnectChunkAndModule ( chunk , module ) ;
132
- if (
133
- chunkGraph . getNumberOfChunkModules ( chunk ) === 0 &&
134
- chunkGraph . getNumberOfEntryModules ( chunk ) === 0
135
- ) {
136
- chunkGraph . disconnectChunk ( chunk ) ;
137
- compilation . chunks . delete ( chunk ) ;
138
- if ( chunk . name ) {
139
- compilation . namedChunks . delete ( chunk . name ) ;
140
- }
141
- }
142
197
}
143
198
}
144
199
}
145
- modules . clear ( ) ;
146
200
}
147
201
148
- // Helper method to get runtime chunks from the compilation
202
+ // Method to get runtime chunks
149
203
private getRuntimeChunks ( compilation : Compilation ) : Set < Chunk > {
150
204
const runtimeChunks = new Set < Chunk > ( ) ;
151
- const entries = compilation . entrypoints ;
152
-
153
- for ( const entrypoint of entries . values ( ) ) {
154
- const runtimeChunk = entrypoint . getRuntimeChunk ( ) ;
155
- if ( runtimeChunk ) {
156
- runtimeChunks . add ( runtimeChunk ) ;
205
+ for ( const chunk of compilation . chunks ) {
206
+ if ( chunk . hasRuntime ( ) ) {
207
+ runtimeChunks . add ( chunk ) ;
157
208
}
158
209
}
159
210
return runtimeChunks ;
0 commit comments