@module-federation/node 0.0.0-feat-node-support-1702930274547 → 0.0.0-next-20231219093413
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +10 -0
- package/.eslintrc.json +47 -0
- package/CHANGELOG.md +1352 -0
- package/LICENSE +21 -0
- package/README.md +192 -0
- package/assets/banner.png +0 -0
- package/dist/jest.config.js +19 -0
- package/dist/jest.config.js.map +1 -0
- package/dist/package.json +62 -0
- package/dist/src/filesystem/stratagies.d.ts +11 -0
- package/{src → dist/src}/filesystem/stratagies.js +11 -31
- package/dist/src/filesystem/stratagies.js.map +1 -0
- package/{src → dist/src}/index.d.ts +2 -0
- package/{src → dist/src}/index.js +5 -1
- package/dist/src/index.js.map +1 -0
- package/dist/src/plugins/AutomaticPublicPathPlugin.js.map +1 -0
- package/dist/src/plugins/ChunkCorrelationPlugin.js +442 -0
- package/dist/src/plugins/ChunkCorrelationPlugin.js.map +1 -0
- package/dist/src/plugins/CommonJsChunkLoadingPlugin.js.map +1 -0
- package/{src → dist/src}/plugins/DynamicFilesystemChunkLoadingRuntimeModule.js +13 -0
- package/dist/src/plugins/DynamicFilesystemChunkLoadingRuntimeModule.js.map +1 -0
- package/dist/src/plugins/NodeContainerPlugin.d.ts +57 -0
- package/dist/src/plugins/NodeContainerPlugin.js +105 -0
- package/dist/src/plugins/NodeContainerPlugin.js.map +1 -0
- package/{src → dist/src}/plugins/NodeFederationPlugin.d.ts +20 -0
- package/dist/src/plugins/NodeFederationPlugin.js +127 -0
- package/dist/src/plugins/NodeFederationPlugin.js.map +1 -0
- package/dist/src/plugins/RemotePublicPathRuntimeModule.js.map +1 -0
- package/{src → dist/src}/plugins/StreamingTargetPlugin.js.map +1 -1
- package/{src → dist/src}/plugins/UniversalFederationPlugin.d.ts +0 -1
- package/{src → dist/src}/plugins/UniversalFederationPlugin.js +3 -3
- package/dist/src/plugins/UniversalFederationPlugin.js.map +1 -0
- package/{src → dist/src}/plugins/webpackChunkUtilities.js +5 -1
- package/dist/src/plugins/webpackChunkUtilities.js.map +1 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/flush-chunks.js.map +1 -0
- package/dist/src/utils/hot-reload.js.map +1 -0
- package/dist/src/utils/index.js.map +1 -0
- package/global.d.ts +27 -0
- package/jest.config.js +14 -16
- package/package.json +17 -23
- package/project.json +58 -0
- package/src/filesystem/stratagies.ts +131 -0
- package/src/index.ts +7 -0
- package/src/plugins/AutomaticPublicPathPlugin.ts +48 -0
- package/src/plugins/ChunkCorrelationPlugin.js +474 -307
- package/src/plugins/CommonJsChunkLoadingPlugin.ts +168 -0
- package/src/plugins/DynamicFilesystemChunkLoadingRuntimeModule.ts +239 -0
- package/src/plugins/NodeContainerPlugin.ts +150 -0
- package/src/plugins/NodeFederationPlugin.ts +185 -0
- package/src/plugins/RemotePublicPathRuntimeModule.ts +137 -0
- package/src/plugins/StreamingTargetPlugin.md +88 -0
- package/src/plugins/StreamingTargetPlugin.ts +81 -0
- package/src/plugins/UniversalFederationPlugin.ts +81 -0
- package/src/plugins/webpackChunkUtilities.ts +383 -0
- package/src/types/index.ts +7 -0
- package/src/utils/flush-chunks.ts +182 -0
- package/src/utils/hot-reload.ts +169 -0
- package/src/utils/index.ts +2 -0
- package/tsconfig.json +28 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.spec.json +9 -0
- package/jest.config.js.map +0 -1
- package/src/filesystem/stratagies.d.ts +0 -18
- package/src/filesystem/stratagies.js.map +0 -1
- package/src/index.js.map +0 -1
- package/src/plugins/AutomaticPublicPathPlugin.js.map +0 -1
- package/src/plugins/ChunkCorrelationPlugin.js.map +0 -1
- package/src/plugins/CommonJsChunkLoadingPlugin.js.map +0 -1
- package/src/plugins/DynamicFilesystemChunkLoadingRuntimeModule.js.map +0 -1
- package/src/plugins/NodeFederationPlugin.js +0 -76
- package/src/plugins/NodeFederationPlugin.js.map +0 -1
- package/src/plugins/RemotePublicPathRuntimeModule.js.map +0 -1
- package/src/plugins/UniversalFederationPlugin.js.map +0 -1
- package/src/plugins/webpackChunkUtilities.js.map +0 -1
- package/src/types/index.js.map +0 -1
- package/src/utils/flush-chunks.js.map +0 -1
- package/src/utils/hot-reload.js.map +0 -1
- package/src/utils/index.js.map +0 -1
- package/{jest.config.d.ts → dist/jest.config.d.ts} +0 -0
- package/{src → dist/src}/plugins/AutomaticPublicPathPlugin.d.ts +0 -0
- package/{src → dist/src}/plugins/AutomaticPublicPathPlugin.js +0 -0
- package/{src → dist/src}/plugins/ChunkCorrelationPlugin.d.ts +6 -6
- /package/{src → dist/src}/plugins/CommonJsChunkLoadingPlugin.d.ts +0 -0
- /package/{src → dist/src}/plugins/CommonJsChunkLoadingPlugin.js +0 -0
- /package/{src → dist/src}/plugins/DynamicFilesystemChunkLoadingRuntimeModule.d.ts +0 -0
- /package/{src → dist/src}/plugins/RemotePublicPathRuntimeModule.d.ts +0 -0
- /package/{src → dist/src}/plugins/RemotePublicPathRuntimeModule.js +0 -0
- /package/{src → dist/src}/plugins/StreamingTargetPlugin.d.ts +0 -0
- /package/{src → dist/src}/plugins/StreamingTargetPlugin.js +0 -0
- /package/{src → dist/src}/plugins/webpackChunkUtilities.d.ts +0 -0
- /package/{src → dist/src}/types/index.d.ts +0 -0
- /package/{src → dist/src}/types/index.js +0 -0
- /package/{src → dist/src}/utils/flush-chunks.d.ts +0 -0
- /package/{src → dist/src}/utils/flush-chunks.js +0 -0
- /package/{src → dist/src}/utils/hot-reload.d.ts +0 -0
- /package/{src → dist/src}/utils/hot-reload.js +0 -0
- /package/{src → dist/src}/utils/index.d.ts +0 -0
- /package/{src → dist/src}/utils/index.js +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
const PLUGIN_NAME = 'FederationStatsPlugin';
|
|
2
|
+
|
|
3
3
|
/** @typedef {import("./webpack-stats-types").WebpackStats} WebpackStats */
|
|
4
4
|
/** @typedef {import( "./webpack-stats-types").WebpackStatsChunk} WebpackStatsChunk */
|
|
5
5
|
/** @typedef {import("./webpack-stats-types").WebpackStatsModule} WebpackStatsModule */
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* @typedef {object} SharedDependency
|
|
8
9
|
* @property {string} shareScope
|
|
@@ -12,16 +13,19 @@ const PLUGIN_NAME = 'FederationStatsPlugin';
|
|
|
12
13
|
* @property {boolean} singleton
|
|
13
14
|
* @property {boolean} eager
|
|
14
15
|
*/
|
|
16
|
+
|
|
15
17
|
/**
|
|
16
18
|
* @typedef {object} SharedModule
|
|
17
19
|
* @property {string[]} chunks
|
|
18
20
|
* @property {SharedDependency[]} provides
|
|
19
21
|
*/
|
|
22
|
+
|
|
20
23
|
/**
|
|
21
24
|
* @typedef {object} Exposed
|
|
22
25
|
* @property {string[]} chunks
|
|
23
26
|
* @property {SharedModule[]} sharedModules
|
|
24
27
|
*/
|
|
28
|
+
|
|
25
29
|
/**
|
|
26
30
|
* @typedef {object} FederatedContainer
|
|
27
31
|
* @property {string} remote
|
|
@@ -29,26 +33,31 @@ const PLUGIN_NAME = 'FederationStatsPlugin';
|
|
|
29
33
|
* @property {SharedModule[]} sharedModules
|
|
30
34
|
* @property {{ [key: string]: Exposed }} exposes
|
|
31
35
|
*/
|
|
36
|
+
|
|
32
37
|
/**
|
|
33
38
|
* @typedef {object} FederatedStats
|
|
34
39
|
* @property {SharedModule[]} sharedModules
|
|
35
40
|
* @property {FederatedContainer[]} federatedModules
|
|
36
41
|
*/
|
|
42
|
+
|
|
37
43
|
const concat = (x, y) => x.concat(y);
|
|
44
|
+
|
|
38
45
|
const flatMap = (xs, f) => xs.map(f).reduce(concat, []);
|
|
46
|
+
|
|
39
47
|
/**
|
|
40
48
|
*
|
|
41
49
|
* @param {WebpackStats} stats
|
|
42
50
|
* @returns {}
|
|
43
51
|
*/
|
|
44
52
|
function getRemoteModules(stats) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
return stats.modules
|
|
54
|
+
.filter((mod) => mod.moduleType === 'remote-module')
|
|
55
|
+
.reduce((acc, remoteModule) => {
|
|
56
|
+
acc[remoteModule.nameForCondition] = remoteModule.id;
|
|
57
|
+
return acc;
|
|
50
58
|
}, {});
|
|
51
59
|
}
|
|
60
|
+
|
|
52
61
|
/**
|
|
53
62
|
*
|
|
54
63
|
* @param {WebpackStats} stats
|
|
@@ -56,16 +65,17 @@ function getRemoteModules(stats) {
|
|
|
56
65
|
* @returns {WebpackStatsModule[]}
|
|
57
66
|
*/
|
|
58
67
|
function getExposedModules(stats, exposedFile) {
|
|
59
|
-
|
|
68
|
+
return stats.modules.filter((mod) => mod.name?.startsWith(exposedFile));
|
|
60
69
|
}
|
|
61
70
|
//eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
62
71
|
function getDependenciesOfChunk(stats, chunk) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
return stats.chunks
|
|
73
|
+
.filter((c) => c.children.includes(chunk.id))
|
|
74
|
+
.reduce((acc, c) => {
|
|
75
|
+
return acc.concat(c.modules);
|
|
67
76
|
}, []);
|
|
68
77
|
}
|
|
78
|
+
|
|
69
79
|
/**
|
|
70
80
|
*
|
|
71
81
|
* @param {WebpackStats} stats
|
|
@@ -73,32 +83,38 @@ function getDependenciesOfChunk(stats, chunk) {
|
|
|
73
83
|
* @returns {Exposed}
|
|
74
84
|
*/
|
|
75
85
|
function getExposed(stats, mod) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
86
|
+
const chunks = stats.chunks.filter((chunk) => {
|
|
87
|
+
return chunk.modules.find((modsInChunk) => {
|
|
88
|
+
return modsInChunk.id === mod.id && !modsInChunk.dependent;
|
|
80
89
|
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
});
|
|
91
|
+
const dependencies = stats.modules
|
|
92
|
+
.filter((sharedModule) => {
|
|
93
|
+
if (sharedModule.moduleType !== 'consume-shared-module') {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return sharedModule.issuerId === mod.id;
|
|
87
97
|
})
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
.map((sharedModule) => {
|
|
99
|
+
return sharedModule.identifier.split('|')[2];
|
|
90
100
|
});
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
|
|
102
|
+
const flatChunks = flatMap(chunks, (chunk) => ({
|
|
103
|
+
[chunk.id]: {
|
|
104
|
+
files: chunk.files.map(
|
|
105
|
+
(f) =>
|
|
106
|
+
`${stats.publicPath === 'auto' ? '' : stats.publicPath || ''}${f}`,
|
|
107
|
+
),
|
|
108
|
+
requiredModules: dependencies,
|
|
109
|
+
},
|
|
110
|
+
}));
|
|
111
|
+
|
|
112
|
+
return flatChunks.reduce((acc, chunk) => {
|
|
113
|
+
Object.assign(acc, chunk);
|
|
114
|
+
return acc;
|
|
115
|
+
}, {});
|
|
101
116
|
}
|
|
117
|
+
|
|
102
118
|
/**
|
|
103
119
|
*
|
|
104
120
|
* @param {import("webpack").Module} mod
|
|
@@ -106,77 +122,109 @@ function getExposed(stats, mod) {
|
|
|
106
122
|
* @returns {boolean}
|
|
107
123
|
*/
|
|
108
124
|
function searchIssuer(mod, check) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
125
|
+
if (mod.issuer && check(mod.issuer)) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return !!mod.modules && mod.modules.some((m) => searchIssuer(m, check));
|
|
113
130
|
}
|
|
131
|
+
|
|
114
132
|
function searchReason(mod, check) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
133
|
+
if (mod.reasons && check(mod.reasons)) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return !!mod.reasons && mod.reasons.some((m) => searchReason(m, check));
|
|
119
138
|
}
|
|
139
|
+
|
|
120
140
|
function searchIssuerAndReason(mod, check) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
141
|
+
const foundIssuer = searchIssuer(mod, (issuer) => check(issuer));
|
|
142
|
+
if (foundIssuer) {
|
|
143
|
+
return foundIssuer;
|
|
144
|
+
}
|
|
145
|
+
return searchReason(mod, (reason) =>
|
|
146
|
+
reason.some((r) => check(r?.moduleIdentifier)),
|
|
147
|
+
);
|
|
126
148
|
}
|
|
149
|
+
|
|
127
150
|
/**
|
|
128
151
|
* @param {import("webpack").Module} mod
|
|
129
152
|
* @param {(issuer: string) => boolean} check
|
|
130
153
|
* @returns {string[]}
|
|
131
154
|
*/
|
|
132
155
|
function getIssuers(mod, check) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
156
|
+
if (mod.issuer && check(mod.issuer)) {
|
|
157
|
+
return [mod.issuer];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
(mod.modules &&
|
|
162
|
+
mod.modules.filter((m) => searchIssuer(m, check)).map((m) => m.issuer)) ||
|
|
163
|
+
[]
|
|
164
|
+
);
|
|
139
165
|
}
|
|
166
|
+
|
|
140
167
|
function getIssuersAndReasons(mod, check) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
if (mod.issuer && check(mod.issuer)) {
|
|
169
|
+
return [mod.issuer];
|
|
170
|
+
}
|
|
171
|
+
if (
|
|
172
|
+
mod.reasons &&
|
|
173
|
+
searchReason(mod, (reason) =>
|
|
174
|
+
reason.some((r) => check(r?.moduleIdentifier)),
|
|
175
|
+
)
|
|
176
|
+
) {
|
|
177
|
+
return mod.reasons
|
|
178
|
+
.filter((r) => {
|
|
179
|
+
return r.moduleIdentifier && check(r.moduleIdentifier);
|
|
180
|
+
})
|
|
181
|
+
.map((r) => r.moduleIdentifier);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
(mod.modules &&
|
|
186
|
+
mod.modules
|
|
187
|
+
.filter((m) => searchIssuerAndReason(m, check))
|
|
188
|
+
.map((m) => {
|
|
189
|
+
return (
|
|
190
|
+
m.issuer ||
|
|
191
|
+
m.reasons.find((r) => check(r?.moduleIdentifier)).moduleIdentifier
|
|
192
|
+
);
|
|
158
193
|
})) ||
|
|
159
|
-
|
|
194
|
+
[]
|
|
195
|
+
);
|
|
160
196
|
}
|
|
197
|
+
|
|
161
198
|
/**
|
|
162
199
|
* @param {string} issuer
|
|
163
200
|
* @returns {SharedDependency}
|
|
164
201
|
*/
|
|
165
202
|
function parseFederatedIssuer(issuer) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
203
|
+
const split = issuer?.split('|') || [];
|
|
204
|
+
if (split.length !== 8 || split[0] !== 'consume-shared-module') {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
const [
|
|
208
|
+
,
|
|
209
|
+
shareScope,
|
|
210
|
+
shareKey,
|
|
211
|
+
requiredVersion,
|
|
212
|
+
strictVersion,
|
|
213
|
+
,
|
|
214
|
+
singleton,
|
|
215
|
+
eager,
|
|
216
|
+
] = split;
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
shareScope,
|
|
220
|
+
shareKey,
|
|
221
|
+
requiredVersion,
|
|
222
|
+
strictVersion: JSON.parse(strictVersion),
|
|
223
|
+
singleton: JSON.parse(singleton),
|
|
224
|
+
eager: JSON.parse(eager),
|
|
225
|
+
};
|
|
179
226
|
}
|
|
227
|
+
|
|
180
228
|
/**
|
|
181
229
|
*
|
|
182
230
|
* @param {WebpackStats} stats
|
|
@@ -184,48 +232,106 @@ function parseFederatedIssuer(issuer) {
|
|
|
184
232
|
* @returns {SharedModule[]}
|
|
185
233
|
*/
|
|
186
234
|
function getSharedModules(stats, federationPlugin) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
.
|
|
235
|
+
return flatMap(
|
|
236
|
+
stats.chunks.filter((chunk) => {
|
|
237
|
+
if (!stats.entrypoints[federationPlugin.name]) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
return stats.entrypoints[federationPlugin.name].chunks.some(
|
|
241
|
+
(id) => chunk.id === id,
|
|
242
|
+
);
|
|
243
|
+
}),
|
|
244
|
+
(chunk) =>
|
|
245
|
+
flatMap(chunk.children, (id) =>
|
|
246
|
+
stats.chunks.filter(
|
|
247
|
+
(c) =>
|
|
248
|
+
c.id === id &&
|
|
249
|
+
c.files.length > 0 &&
|
|
250
|
+
c.parents.some((p) =>
|
|
251
|
+
stats.entrypoints[federationPlugin.name].chunks.some(
|
|
252
|
+
(c) => c === p,
|
|
253
|
+
),
|
|
254
|
+
) &&
|
|
255
|
+
c.modules.some((m) =>
|
|
256
|
+
searchIssuer(m, (issuer) =>
|
|
257
|
+
issuer?.startsWith('consume-shared-module'),
|
|
258
|
+
),
|
|
259
|
+
),
|
|
260
|
+
),
|
|
261
|
+
),
|
|
262
|
+
)
|
|
263
|
+
.map((chunk) => ({
|
|
264
|
+
chunks: chunk.files.map(
|
|
265
|
+
(f) =>
|
|
266
|
+
`${stats.publicPath === 'auto' ? '' : stats.publicPath || ''}${f}`,
|
|
267
|
+
),
|
|
268
|
+
provides: flatMap(
|
|
269
|
+
chunk.modules.filter((m) =>
|
|
270
|
+
searchIssuer(m, (issuer) =>
|
|
271
|
+
issuer?.startsWith('consume-shared-module'),
|
|
272
|
+
),
|
|
273
|
+
),
|
|
274
|
+
(m) =>
|
|
275
|
+
getIssuers(m, (issuer) =>
|
|
276
|
+
issuer?.startsWith('consume-shared-module'),
|
|
277
|
+
),
|
|
278
|
+
)
|
|
279
|
+
.map(parseFederatedIssuer)
|
|
280
|
+
.filter((f) => !!f),
|
|
201
281
|
}))
|
|
202
|
-
|
|
282
|
+
.filter((c) => c.provides.length > 0);
|
|
203
283
|
}
|
|
284
|
+
|
|
204
285
|
/**
|
|
205
286
|
* @param {WebpackStats} stats
|
|
206
287
|
* @returns {SharedModule[]}
|
|
207
288
|
*/
|
|
208
289
|
function getMainSharedModules(stats) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
290
|
+
const chunks = stats.namedChunkGroups['main']
|
|
291
|
+
? flatMap(stats.namedChunkGroups['main'].chunks, (c) =>
|
|
292
|
+
stats.chunks.filter((chunk) => chunk.id === c),
|
|
293
|
+
)
|
|
294
|
+
: [];
|
|
295
|
+
|
|
296
|
+
return flatMap(chunks, (chunk) =>
|
|
297
|
+
flatMap(chunk.children, (id) =>
|
|
298
|
+
stats.chunks.filter((c) => {
|
|
299
|
+
return (
|
|
300
|
+
c.id === id &&
|
|
301
|
+
c.files.length > 0 &&
|
|
302
|
+
c.modules.some((m) => {
|
|
303
|
+
return searchIssuerAndReason(m, (check) =>
|
|
304
|
+
check?.startsWith('consume-shared-module'),
|
|
305
|
+
);
|
|
306
|
+
})
|
|
307
|
+
);
|
|
308
|
+
}),
|
|
309
|
+
),
|
|
310
|
+
)
|
|
311
|
+
.map((chunk) => {
|
|
312
|
+
return {
|
|
313
|
+
chunks: chunk.files.map(
|
|
314
|
+
(f) =>
|
|
315
|
+
`${stats.publicPath === 'auto' ? '' : stats.publicPath || ''}${f}`,
|
|
316
|
+
),
|
|
317
|
+
provides: flatMap(
|
|
318
|
+
chunk.modules.filter((m) =>
|
|
319
|
+
searchIssuerAndReason(m, (check) =>
|
|
320
|
+
check?.startsWith('consume-shared-module'),
|
|
321
|
+
),
|
|
322
|
+
),
|
|
323
|
+
(m) =>
|
|
324
|
+
getIssuersAndReasons(m, (issuer) =>
|
|
325
|
+
issuer?.startsWith('consume-shared-module'),
|
|
326
|
+
),
|
|
327
|
+
)
|
|
328
|
+
.map(parseFederatedIssuer)
|
|
329
|
+
.filter((f) => !!f),
|
|
330
|
+
};
|
|
226
331
|
})
|
|
227
|
-
|
|
332
|
+
.filter((c) => c.provides.length > 0);
|
|
228
333
|
}
|
|
334
|
+
|
|
229
335
|
/**
|
|
230
336
|
*
|
|
231
337
|
* @param {WebpackStats} stats
|
|
@@ -233,210 +339,271 @@ function getMainSharedModules(stats) {
|
|
|
233
339
|
* @returns {FederatedStats}
|
|
234
340
|
*/
|
|
235
341
|
function getFederationStats(stats, federationPluginOptions) {
|
|
236
|
-
|
|
342
|
+
const exposedModules = Object.entries(federationPluginOptions.exposes).reduce(
|
|
343
|
+
(exposedModules, [exposedAs, exposedFile]) =>
|
|
344
|
+
Object.assign(exposedModules, {
|
|
237
345
|
[exposedAs]: getExposedModules(stats, exposedFile),
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
346
|
+
}),
|
|
347
|
+
{},
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
/** @type {{ [key: string]: Exposed }} */
|
|
351
|
+
const exposes = Object.entries(exposedModules).reduce(
|
|
352
|
+
(exposedChunks, [exposedAs, exposedModules]) =>
|
|
353
|
+
Object.assign(exposedChunks, {
|
|
241
354
|
[exposedAs]: flatMap(exposedModules, (mod) => getExposed(stats, mod)),
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
355
|
+
}),
|
|
356
|
+
{},
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
/** @type {string} */
|
|
360
|
+
const remote =
|
|
361
|
+
federationPluginOptions.library?.name || federationPluginOptions.name;
|
|
362
|
+
|
|
363
|
+
const sharedModules = getSharedModules(stats, federationPluginOptions);
|
|
364
|
+
const remoteModules = getRemoteModules(stats);
|
|
365
|
+
return {
|
|
366
|
+
remote,
|
|
367
|
+
entry: `${stats.publicPath === 'auto' ? '' : stats.publicPath || ''}${
|
|
368
|
+
stats.assetsByChunkName[remote] &&
|
|
369
|
+
stats.assetsByChunkName[remote].length === 1
|
|
370
|
+
? stats.assetsByChunkName[remote][0]
|
|
371
|
+
: federationPluginOptions.filename
|
|
372
|
+
}`,
|
|
373
|
+
sharedModules,
|
|
374
|
+
exposes,
|
|
375
|
+
remoteModules,
|
|
376
|
+
};
|
|
257
377
|
}
|
|
378
|
+
|
|
258
379
|
/**
|
|
259
380
|
* @typedef {object} FederationStatsPluginOptions
|
|
260
381
|
* @property {string | string[]} filename The filename or an array of filenames in the `output.path` directory to write stats to.
|
|
261
382
|
*/
|
|
383
|
+
|
|
262
384
|
/**
|
|
263
385
|
* Writes relevant federation stats to a file for further consumption.
|
|
264
386
|
*/
|
|
265
387
|
class FederationStatsPlugin {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
this._options = options;
|
|
388
|
+
/**
|
|
389
|
+
*
|
|
390
|
+
* @param {FederationStatsPluginOptions} options
|
|
391
|
+
*/
|
|
392
|
+
constructor(options) {
|
|
393
|
+
if (!options || !options.filename) {
|
|
394
|
+
throw new Error('filename option is required.');
|
|
275
395
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
396
|
+
|
|
397
|
+
this._options = options;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
*
|
|
402
|
+
* @param {import("webpack").Compiler} compiler
|
|
403
|
+
*/
|
|
404
|
+
apply(compiler) {
|
|
405
|
+
const federationPlugins = compiler.options.plugins?.filter(
|
|
406
|
+
(plugin) =>
|
|
407
|
+
[
|
|
408
|
+
'NextFederationPlugin',
|
|
409
|
+
'UniversalFederationPlugin',
|
|
410
|
+
'NodeFederationPlugin',
|
|
411
|
+
'ModuleFederationPlugin',
|
|
412
|
+
].includes(plugin.constructor.name) && plugin?._options?.exposes,
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
if (!federationPlugins || federationPlugins.length === 0) {
|
|
416
|
+
console.error('No ModuleFederationPlugin(s) found.');
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// This is where the plugin is tapping into the Webpack compilation lifecycle.
|
|
421
|
+
// It's listening to the 'thisCompilation' event, which is triggered once for each new compilation.
|
|
422
|
+
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
|
|
423
|
+
// 'processAssets' is a hook that gets triggered when Webpack has finished the compilation
|
|
424
|
+
// and is about to generate the final assets. It allows plugins to do additional processing on the assets.
|
|
425
|
+
compilation.hooks.processAssets.tap(
|
|
426
|
+
{
|
|
427
|
+
name: PLUGIN_NAME,
|
|
428
|
+
stage: compilation.constructor.PROCESS_ASSETS_STAGE_REPORT,
|
|
429
|
+
},
|
|
430
|
+
() => {
|
|
431
|
+
// Extract the options from the federation plugins.
|
|
432
|
+
const [federationOpts] = federationPlugins.map(
|
|
433
|
+
(federationPlugin) => federationPlugin?._options,
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
let container;
|
|
437
|
+
// Loop through all entry points and if one matches the name of a federation plugin,
|
|
438
|
+
// store the entry point in the 'container' variable.
|
|
439
|
+
for (const [name, entry] of compilation.entrypoints) {
|
|
440
|
+
if (container) {
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
federationOpts.name.includes(name) && (container = entry);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// If no matching entry point was found, exit the function early.
|
|
447
|
+
if (!container) {
|
|
289
448
|
return;
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const rootModules = compilation.chunkGraph.getChunkRootModules(exposedChunk);
|
|
344
|
-
// Check if the module associated with the dependency is one of the root modules for the chunk.
|
|
345
|
-
const moduleActuallyNeedsChunk = rootModules.includes(module);
|
|
346
|
-
// If the chunk is not meant for this runtime or the module doesn't need the chunk, skip the rest of this iteration.
|
|
347
|
-
if (!isForThisRuntime || !moduleActuallyNeedsChunk) {
|
|
348
|
-
continue;
|
|
349
|
-
}
|
|
350
|
-
// Add the files associated with the chunk to the 'builtExposes' object under the name of the exposed module.
|
|
351
|
-
builtExposes[dep.exposedName] = [
|
|
352
|
-
...(builtExposes[dep.exposedName] || []),
|
|
353
|
-
...(exposedChunk.files || []),
|
|
354
|
-
];
|
|
355
|
-
}
|
|
356
|
-
// Add the module to the 'exposedResolved' object under the name of the exposed module.
|
|
357
|
-
exposedResolved[dep.exposedName] = module;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
// Generate a JSON object that contains detailed information about the compilation.
|
|
361
|
-
const stats = compilation.getStats().toJson({
|
|
362
|
-
all: false,
|
|
363
|
-
assets: true,
|
|
364
|
-
reasons: true,
|
|
365
|
-
modules: true,
|
|
366
|
-
children: true,
|
|
367
|
-
chunkGroups: true,
|
|
368
|
-
chunkModules: true,
|
|
369
|
-
chunkOrigins: false,
|
|
370
|
-
entrypoints: true,
|
|
371
|
-
namedChunkGroups: false,
|
|
372
|
-
chunkRelations: true,
|
|
373
|
-
chunks: true,
|
|
374
|
-
ids: true,
|
|
375
|
-
nestedModules: false,
|
|
376
|
-
outputPath: true,
|
|
377
|
-
publicPath: true,
|
|
378
|
-
});
|
|
379
|
-
// Apply a function 'getFederationStats' on the stats with the federation plugin options as the second argument.
|
|
380
|
-
const federatedModules = getFederationStats(stats, federationOpts);
|
|
381
|
-
// Assign the 'builtExposes' object to the 'exposes' property of the 'federatedModules' object.
|
|
382
|
-
federatedModules.exposes = builtExposes;
|
|
383
|
-
// Apply a function 'getMainSharedModules' on the stats.
|
|
384
|
-
const sharedModules = getMainSharedModules(stats);
|
|
385
|
-
// Create a Set to hold the vendor chunks.
|
|
386
|
-
const vendorChunks = new Set();
|
|
387
|
-
// Iterate over the shared modules.
|
|
388
|
-
for (const share of sharedModules) {
|
|
389
|
-
if (share?.chunks) {
|
|
390
|
-
// If a shared module has chunks, add them to the 'vendorChunks' Set.
|
|
391
|
-
for (const file of share.chunks) {
|
|
392
|
-
vendorChunks.add(file);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Get the chunk associated with the entry point.
|
|
452
|
+
container = container?.getEntrypointChunk();
|
|
453
|
+
|
|
454
|
+
// Get the module associated with the chunk.
|
|
455
|
+
const [containerEntryModule] = Array.from(
|
|
456
|
+
compilation.chunkGraph.getChunkEntryModulesIterable(container),
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
const { blocks } = containerEntryModule;
|
|
460
|
+
|
|
461
|
+
const exposedResolved = {};
|
|
462
|
+
const builtExposes = {};
|
|
463
|
+
|
|
464
|
+
// Iterate over each dependency block associated with the entry module.
|
|
465
|
+
for (let block of blocks) {
|
|
466
|
+
const blockmodule = block;
|
|
467
|
+
|
|
468
|
+
// Iterate over each dependency within the block.
|
|
469
|
+
for (const dep of blockmodule.dependencies) {
|
|
470
|
+
// Get the module that corresponds to the dependency.
|
|
471
|
+
const connection = compilation.moduleGraph.getConnection(dep);
|
|
472
|
+
if (!connection) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
const { module } = connection;
|
|
476
|
+
|
|
477
|
+
const moduleChunks =
|
|
478
|
+
compilation.chunkGraph.getModuleChunksIterable(module);
|
|
479
|
+
// Iterate over each chunk associated with the module.
|
|
480
|
+
for (let exposedChunk of moduleChunks) {
|
|
481
|
+
// Determine the runtime for the chunk.
|
|
482
|
+
const runtime =
|
|
483
|
+
typeof exposedChunk.runtime === 'string'
|
|
484
|
+
? new Set([exposedChunk.runtime])
|
|
485
|
+
: exposedChunk.runtime;
|
|
486
|
+
|
|
487
|
+
// Check if the chunk is meant for the same runtime as the entry module.
|
|
488
|
+
const isForThisRuntime = runtime.has(
|
|
489
|
+
containerEntryModule._name,
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
// Get the root modules for the chunk.
|
|
493
|
+
const rootModules =
|
|
494
|
+
compilation.chunkGraph.getChunkRootModules(exposedChunk);
|
|
495
|
+
|
|
496
|
+
// Check if the module associated with the dependency is one of the root modules for the chunk.
|
|
497
|
+
const moduleActuallyNeedsChunk = rootModules.includes(module);
|
|
498
|
+
|
|
499
|
+
// If the chunk is not meant for this runtime or the module doesn't need the chunk, skip the rest of this iteration.
|
|
500
|
+
if (!isForThisRuntime || !moduleActuallyNeedsChunk) {
|
|
501
|
+
continue;
|
|
395
502
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
503
|
+
|
|
504
|
+
// Add the files associated with the chunk to the 'builtExposes' object under the name of the exposed module.
|
|
505
|
+
builtExposes[dep.exposedName] = [
|
|
506
|
+
...(builtExposes[dep.exposedName] || []),
|
|
507
|
+
...(exposedChunk.files || []),
|
|
508
|
+
];
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Add the module to the 'exposedResolved' object under the name of the exposed module.
|
|
512
|
+
exposedResolved[dep.exposedName] = module;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Generate a JSON object that contains detailed information about the compilation.
|
|
517
|
+
const stats = compilation.getStats().toJson({
|
|
518
|
+
all: false,
|
|
519
|
+
assets: true,
|
|
520
|
+
reasons: true,
|
|
521
|
+
modules: true,
|
|
522
|
+
children: true,
|
|
523
|
+
chunkGroups: true,
|
|
524
|
+
chunkModules: true,
|
|
525
|
+
chunkOrigins: false,
|
|
526
|
+
entrypoints: true,
|
|
527
|
+
namedChunkGroups: false,
|
|
528
|
+
chunkRelations: true,
|
|
529
|
+
chunks: true,
|
|
530
|
+
ids: true,
|
|
531
|
+
nestedModules: false,
|
|
532
|
+
outputPath: true,
|
|
533
|
+
publicPath: true,
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
// Apply a function 'getFederationStats' on the stats with the federation plugin options as the second argument.
|
|
537
|
+
const federatedModules = getFederationStats(stats, federationOpts);
|
|
538
|
+
|
|
539
|
+
// Assign the 'builtExposes' object to the 'exposes' property of the 'federatedModules' object.
|
|
540
|
+
federatedModules.exposes = builtExposes;
|
|
541
|
+
|
|
542
|
+
// Apply a function 'getMainSharedModules' on the stats.
|
|
543
|
+
const sharedModules = getMainSharedModules(stats);
|
|
544
|
+
|
|
545
|
+
// Create a Set to hold the vendor chunks.
|
|
546
|
+
const vendorChunks = new Set();
|
|
547
|
+
|
|
548
|
+
// Iterate over the shared modules.
|
|
549
|
+
for (const share of sharedModules) {
|
|
550
|
+
if (share?.chunks) {
|
|
551
|
+
// If a shared module has chunks, add them to the 'vendorChunks' Set.
|
|
552
|
+
for (const file of share.chunks) {
|
|
553
|
+
vendorChunks.add(file);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Construct an object that contains the shared and federated modules.
|
|
559
|
+
const statsResult = {
|
|
560
|
+
sharedModules,
|
|
561
|
+
federatedModules: [federatedModules],
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
// Convert the 'statsResult' object to a JSON string.
|
|
565
|
+
const statsJson = JSON.stringify(statsResult);
|
|
566
|
+
|
|
567
|
+
// Convert the JSON string to a buffer.
|
|
568
|
+
const statsBuffer = Buffer.from(statsJson, 'utf-8');
|
|
569
|
+
|
|
570
|
+
// Construct an object that represents the source of the final asset.
|
|
571
|
+
const statsSource = {
|
|
572
|
+
source: () => statsBuffer,
|
|
573
|
+
size: () => statsBuffer.length,
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
// Get the filename of the final asset from the plugin options.
|
|
577
|
+
const { filename } = this._options;
|
|
578
|
+
|
|
579
|
+
// If filename is an array, loop over it to emit or update assets.
|
|
580
|
+
if (Array.isArray(filename)) {
|
|
581
|
+
for (const file of filename) {
|
|
582
|
+
// Check if an asset with the same filename already exists.
|
|
583
|
+
const asset = compilation.getAsset(file);
|
|
584
|
+
|
|
585
|
+
// If an asset with the same filename already exists, update it. Otherwise, create a new asset.
|
|
586
|
+
if (asset) {
|
|
587
|
+
compilation.updateAsset(file, statsSource);
|
|
588
|
+
} else {
|
|
589
|
+
compilation.emitAsset(file, statsSource);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
// Check if an asset with the same filename already exists.
|
|
594
|
+
const asset = compilation.getAsset(filename);
|
|
595
|
+
|
|
596
|
+
// If an asset with the same filename already exists, update it. Otherwise, create a new asset.
|
|
597
|
+
if (asset) {
|
|
598
|
+
compilation.updateAsset(filename, statsSource);
|
|
599
|
+
} else {
|
|
600
|
+
compilation.emitAsset(filename, statsSource);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
);
|
|
605
|
+
});
|
|
606
|
+
}
|
|
440
607
|
}
|
|
608
|
+
|
|
441
609
|
module.exports = FederationStatsPlugin;
|
|
442
|
-
//# sourceMappingURL=ChunkCorrelationPlugin.js.map
|