@module-federation/manifest 0.24.1 → 2.0.1

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/dist/index.cjs.js DELETED
@@ -1,1225 +0,0 @@
1
- 'use strict';
2
-
3
- var sdk = require('@module-federation/sdk');
4
- var chalk = require('chalk');
5
- var path = require('path');
6
- var core = require('@module-federation/dts-plugin/core');
7
- var fs = require('fs');
8
- var managers = require('@module-federation/managers');
9
-
10
- const PLUGIN_IDENTIFIER = 'Module Federation Manifest Plugin';
11
- const HOT_UPDATE_SUFFIX = '.hot-update';
12
-
13
- const createBundlerLogger = typeof sdk.createInfrastructureLogger === 'function'
14
- ? sdk.createInfrastructureLogger
15
- : sdk.createLogger;
16
- const logger = createBundlerLogger(chalk.cyan(`[ ${PLUGIN_IDENTIFIER} ]`));
17
-
18
- function isHotFile(file) {
19
- return file.includes(HOT_UPDATE_SUFFIX);
20
- }
21
- const collectAssets = (assets, jsTargetSet, cssTargetSet) => {
22
- assets.forEach((file) => {
23
- if (file.endsWith('.css')) {
24
- cssTargetSet.add(file);
25
- }
26
- else {
27
- if (isDev()) {
28
- if (!isHotFile(file)) {
29
- jsTargetSet.add(file);
30
- }
31
- }
32
- else {
33
- jsTargetSet.add(file);
34
- }
35
- }
36
- });
37
- };
38
- function getSharedModuleName(name) {
39
- const [_type, _shared, _module, _shareScope, sharedInfo] = name.split(' ');
40
- return sharedInfo.split('@').slice(0, -1).join('@');
41
- }
42
- function getAssetsByChunkIDs(compilation, chunkIDMap) {
43
- const arrayChunks = Array.from(compilation.chunks);
44
- const assetMap = {};
45
- Object.keys(chunkIDMap).forEach((key) => {
46
- const chunkIDs = Array.from(chunkIDMap[key]);
47
- if (!assetMap[key]) {
48
- assetMap[key] = {
49
- css: new Set(),
50
- js: new Set(),
51
- };
52
- }
53
- chunkIDs.forEach((chunkID) => {
54
- const chunk = arrayChunks.find((item) => item.id === chunkID);
55
- if (chunk) {
56
- collectAssets([...chunk.files], assetMap[key].js, assetMap[key].css);
57
- }
58
- });
59
- });
60
- const assets = {};
61
- Object.keys(assetMap).map((key) => {
62
- assets[key] = {
63
- js: Array.from(assetMap[key].js),
64
- css: Array.from(assetMap[key].css),
65
- };
66
- });
67
- return assets;
68
- }
69
- function findChunk(id, chunks) {
70
- for (const chunk of chunks) {
71
- if (id === chunk.id) {
72
- return chunk;
73
- }
74
- }
75
- }
76
- function getSharedModules(stats, sharedModules) {
77
- // 获取入口文件就是实际内容的 module
78
- const entryContentModuleNames = [];
79
- let effectiveSharedModules = stats.modules?.reduce((sum, module) => {
80
- for (const sharedModule of sharedModules) {
81
- if (sharedModule.name === module.issuerName) {
82
- entryContentModuleNames.push(sharedModule.name);
83
- sum.push([getSharedModuleName(module.issuerName), module]);
84
- return sum;
85
- }
86
- }
87
- return sum;
88
- }, []) || [];
89
- // 获取入口文件仅作为 Re Export 的 module
90
- const entryReExportModules = sharedModules.filter((sharedModule) => !entryContentModuleNames.includes(sharedModule.name));
91
- if (entryReExportModules.length) {
92
- effectiveSharedModules = effectiveSharedModules.concat(stats.modules.reduce((sum, module) => {
93
- let flag = false;
94
- for (const entryReExportModule of entryReExportModules) {
95
- if (flag) {
96
- break;
97
- }
98
- if (module.reasons) {
99
- for (const issueModule of module.reasons) {
100
- if (issueModule.moduleName === entryReExportModule.name) {
101
- sum.push([
102
- getSharedModuleName(entryReExportModule.name),
103
- module,
104
- ]);
105
- flag = true;
106
- break;
107
- }
108
- }
109
- }
110
- }
111
- return sum;
112
- }, []));
113
- }
114
- return effectiveSharedModules;
115
- }
116
- function getAssetsByChunk(chunk, entryPointNames) {
117
- const assesSet = {
118
- js: {
119
- sync: new Set(),
120
- async: new Set(),
121
- },
122
- css: {
123
- sync: new Set(),
124
- async: new Set(),
125
- },
126
- };
127
- const collectChunkFiles = (targetChunk, type) => {
128
- [...targetChunk.groupsIterable].forEach((chunkGroup) => {
129
- if (chunkGroup.name && !entryPointNames.includes(chunkGroup.name)) {
130
- collectAssets(chunkGroup.getFiles(), assesSet.js[type], assesSet.css[type]);
131
- }
132
- });
133
- };
134
- collectChunkFiles(chunk, 'sync');
135
- [...chunk.getAllAsyncChunks()].forEach((asyncChunk) => {
136
- collectAssets([...asyncChunk.files], assesSet.js['async'], assesSet.css['async']);
137
- collectChunkFiles(asyncChunk, 'async');
138
- });
139
- const assets = {
140
- js: {
141
- sync: Array.from(assesSet.js.sync),
142
- async: Array.from(assesSet.js.async),
143
- },
144
- css: {
145
- sync: Array.from(assesSet.css.sync),
146
- async: Array.from(assesSet.css.async),
147
- },
148
- };
149
- return assets;
150
- }
151
- function assert(condition, msg) {
152
- if (!condition) {
153
- error(msg);
154
- }
155
- }
156
- function error(msg) {
157
- throw new Error(`[ ${PLUGIN_IDENTIFIER} ]: ${msg}`);
158
- }
159
- function isDev() {
160
- return process.env['NODE_ENV'] === 'development';
161
- }
162
- function getFileNameWithOutExt(str) {
163
- return str.replace(path.extname(str), '');
164
- }
165
- function getTypesMetaInfo(pluginOptions, context) {
166
- const defaultRemoteOptions = {
167
- generateAPITypes: true,
168
- compileInChildProcess: true,
169
- };
170
- const defaultTypesMetaInfo = {
171
- path: '',
172
- name: '',
173
- zip: '',
174
- api: '',
175
- };
176
- try {
177
- const normalizedDtsOptions = sdk.normalizeOptions(core.isTSProject(pluginOptions.dts, context), {
178
- generateTypes: defaultRemoteOptions,
179
- consumeTypes: {},
180
- }, 'mfOptions.dts')(pluginOptions.dts);
181
- if (normalizedDtsOptions === false) {
182
- return defaultTypesMetaInfo;
183
- }
184
- const normalizedRemote = sdk.normalizeOptions(true, defaultRemoteOptions, 'mfOptions.dts.generateTypes')(normalizedDtsOptions.generateTypes);
185
- if (normalizedRemote === false) {
186
- return defaultTypesMetaInfo;
187
- }
188
- const { apiFileName, zipName } = core.retrieveTypesAssetsInfo({
189
- ...normalizedRemote,
190
- context,
191
- moduleFederationConfig: pluginOptions,
192
- });
193
- return {
194
- path: '',
195
- name: '',
196
- zip: zipName,
197
- api: apiFileName,
198
- };
199
- }
200
- catch (err) {
201
- logger.warn(`getTypesMetaInfo failed, it will use the default types meta info, and the errors as belows: ${err}`);
202
- return defaultTypesMetaInfo;
203
- }
204
- }
205
-
206
- class ManifestManager {
207
- constructor() {
208
- this._options = {};
209
- }
210
- init(options) {
211
- this._options = options;
212
- }
213
- get fileName() {
214
- return sdk.getManifestFileName(this._options.manifest).manifestFileName;
215
- }
216
- updateManifest(options) {
217
- const manifest = this.generateManifest(options);
218
- return manifest;
219
- }
220
- generateManifest(options) {
221
- const { publicPath, stats, compiler } = options;
222
- // Initialize manifest with required properties from stats
223
- const { id, name, metaData } = stats;
224
- if (metaData.buildInfo) {
225
- 'target' in metaData.buildInfo && delete metaData.buildInfo.target;
226
- 'plugins' in metaData.buildInfo && delete metaData.buildInfo.plugins;
227
- }
228
- const manifest = {
229
- id,
230
- name,
231
- metaData,
232
- shared: [],
233
- remotes: [],
234
- exposes: [],
235
- };
236
- manifest.exposes = stats.exposes.reduce((sum, cur) => {
237
- const expose = {
238
- id: cur.id,
239
- name: cur.name,
240
- assets: cur.assets,
241
- path: cur.path,
242
- };
243
- sum.push(expose);
244
- return sum;
245
- }, []);
246
- manifest.shared = stats.shared.reduce((sum, cur) => {
247
- const shared = {
248
- id: cur.id,
249
- name: cur.name,
250
- version: cur.version,
251
- singleton: cur.singleton,
252
- requiredVersion: cur.requiredVersion,
253
- hash: cur.hash,
254
- assets: cur.assets,
255
- fallback: cur.fallback,
256
- fallbackName: cur.fallbackName,
257
- fallbackType: cur.fallbackType,
258
- };
259
- sum.push(shared);
260
- return sum;
261
- }, []);
262
- manifest.remotes = stats.remotes.reduce((sum, cur) => {
263
- // @ts-ignore version/entry will be added as follow
264
- const remote = {
265
- federationContainerName: cur.federationContainerName,
266
- moduleName: cur.moduleName,
267
- alias: cur.alias,
268
- };
269
- if ('entry' in cur) {
270
- // @ts-ignore
271
- remote.entry = cur.entry;
272
- }
273
- else if ('version' in cur) {
274
- // @ts-ignore
275
- remote.entry = cur.version;
276
- }
277
- sum.push(remote);
278
- return sum;
279
- }, []);
280
- if (isDev() &&
281
- (process.env['MF_SSR_PRJ']
282
- ? compiler.options.target !== 'async-node'
283
- : true)) {
284
- logger.info(`Manifest Link: ${chalk.cyan(`${publicPath === 'auto' ? '{auto}/' : publicPath}${this.fileName}`)} `);
285
- }
286
- return manifest;
287
- }
288
- }
289
-
290
- const isNonEmptyString = (value) => {
291
- return typeof value === 'string' && value.trim().length > 0;
292
- };
293
- const normalizeExposeValue = (exposeValue) => {
294
- if (!exposeValue) {
295
- return undefined;
296
- }
297
- const toImportArray = (value) => {
298
- if (isNonEmptyString(value)) {
299
- return [value];
300
- }
301
- if (Array.isArray(value)) {
302
- const normalized = value.filter(isNonEmptyString);
303
- return normalized.length ? normalized : undefined;
304
- }
305
- return undefined;
306
- };
307
- if (typeof exposeValue === 'object') {
308
- if ('import' in exposeValue) {
309
- const { import: rawImport, name } = exposeValue;
310
- const normalizedImport = toImportArray(rawImport);
311
- if (!normalizedImport?.length) {
312
- return undefined;
313
- }
314
- return {
315
- import: normalizedImport,
316
- ...(isNonEmptyString(name) ? { name } : {}),
317
- };
318
- }
319
- return undefined;
320
- }
321
- const normalizedImport = toImportArray(exposeValue);
322
- if (!normalizedImport?.length) {
323
- return undefined;
324
- }
325
- return { import: normalizedImport };
326
- };
327
- const parseContainerExposeEntries = (identifier) => {
328
- const startIndex = identifier.indexOf('[');
329
- if (startIndex < 0) {
330
- return undefined;
331
- }
332
- let depth = 0;
333
- let inString = false;
334
- let isEscaped = false;
335
- for (let cursor = startIndex; cursor < identifier.length; cursor++) {
336
- const char = identifier[cursor];
337
- if (isEscaped) {
338
- isEscaped = false;
339
- continue;
340
- }
341
- if (char === '\\') {
342
- isEscaped = true;
343
- continue;
344
- }
345
- if (char === '"') {
346
- inString = !inString;
347
- continue;
348
- }
349
- if (inString) {
350
- continue;
351
- }
352
- if (char === '[') {
353
- depth++;
354
- }
355
- else if (char === ']') {
356
- depth--;
357
- if (depth === 0) {
358
- const serialized = identifier.slice(startIndex, cursor + 1);
359
- try {
360
- return JSON.parse(serialized);
361
- }
362
- catch {
363
- return undefined;
364
- }
365
- }
366
- }
367
- }
368
- return undefined;
369
- };
370
- const getExposeName = (exposeKey) => {
371
- return exposeKey.replace('./', '');
372
- };
373
- function getExposeItem({ exposeKey, name, file, }) {
374
- const exposeModuleName = getExposeName(exposeKey);
375
- return {
376
- path: exposeKey,
377
- id: sdk.composeKeyWithSeparator(name, exposeModuleName),
378
- name: exposeModuleName,
379
- // @ts-ignore to deduplicate
380
- requires: [],
381
- file: path.relative(process.cwd(), file.import[0]),
382
- assets: {
383
- js: {
384
- async: [],
385
- sync: [],
386
- },
387
- css: {
388
- async: [],
389
- sync: [],
390
- },
391
- },
392
- };
393
- }
394
- const getShareItem = ({ pkgName, normalizedShareOptions, pkgVersion, hostName, }) => {
395
- return {
396
- ...normalizedShareOptions,
397
- id: `${hostName}:${pkgName}`,
398
- requiredVersion: normalizedShareOptions?.requiredVersion || `^${pkgVersion}`,
399
- name: pkgName,
400
- version: pkgVersion,
401
- assets: {
402
- js: {
403
- async: [],
404
- sync: [],
405
- },
406
- css: {
407
- async: [],
408
- sync: [],
409
- },
410
- },
411
- // @ts-ignore to deduplicate
412
- usedIn: new Set(),
413
- usedExports: [],
414
- fallback: '',
415
- };
416
- };
417
- class ModuleHandler {
418
- constructor(options, modules, { bundler }) {
419
- this._bundler = 'webpack';
420
- this._remoteManager = new managers.RemoteManager();
421
- this._sharedManager = new managers.SharedManager();
422
- this._options = options;
423
- this._modules = modules;
424
- this._bundler = bundler;
425
- this._containerManager = new managers.ContainerManager();
426
- this._containerManager.init(options);
427
- this._remoteManager = new managers.RemoteManager();
428
- this._remoteManager.init(options);
429
- this._sharedManager = new managers.SharedManager();
430
- this._sharedManager.init(options);
431
- }
432
- get isRspack() {
433
- return this._bundler === 'rspack';
434
- }
435
- _handleSharedModule(mod, sharedMap, exposesMap) {
436
- const { identifier, moduleType } = mod;
437
- if (!identifier) {
438
- return;
439
- }
440
- const sharedManagerNormalizedOptions = this._sharedManager.normalizedOptions;
441
- const initShared = (pkgName, pkgVersion) => {
442
- if (sharedMap[pkgName]) {
443
- return;
444
- }
445
- sharedMap[pkgName] = getShareItem({
446
- pkgName,
447
- pkgVersion,
448
- normalizedShareOptions: sharedManagerNormalizedOptions[pkgName],
449
- hostName: this._options.name,
450
- });
451
- };
452
- const collectRelationshipMap = (mod, pkgName) => {
453
- const { issuerName, reasons } = mod;
454
- if (issuerName) {
455
- if (exposesMap[getFileNameWithOutExt(issuerName)]) {
456
- const expose = exposesMap[getFileNameWithOutExt(issuerName)];
457
- // @ts-ignore use Set to deduplicate
458
- expose.requires.push(pkgName);
459
- // @ts-ignore use Set to deduplicate
460
- sharedMap[pkgName].usedIn.add(expose.path);
461
- }
462
- }
463
- if (reasons) {
464
- reasons.forEach(({ resolvedModule, moduleName }) => {
465
- let exposeModName = this.isRspack ? moduleName : resolvedModule;
466
- // filters out entrypoints
467
- if (exposeModName) {
468
- if (exposesMap[getFileNameWithOutExt(exposeModName)]) {
469
- const expose = exposesMap[getFileNameWithOutExt(exposeModName)];
470
- // @ts-ignore to deduplicate
471
- expose.requires.push(pkgName);
472
- // @ts-ignore to deduplicate
473
- sharedMap[pkgName].usedIn.add(expose.path);
474
- }
475
- }
476
- });
477
- }
478
- };
479
- const parseResolvedIdentifier = (nameAndVersion) => {
480
- let name = '';
481
- let version = '';
482
- if (nameAndVersion.startsWith('@')) {
483
- const splitInfo = nameAndVersion.split('@');
484
- splitInfo[0] = '@';
485
- name = splitInfo[0] + splitInfo[1];
486
- version = splitInfo[2];
487
- }
488
- else if (nameAndVersion.includes('@')) {
489
- [name, version] = nameAndVersion.split('@');
490
- version = version.replace(/[\^~>|>=]/g, '');
491
- }
492
- return {
493
- name,
494
- version,
495
- };
496
- };
497
- if (moduleType === 'provide-module') {
498
- // identifier(rspack) = provide shared module (default) react@18.2.0 = /temp/node_modules/.pnpm/react@18.2.0/node_modules/react/index.js
499
- // identifier(webpack) = provide module (default) react@18.2.0 = /temp/node_modules/.pnpm/react@18.2.0/node_modules/react/index.js
500
- const data = identifier.split(' ');
501
- const nameAndVersion = this.isRspack ? data[4] : data[3];
502
- const { name, version } = parseResolvedIdentifier(nameAndVersion);
503
- if (name && version) {
504
- initShared(name, version);
505
- collectRelationshipMap(mod, name);
506
- }
507
- }
508
- if (moduleType === 'consume-shared-module') {
509
- // identifier(rspack) = consume shared module (default) lodash/get@^4.17.21 (strict) (fallback: /temp/node_modules/.pnpm/lodash@4.17.21/node_modules/lodash/get.js)
510
- // identifier(webpack) = consume-shared-module|default|react-dom|!=1.8...2...0|false|/temp/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/index.js|true|false
511
- const SEPARATOR = this.isRspack ? ' ' : '|';
512
- const data = identifier.split(SEPARATOR);
513
- let pkgName = '';
514
- let pkgVersion = '';
515
- if (this.isRspack) {
516
- const nameAndVersion = data[4];
517
- const res = parseResolvedIdentifier(nameAndVersion);
518
- pkgName = res.name;
519
- pkgVersion = res.version;
520
- }
521
- else {
522
- pkgName = data[2];
523
- const pkgVersionRange = data[3];
524
- pkgVersion = '';
525
- if (pkgVersionRange.startsWith('=')) {
526
- pkgVersion = data[3].replace('=', '');
527
- }
528
- else {
529
- if (sharedManagerNormalizedOptions[pkgName]) {
530
- pkgVersion = sharedManagerNormalizedOptions[pkgName].version;
531
- }
532
- else {
533
- const fullPkgName = pkgName.split('/').slice(0, -1).join('/');
534
- // pkgName: react-dom/
535
- if (sharedManagerNormalizedOptions[`${fullPkgName}/`]) {
536
- if (sharedManagerNormalizedOptions[fullPkgName]) {
537
- pkgVersion =
538
- sharedManagerNormalizedOptions[fullPkgName].version;
539
- }
540
- else {
541
- pkgVersion =
542
- sharedManagerNormalizedOptions[`${fullPkgName}/`].version;
543
- }
544
- }
545
- }
546
- }
547
- }
548
- if (pkgName && pkgVersion) {
549
- initShared(pkgName, pkgVersion);
550
- collectRelationshipMap(mod, pkgName);
551
- }
552
- }
553
- }
554
- _handleRemoteModule(mod, remotes, remotesConsumerMap) {
555
- const { identifier, reasons, nameForCondition } = mod;
556
- if (!identifier) {
557
- return;
558
- }
559
- const remoteManagerNormalizedOptions = this._remoteManager.normalizedOptions;
560
- // identifier = remote (default) webpack/container/reference/app2 ./Button
561
- const data = identifier.split(' ');
562
- if (data.length === 4) {
563
- const moduleName = data[3].replace('./', '');
564
- const remoteAlias = data[2].replace('webpack/container/reference/', '');
565
- const normalizedRemote = remoteManagerNormalizedOptions[remoteAlias];
566
- const basicRemote = {
567
- alias: normalizedRemote.alias,
568
- consumingFederationContainerName: this._options.name || '',
569
- federationContainerName: remoteManagerNormalizedOptions[remoteAlias].name,
570
- moduleName,
571
- // @ts-ignore to deduplicate
572
- usedIn: new Set(),
573
- };
574
- if (!nameForCondition) {
575
- return;
576
- }
577
- let remote;
578
- if ('version' in normalizedRemote) {
579
- remote = {
580
- ...basicRemote,
581
- version: normalizedRemote.version,
582
- };
583
- }
584
- else {
585
- remote = {
586
- ...basicRemote,
587
- entry: normalizedRemote.entry,
588
- };
589
- }
590
- remotes.push(remote);
591
- remotesConsumerMap[nameForCondition] = remote;
592
- }
593
- if (reasons) {
594
- reasons.forEach(({ userRequest, resolvedModule, moduleName }) => {
595
- let exposeModName = this.isRspack ? moduleName : resolvedModule;
596
- if (userRequest && exposeModName && remotesConsumerMap[userRequest]) {
597
- // @ts-ignore to deduplicate
598
- remotesConsumerMap[userRequest].usedIn.add(exposeModName.replace('./', ''));
599
- }
600
- });
601
- }
602
- }
603
- _handleContainerModule(mod, exposesMap) {
604
- const { identifier } = mod;
605
- if (!identifier) {
606
- return;
607
- }
608
- // identifier: container entry (default) [[".",{"import":["./src/routes/page.tsx"],"name":"__federation_expose_default_export"}]]'
609
- const entries = parseContainerExposeEntries(identifier) ??
610
- this._getContainerExposeEntriesFromOptions();
611
- if (!entries) {
612
- return;
613
- }
614
- entries.forEach(([prefixedName, file]) => {
615
- // TODO: support multiple import
616
- exposesMap[getFileNameWithOutExt(file.import[0])] = getExposeItem({
617
- exposeKey: prefixedName,
618
- name: this._options.name,
619
- file,
620
- });
621
- });
622
- }
623
- _getContainerExposeEntriesFromOptions() {
624
- const exposes = this._containerManager.containerPluginExposesOptions;
625
- const normalizedEntries = Object.entries(exposes).reduce((acc, [exposeKey, exposeOptions]) => {
626
- const normalizedExpose = normalizeExposeValue(exposeOptions);
627
- if (!normalizedExpose?.import.length) {
628
- return acc;
629
- }
630
- acc.push([exposeKey, normalizedExpose]);
631
- return acc;
632
- }, []);
633
- if (normalizedEntries.length) {
634
- return normalizedEntries;
635
- }
636
- const rawExposes = this._options.exposes;
637
- if (!rawExposes || Array.isArray(rawExposes)) {
638
- return undefined;
639
- }
640
- const normalizedFromOptions = Object.entries(rawExposes).reduce((acc, [exposeKey, exposeOptions]) => {
641
- const normalizedExpose = normalizeExposeValue(exposeOptions);
642
- if (!normalizedExpose?.import.length) {
643
- return acc;
644
- }
645
- acc.push([exposeKey, normalizedExpose]);
646
- return acc;
647
- }, []);
648
- return normalizedFromOptions.length ? normalizedFromOptions : undefined;
649
- }
650
- _initializeExposesFromOptions(exposesMap) {
651
- if (!this._options.name || !this._containerManager.enable) {
652
- return;
653
- }
654
- const exposes = this._containerManager.containerPluginExposesOptions;
655
- Object.entries(exposes).forEach(([exposeKey, exposeOptions]) => {
656
- if (!exposeOptions.import?.length) {
657
- return;
658
- }
659
- const [exposeImport] = exposeOptions.import;
660
- if (!exposeImport) {
661
- return;
662
- }
663
- const exposeMapKey = getFileNameWithOutExt(exposeImport);
664
- if (!exposesMap[exposeMapKey]) {
665
- exposesMap[exposeMapKey] = getExposeItem({
666
- exposeKey,
667
- name: this._options.name,
668
- file: exposeOptions,
669
- });
670
- }
671
- });
672
- }
673
- collect() {
674
- const remotes = [];
675
- const remotesConsumerMap = {};
676
- const exposesMap = {};
677
- const sharedMap = {};
678
- this._initializeExposesFromOptions(exposesMap);
679
- const isSharedModule = (moduleType) => {
680
- return Boolean(moduleType &&
681
- ['provide-module', 'consume-shared-module'].includes(moduleType));
682
- };
683
- const isContainerModule = (identifier) => {
684
- return identifier.startsWith('container entry');
685
- };
686
- const isRemoteModule = (identifier) => {
687
- return identifier.startsWith('remote ');
688
- };
689
- // handle remote/expose
690
- this._modules.forEach((mod) => {
691
- const { identifier, reasons, nameForCondition, moduleType } = mod;
692
- if (!identifier) {
693
- return;
694
- }
695
- if (isSharedModule(moduleType)) {
696
- this._handleSharedModule(mod, sharedMap, exposesMap);
697
- }
698
- if (isRemoteModule(identifier)) {
699
- this._handleRemoteModule(mod, remotes, remotesConsumerMap);
700
- }
701
- else if (isContainerModule(identifier)) {
702
- this._handleContainerModule(mod, exposesMap);
703
- }
704
- });
705
- return {
706
- remotes,
707
- exposesMap,
708
- sharedMap,
709
- };
710
- }
711
- }
712
-
713
- /* eslint-disable max-lines-per-function */
714
- /* eslint-disable @typescript-eslint/member-ordering */
715
- /* eslint-disable max-depth */
716
- class StatsManager {
717
- constructor() {
718
- this._options = {};
719
- this._bundler = 'webpack';
720
- this._containerManager = new managers.ContainerManager();
721
- this._remoteManager = new managers.RemoteManager();
722
- this._sharedManager = new managers.SharedManager();
723
- this._pkgJsonManager = new managers.PKGJsonManager();
724
- }
725
- getBuildInfo(context, target) {
726
- const rootPath = context || process.cwd();
727
- const pkg = this._pkgJsonManager.readPKGJson(rootPath);
728
- const statsBuildInfo = {
729
- buildVersion: managers.utils.getBuildVersion(rootPath),
730
- buildName: managers.utils.getBuildName() || pkg['name'],
731
- };
732
- if (this._sharedManager.enableTreeShaking) {
733
- statsBuildInfo.target = target
734
- ? Array.isArray(target)
735
- ? target
736
- : [target]
737
- : [];
738
- statsBuildInfo.plugins = this._options.treeShakingSharedPlugins || [];
739
- statsBuildInfo.excludePlugins =
740
- this._options.treeShakingSharedExcludePlugins || [];
741
- }
742
- return statsBuildInfo;
743
- }
744
- get fileName() {
745
- return sdk.getManifestFileName(this._options.manifest).statsFileName;
746
- }
747
- setMetaDataPublicPath(metaData, compiler) {
748
- if (this._options.getPublicPath) {
749
- if ('publicPath' in metaData) {
750
- // @ts-ignore
751
- delete metaData.publicPath;
752
- }
753
- metaData.getPublicPath = this._options.getPublicPath;
754
- }
755
- else {
756
- metaData.publicPath =
757
- this.getPublicPath(compiler);
758
- }
759
- return metaData;
760
- }
761
- _getMetaData(compiler, compilation, extraOptions) {
762
- const { context } = compiler.options;
763
- const { _options: { name }, } = this;
764
- const buildInfo = this.getBuildInfo(context, compilation.options.target || '');
765
- const type = this._pkgJsonManager.getExposeGarfishModuleType(context || process.cwd());
766
- const getRemoteEntryName = () => {
767
- if (!this._containerManager.enable) {
768
- return '';
769
- }
770
- assert(name, 'name is required');
771
- const remoteEntryPoint = compilation.entrypoints.get(name);
772
- assert(remoteEntryPoint, 'Can not get remoteEntry entryPoint!');
773
- const remoteEntryNameChunk = compilation.namedChunks.get(name);
774
- assert(remoteEntryNameChunk, 'Can not get remoteEntry chunk!');
775
- const files = Array.from(remoteEntryNameChunk.files).filter((f) => !f.includes(HOT_UPDATE_SUFFIX) && !f.endsWith('.css'));
776
- assert(files.length > 0, 'no files found for remoteEntry chunk');
777
- assert(files.length === 1, `remoteEntry chunk should not have multiple files!, current files: ${files.join(',')}`);
778
- const remoteEntryName = files[0];
779
- return remoteEntryName;
780
- };
781
- const globalName = this._containerManager.globalEntryName;
782
- assert(globalName, 'Can not get library.name, please ensure you have set library.name and the type is "string" !');
783
- assert(this._pluginVersion, 'Can not get pluginVersion, please ensure you have set pluginVersion !');
784
- const metaData = {
785
- name: name,
786
- type,
787
- buildInfo,
788
- remoteEntry: {
789
- name: getRemoteEntryName(),
790
- path: '',
791
- // same as the types supported by runtime, currently only global/var/script is supported
792
- type: this._options?.library?.type ||
793
- 'global',
794
- },
795
- types: getTypesMetaInfo(this._options, compiler.context),
796
- globalName: globalName,
797
- pluginVersion: this._pluginVersion,
798
- };
799
- let prefetchInterface = false;
800
- const prefetchFilePath = path.resolve(compiler.options.context || process.cwd(), `node_modules/.mf/${sdk.encodeName(name)}/${sdk.MFPrefetchCommon.fileName}`);
801
- const existPrefetch = fs.existsSync(prefetchFilePath);
802
- if (existPrefetch) {
803
- const content = fs.readFileSync(prefetchFilePath).toString();
804
- if (content) {
805
- prefetchInterface = true;
806
- }
807
- }
808
- metaData.prefetchInterface = prefetchInterface;
809
- return this.setMetaDataPublicPath(metaData, compiler);
810
- }
811
- _getFilteredModules(stats) {
812
- const filteredModules = stats.modules.filter((module) => {
813
- if (!module || !module.name) {
814
- return false;
815
- }
816
- const array = [
817
- module.name.includes('container entry'),
818
- module.name.includes('remote '),
819
- module.name.includes('shared module '),
820
- module.name.includes('provide module '),
821
- ];
822
- return array.some((item) => item);
823
- });
824
- return filteredModules;
825
- }
826
- _getModuleAssets(compilation, entryPointNames) {
827
- const { chunks } = compilation;
828
- const { exposeFileNameImportMap } = this._containerManager;
829
- const assets = {};
830
- chunks.forEach((chunk) => {
831
- if (typeof chunk.name === 'string' &&
832
- exposeFileNameImportMap[chunk.name]) {
833
- // TODO: support multiple import
834
- const exposeKey = exposeFileNameImportMap[chunk.name][0];
835
- assets[getFileNameWithOutExt(exposeKey)] = getAssetsByChunk(chunk, entryPointNames);
836
- }
837
- });
838
- return assets;
839
- }
840
- _getProvideSharedAssets(compilation, stats, entryPointNames) {
841
- const sharedModules = stats.modules.filter((module) => {
842
- if (!module || !module.name) {
843
- return false;
844
- }
845
- const array = [module.name.includes('consume shared module ')];
846
- return array.some((item) => item);
847
- });
848
- const manifestOverrideChunkIDMap = {};
849
- const effectiveSharedModules = getSharedModules(stats, sharedModules);
850
- effectiveSharedModules.forEach((item) => {
851
- const [sharedModuleName, sharedModule] = item;
852
- if (!manifestOverrideChunkIDMap[sharedModuleName]) {
853
- manifestOverrideChunkIDMap[sharedModuleName] = {
854
- async: new Set(),
855
- sync: new Set(),
856
- };
857
- }
858
- sharedModule.chunks.forEach((chunkID) => {
859
- const chunk = findChunk(chunkID, compilation.chunks);
860
- manifestOverrideChunkIDMap[sharedModuleName].sync.add(chunkID);
861
- if (!chunk) {
862
- return;
863
- }
864
- [...chunk.groupsIterable].forEach((group) => {
865
- if (group.name && !entryPointNames.includes(group.name)) {
866
- manifestOverrideChunkIDMap[sharedModuleName].sync.add(group.id);
867
- }
868
- });
869
- });
870
- });
871
- const assets = {
872
- js: {
873
- async: [],
874
- sync: [],
875
- },
876
- css: {
877
- async: [],
878
- sync: [],
879
- },
880
- };
881
- Object.keys(manifestOverrideChunkIDMap).forEach((override) => {
882
- const asyncAssets = getAssetsByChunkIDs(compilation, {
883
- [override]: manifestOverrideChunkIDMap[override].async,
884
- });
885
- const syncAssets = getAssetsByChunkIDs(compilation, {
886
- [override]: manifestOverrideChunkIDMap[override].sync,
887
- });
888
- assets[override] = {
889
- js: {
890
- async: asyncAssets[override].js,
891
- sync: syncAssets[override].js,
892
- },
893
- css: {
894
- async: asyncAssets[override].css,
895
- sync: syncAssets[override].css,
896
- },
897
- };
898
- });
899
- return assets;
900
- }
901
- async _generateStats(compiler, compilation, extraOptions) {
902
- try {
903
- const { name, manifest: manifestOptions = {}, exposes = {}, } = this._options;
904
- const metaData = this._getMetaData(compiler, compilation, extraOptions);
905
- const stats = {
906
- id: name,
907
- name: name,
908
- metaData,
909
- shared: [],
910
- remotes: [],
911
- exposes: [],
912
- };
913
- if (typeof manifestOptions === 'object' &&
914
- manifestOptions.disableAssetsAnalyze) {
915
- const remotes = this._remoteManager.statsRemoteWithEmptyUsedIn;
916
- stats.remotes = remotes;
917
- stats.exposes = Object.keys(exposes).map((exposeKey) => {
918
- return getExposeItem({
919
- exposeKey,
920
- name: name,
921
- file: {
922
- import: exposes[exposeKey].import,
923
- },
924
- });
925
- });
926
- stats.shared = Object.entries(this._sharedManager.normalizedOptions).reduce((sum, cur) => {
927
- const [pkgName, normalizedShareOptions] = cur;
928
- sum.push(getShareItem({
929
- pkgName,
930
- normalizedShareOptions,
931
- pkgVersion: normalizedShareOptions.version || managers.UNKNOWN_MODULE_NAME,
932
- hostName: name,
933
- }));
934
- return sum;
935
- }, []);
936
- return stats;
937
- }
938
- const liveStats = compilation.getStats();
939
- const statsOptions = {
940
- all: false,
941
- modules: true,
942
- builtAt: true,
943
- hash: true,
944
- ids: true,
945
- version: true,
946
- entrypoints: true,
947
- assets: false,
948
- chunks: false,
949
- reasons: true,
950
- };
951
- if (this._bundler === 'webpack') {
952
- statsOptions['cached'] = true;
953
- }
954
- statsOptions['cachedModules'] = true;
955
- const webpackStats = liveStats.toJson(statsOptions);
956
- const filteredModules = this._getFilteredModules(webpackStats);
957
- const moduleHandler = new ModuleHandler(this._options, filteredModules, {
958
- bundler: this._bundler,
959
- });
960
- const { remotes, exposesMap, sharedMap } = moduleHandler.collect();
961
- const entryPointNames = [...compilation.entrypoints.values()]
962
- .map((e) => e.name)
963
- .filter((v) => !!v);
964
- await Promise.all([
965
- new Promise((resolve) => {
966
- const sharedAssets = this._getProvideSharedAssets(compilation, webpackStats, entryPointNames);
967
- Object.keys(sharedMap).forEach((sharedKey) => {
968
- const assets = sharedAssets[sharedKey];
969
- if (assets) {
970
- sharedMap[sharedKey].assets = assets;
971
- }
972
- });
973
- resolve();
974
- }),
975
- new Promise((resolve) => {
976
- const moduleAssets = this._getModuleAssets(compilation, entryPointNames);
977
- Object.keys(exposesMap).forEach((exposeKey) => {
978
- const assets = moduleAssets[exposeKey];
979
- if (assets) {
980
- exposesMap[exposeKey].assets = assets;
981
- }
982
- exposesMap[exposeKey].requires = Array.from(new Set(exposesMap[exposeKey].requires));
983
- });
984
- resolve();
985
- }),
986
- ]);
987
- await Promise.all([
988
- new Promise((resolve) => {
989
- const remoteMemo = new Set();
990
- stats.remotes = remotes.map((remote) => {
991
- remoteMemo.add(remote.federationContainerName);
992
- return {
993
- ...remote,
994
- usedIn: Array.from(remote.usedIn.values()),
995
- };
996
- });
997
- const statsRemoteWithEmptyUsedIn = this._remoteManager.statsRemoteWithEmptyUsedIn;
998
- statsRemoteWithEmptyUsedIn.forEach((remoteInfo) => {
999
- if (!remoteMemo.has(remoteInfo.federationContainerName)) {
1000
- stats.remotes.push(remoteInfo);
1001
- }
1002
- });
1003
- resolve();
1004
- }),
1005
- new Promise((resolve) => {
1006
- stats.shared = Object.values(sharedMap).map((shared) => ({
1007
- ...shared,
1008
- usedIn: Array.from(shared.usedIn),
1009
- }));
1010
- resolve();
1011
- }),
1012
- ]);
1013
- await new Promise((resolve) => {
1014
- const sharedAssets = stats.shared.reduce((sum, shared) => {
1015
- const { js, css } = shared.assets;
1016
- [...js.sync, ...js.async, ...css.async, css.sync].forEach((asset) => {
1017
- sum.add(asset);
1018
- });
1019
- return sum;
1020
- }, new Set());
1021
- const { fileExposeKeyMap } = this._containerManager;
1022
- stats.exposes = [];
1023
- Object.entries(fileExposeKeyMap).forEach(([exposeFileWithoutExt, exposeKeySet]) => {
1024
- const expose = exposesMap[exposeFileWithoutExt] || {
1025
- assets: {
1026
- js: { sync: [], async: [] },
1027
- css: { sync: [], async: [] },
1028
- },
1029
- };
1030
- exposeKeySet.forEach((exposeKey) => {
1031
- const { js, css } = expose.assets;
1032
- const exposeModuleName = getExposeName(exposeKey);
1033
- stats.exposes.push({
1034
- ...expose,
1035
- path: exposeKey,
1036
- id: sdk.composeKeyWithSeparator(this._options.name, exposeModuleName),
1037
- name: exposeModuleName,
1038
- assets: {
1039
- js: {
1040
- sync: js.sync.filter((asset) => !sharedAssets.has(asset)),
1041
- async: js.async.filter((asset) => !sharedAssets.has(asset)),
1042
- },
1043
- css: {
1044
- sync: css.sync.filter((asset) => !sharedAssets.has(asset)),
1045
- async: css.async.filter((asset) => !sharedAssets.has(asset)),
1046
- },
1047
- },
1048
- });
1049
- });
1050
- });
1051
- Object.values(exposesMap).map((expose) => {
1052
- const { js, css } = expose.assets;
1053
- return {
1054
- ...expose,
1055
- assets: {
1056
- js: {
1057
- sync: js.sync.filter((asset) => !sharedAssets.has(asset)),
1058
- async: js.async.filter((asset) => !sharedAssets.has(asset)),
1059
- },
1060
- css: {
1061
- sync: css.sync.filter((asset) => !sharedAssets.has(asset)),
1062
- async: css.async.filter((asset) => !sharedAssets.has(asset)),
1063
- },
1064
- },
1065
- };
1066
- });
1067
- resolve();
1068
- });
1069
- return stats;
1070
- }
1071
- catch (err) {
1072
- throw err;
1073
- }
1074
- }
1075
- getPublicPath(compiler) {
1076
- if (this._publicPath) {
1077
- return this._publicPath;
1078
- }
1079
- const { output: { publicPath: originalPublicPath }, } = compiler.options;
1080
- let publicPath = originalPublicPath;
1081
- this._publicPath = publicPath;
1082
- return publicPath;
1083
- }
1084
- init(options, { pluginVersion, bundler, }) {
1085
- this._options = options;
1086
- this._pluginVersion = pluginVersion;
1087
- this._bundler = bundler;
1088
- this._containerManager = new managers.ContainerManager();
1089
- this._containerManager.init(options);
1090
- this._remoteManager = new managers.RemoteManager();
1091
- this._remoteManager.init(options);
1092
- this._sharedManager = new managers.SharedManager();
1093
- this._sharedManager.init(options);
1094
- }
1095
- updateStats(stats, compiler) {
1096
- const { metaData } = stats;
1097
- if (!metaData.types) {
1098
- metaData.types = getTypesMetaInfo(this._options, compiler.context);
1099
- }
1100
- if (!metaData.pluginVersion) {
1101
- metaData.pluginVersion = this._pluginVersion;
1102
- }
1103
- this.setMetaDataPublicPath(metaData, compiler);
1104
- // rspack not support legacy prefetch, and this field should be removed in the future
1105
- metaData.prefetchInterface = false;
1106
- return stats;
1107
- }
1108
- async generateStats(compiler, compilation) {
1109
- try {
1110
- const stats = await this._generateStats(compiler, compilation);
1111
- return stats;
1112
- }
1113
- catch (err) {
1114
- throw err;
1115
- }
1116
- }
1117
- validate(compiler) {
1118
- const { output: { publicPath }, } = compiler.options;
1119
- if (typeof publicPath !== 'string') {
1120
- logger.warn(`Manifest will not generate, because publicPath can only be string, but got '${publicPath}'`);
1121
- return false;
1122
- }
1123
- else if (publicPath === 'auto') {
1124
- logger.warn(`Manifest will use absolute path resolution via its host at runtime, reason: publicPath='${publicPath}'`);
1125
- return true;
1126
- }
1127
- return true;
1128
- }
1129
- }
1130
-
1131
- class StatsPlugin {
1132
- constructor(options, { pluginVersion, bundler, }) {
1133
- this.name = 'StatsPlugin';
1134
- this._options = {};
1135
- this._statsManager = new StatsManager();
1136
- this._manifestManager = new ManifestManager();
1137
- this._enable = true;
1138
- this._bundler = 'webpack';
1139
- try {
1140
- this._options = options;
1141
- this._bundler = bundler;
1142
- this._statsManager.init(this._options, { pluginVersion, bundler });
1143
- this._manifestManager.init(this._options);
1144
- }
1145
- catch (err) {
1146
- if (err instanceof Error) {
1147
- err.message = `[ ${PLUGIN_IDENTIFIER} ]: Manifest will not generate, because: ${err.message}`;
1148
- }
1149
- logger.error(err);
1150
- this._enable = false;
1151
- }
1152
- }
1153
- apply(compiler) {
1154
- sdk.bindLoggerToCompiler(logger, compiler, PLUGIN_IDENTIFIER);
1155
- if (!this._enable) {
1156
- return;
1157
- }
1158
- const res = this._statsManager.validate(compiler);
1159
- if (!res) {
1160
- return;
1161
- }
1162
- compiler.hooks.thisCompilation.tap('generateStats', (compilation) => {
1163
- compilation.hooks.processAssets.tapPromise({
1164
- name: 'generateStats',
1165
- // @ts-ignore use runtime variable in case peer dep not installed
1166
- stage: compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER,
1167
- }, async () => {
1168
- if (this._options.manifest !== false) {
1169
- const existedStats = compilation.getAsset(this._statsManager.fileName);
1170
- // new rspack should hit
1171
- if (existedStats) {
1172
- let updatedStats = this._statsManager.updateStats(JSON.parse(existedStats.source.source().toString()), compiler);
1173
- if (typeof this._options.manifest === 'object' &&
1174
- this._options.manifest.additionalData) {
1175
- updatedStats =
1176
- (await this._options.manifest.additionalData({
1177
- stats: updatedStats,
1178
- compiler,
1179
- compilation,
1180
- bundler: this._bundler,
1181
- })) || updatedStats;
1182
- }
1183
- compilation.updateAsset(this._statsManager.fileName, new compiler.webpack.sources.RawSource(JSON.stringify(updatedStats, null, 2)));
1184
- const updatedManifest = this._manifestManager.updateManifest({
1185
- compilation,
1186
- stats: updatedStats,
1187
- publicPath: this._statsManager.getPublicPath(compiler),
1188
- compiler,
1189
- bundler: this._bundler,
1190
- });
1191
- const source = new compiler.webpack.sources.RawSource(JSON.stringify(updatedManifest, null, 2));
1192
- compilation.updateAsset(this._manifestManager.fileName, source);
1193
- return;
1194
- }
1195
- // webpack + legacy rspack
1196
- let stats = await this._statsManager.generateStats(compiler, compilation);
1197
- if (typeof this._options.manifest === 'object' &&
1198
- this._options.manifest.additionalData) {
1199
- stats =
1200
- (await this._options.manifest.additionalData({
1201
- stats,
1202
- compiler,
1203
- compilation,
1204
- bundler: this._bundler,
1205
- })) || stats;
1206
- }
1207
- const manifest = await this._manifestManager.generateManifest({
1208
- compilation,
1209
- stats: stats,
1210
- publicPath: this._statsManager.getPublicPath(compiler),
1211
- compiler,
1212
- bundler: this._bundler,
1213
- });
1214
- compilation.emitAsset(this._statsManager.fileName, new compiler.webpack.sources.RawSource(JSON.stringify(stats, null, 2)));
1215
- compilation.emitAsset(this._manifestManager.fileName, new compiler.webpack.sources.RawSource(JSON.stringify(manifest, null, 2)));
1216
- }
1217
- });
1218
- });
1219
- }
1220
- }
1221
-
1222
- exports.ManifestManager = ManifestManager;
1223
- exports.StatsManager = StatsManager;
1224
- exports.StatsPlugin = StatsPlugin;
1225
- //# sourceMappingURL=index.cjs.js.map