@module-federation/vite 1.10.0 → 1.11.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.
Files changed (45) hide show
  1. package/README.md +4 -1
  2. package/lib/index.cjs +1819 -1963
  3. package/lib/index.d.cts +131 -0
  4. package/lib/index.d.mts +131 -0
  5. package/lib/index.mjs +1946 -0
  6. package/package.json +29 -18
  7. package/lib/index.d.ts +0 -4
  8. package/lib/index.esm.js +0 -2091
  9. package/lib/index.modern.js +0 -2123
  10. package/lib/index.umd.js +0 -2112
  11. package/lib/plugins/__tests__/pluginCheckAliasConflicts.test.d.ts +0 -1
  12. package/lib/plugins/__tests__/pluginDts.test.d.ts +0 -1
  13. package/lib/plugins/pluginAddEntry.d.ts +0 -10
  14. package/lib/plugins/pluginCheckAliasConflicts.d.ts +0 -9
  15. package/lib/plugins/pluginDevProxyModuleTopLevelAwait.d.ts +0 -2
  16. package/lib/plugins/pluginDts.d.ts +0 -3
  17. package/lib/plugins/pluginMFManifest.d.ts +0 -3
  18. package/lib/plugins/pluginModuleParseEnd.d.ts +0 -10
  19. package/lib/plugins/pluginProxyRemoteEntry.d.ts +0 -2
  20. package/lib/plugins/pluginProxyRemotes.d.ts +0 -3
  21. package/lib/plugins/pluginProxySharedModule_preBuild.d.ts +0 -7
  22. package/lib/utils/PromiseStore.d.ts +0 -16
  23. package/lib/utils/VirtualModule.d.ts +0 -26
  24. package/lib/utils/__tests__/VirtualModule.test.d.ts +0 -1
  25. package/lib/utils/__tests__/cssModuleHelpers.test.d.ts +0 -1
  26. package/lib/utils/__tests__/helpers.d.ts +0 -2
  27. package/lib/utils/__tests__/normalizeModuleFederationOption.test.d.ts +0 -1
  28. package/lib/utils/__tests__/publicPath.test.d.ts +0 -1
  29. package/lib/utils/__tests__/serializeRuntimeOptions.test.d.ts +0 -1
  30. package/lib/utils/aliasToArrayPlugin.d.ts +0 -10
  31. package/lib/utils/cssModuleHelpers.d.ts +0 -75
  32. package/lib/utils/localSharedImportMap_temp.d.ts +0 -2
  33. package/lib/utils/mapCodeToCodeWithSourcemap.d.ts +0 -4
  34. package/lib/utils/normalizeModuleFederationOptions.d.ts +0 -159
  35. package/lib/utils/normalizeOptimizeDeps.d.ts +0 -9
  36. package/lib/utils/packageNameUtils.d.ts +0 -22
  37. package/lib/utils/publicPath.d.ts +0 -9
  38. package/lib/utils/serializeRuntimeOptions.d.ts +0 -10
  39. package/lib/utils/wrapManualChunks.d.ts +0 -1
  40. package/lib/virtualModules/index.d.ts +0 -6
  41. package/lib/virtualModules/virtualExposes.d.ts +0 -2
  42. package/lib/virtualModules/virtualRemoteEntry.d.ts +0 -16
  43. package/lib/virtualModules/virtualRemotes.d.ts +0 -6
  44. package/lib/virtualModules/virtualRuntimeInitStatus.d.ts +0 -3
  45. package/lib/virtualModules/virtualShared_preBuild.d.ts +0 -17
@@ -1,2123 +0,0 @@
1
- import defu from 'defu';
2
- import * as fs from 'fs';
3
- import { mkdirSync, writeFileSync, existsSync, writeFile } from 'fs';
4
- import * as path from 'pathe';
5
- import path__default, { resolve, basename, parse, join, dirname } from 'pathe';
6
- import MagicString from 'magic-string';
7
- import { createFilter } from '@rollup/pluginutils';
8
- import { walk } from 'estree-walker';
9
- import { normalizeOptions } from '@module-federation/sdk';
10
- import { normalizeDtsOptions, normalizeConsumeTypesOptions, consumeTypesAPI, normalizeGenerateTypesOptions, generateTypesAPI, isTSProject } from '@module-federation/dts-plugin';
11
- import { rpc } from '@module-federation/dts-plugin/core';
12
-
13
- async function mapCodeToCodeWithSourcemap(code) {
14
- const resolvedCode = await code;
15
- if (resolvedCode === undefined) {
16
- return;
17
- }
18
- const s = new MagicString(resolvedCode);
19
- return {
20
- code: s.toString(),
21
- map: s.generateMap({
22
- hires: true
23
- })
24
- };
25
- }
26
-
27
- function getFirstHtmlEntryFile(entryFiles) {
28
- return entryFiles.find(file => file.endsWith('.html'));
29
- }
30
- const addEntry = ({
31
- entryName,
32
- entryPath,
33
- fileName,
34
- inject: _inject = 'entry'
35
- }) => {
36
- let devEntryPath = entryPath.startsWith('virtual:mf') ? '@id/' + entryPath : entryPath;
37
- let entryFiles = [];
38
- let htmlFilePath;
39
- let _command;
40
- let emitFileId;
41
- let viteConfig;
42
- function injectHtml() {
43
- return _inject === 'html' && htmlFilePath;
44
- }
45
- function injectEntry() {
46
- return _inject === 'entry' || !htmlFilePath;
47
- }
48
- return [{
49
- name: 'add-entry',
50
- apply: 'serve',
51
- config(config, {
52
- command
53
- }) {
54
- _command = command;
55
- },
56
- configResolved(config) {
57
- viteConfig = config;
58
- devEntryPath = config.base + devEntryPath.replace(/\\\\?/g, '/').replace(/.+?\:([/\\])[/\\]?/, '$1').replace(/^\//, '');
59
- },
60
- configureServer(server) {
61
- server.middlewares.use((req, res, next) => {
62
- if (!fileName) {
63
- next();
64
- return;
65
- }
66
- if (req.url && req.url.startsWith((viteConfig.base + fileName).replace(/^\/?/, '/'))) {
67
- req.url = devEntryPath;
68
- }
69
- next();
70
- });
71
- },
72
- transformIndexHtml(c) {
73
- if (!injectHtml()) return;
74
- return c.replace('<head>', `<head><script type="module" src=${JSON.stringify(devEntryPath.replace(/.+?\:([/\\])[/\\]?/, '$1').replace(/\\\\?/g, '/'))}></script>`);
75
- },
76
- transform(code, id) {
77
- if (id.includes('node_modules') || _inject !== 'html' || htmlFilePath) {
78
- return;
79
- }
80
- if (id.includes('.svelte-kit') && id.includes('internal.js')) {
81
- const src = devEntryPath.replace(/.+?\:([/\\])[/\\]?/, '$1').replace(/\\\\?/g, '/');
82
- return code.replace(/<head>/g, '<head><script type=\\"module\\" src=\\"' + src + '\\"></script>');
83
- }
84
- }
85
- }, {
86
- name: 'add-entry',
87
- enforce: 'post',
88
- configResolved(config) {
89
- viteConfig = config;
90
- const inputOptions = config.build.rollupOptions.input;
91
- if (!inputOptions) {
92
- htmlFilePath = path.resolve(config.root, 'index.html');
93
- } else if (typeof inputOptions === 'string') {
94
- entryFiles = [inputOptions];
95
- } else if (Array.isArray(inputOptions)) {
96
- entryFiles = inputOptions;
97
- } else if (typeof inputOptions === 'object') {
98
- entryFiles = Object.values(inputOptions);
99
- }
100
- if (entryFiles && entryFiles.length > 0) {
101
- htmlFilePath = getFirstHtmlEntryFile(entryFiles);
102
- }
103
- },
104
- buildStart() {
105
- if (_command === 'serve') return;
106
- const hasHash = fileName == null || fileName.includes == null ? void 0 : fileName.includes('[hash');
107
- const emitFileOptions = {
108
- name: entryName,
109
- type: 'chunk',
110
- id: entryPath,
111
- preserveSignature: 'strict'
112
- };
113
- if (!hasHash) {
114
- emitFileOptions.fileName = fileName;
115
- }
116
- emitFileId = this.emitFile(emitFileOptions);
117
- if (htmlFilePath && fs.existsSync(htmlFilePath)) {
118
- const htmlContent = fs.readFileSync(htmlFilePath, 'utf-8');
119
- const scriptRegex = /<script\s+[^>]*src=["']([^"']+)["'][^>]*>/gi;
120
- let match;
121
- while ((match = scriptRegex.exec(htmlContent)) !== null) {
122
- entryFiles.push(match[1]);
123
- }
124
- }
125
- },
126
- generateBundle(options, bundle) {
127
- var _viteConfig$experimen, _viteConfig$experimen2;
128
- if (!injectHtml()) return;
129
- const file = this.getFileName(emitFileId);
130
- const path = (_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl ? (_viteConfig$experimen2 = viteConfig.experimental) == null ? void 0 : _viteConfig$experimen2.renderBuiltUrl(file) : viteConfig.base + file;
131
- const scriptContent = `
132
- <script type="module" src="${path}"></script>
133
- `;
134
- for (const fileName in bundle) {
135
- if (fileName.endsWith('.html')) {
136
- let htmlAsset = bundle[fileName];
137
- if (htmlAsset.type === 'chunk') return;
138
- let htmlContent = htmlAsset.source.toString() || '';
139
- htmlContent = htmlContent.replace('<head>', `<head>${scriptContent}`);
140
- htmlAsset.source = htmlContent;
141
- }
142
- }
143
- },
144
- transform(code, id) {
145
- if (injectEntry() && entryFiles.some(file => id.endsWith(file))) {
146
- const injection = `
147
- import ${JSON.stringify(entryPath)};
148
- `;
149
- return mapCodeToCodeWithSourcemap(injection + code);
150
- }
151
- }
152
- }];
153
- };
154
-
155
- /**
156
- * Check if user-defined alias conflicts with shared modules
157
- * This should run after aliasToArrayPlugin to ensure alias is an array
158
- */
159
- function checkAliasConflicts(options) {
160
- const {
161
- shared = {}
162
- } = options;
163
- const sharedKeys = Object.keys(shared);
164
- return {
165
- name: 'check-alias-conflicts',
166
- configResolved(config) {
167
- var _config$resolve;
168
- if (sharedKeys.length === 0) return;
169
- const userAliases = ((_config$resolve = config.resolve) == null ? void 0 : _config$resolve.alias) || [];
170
- const conflicts = [];
171
- for (const sharedKey of sharedKeys) {
172
- for (const aliasEntry of userAliases) {
173
- const findPattern = aliasEntry.find;
174
- const replacement = aliasEntry.replacement;
175
- // Skip if replacement is not a string (e.g., customResolver)
176
- if (typeof replacement !== 'string') continue;
177
- // Skip Module Federation internal aliases (used for proxying shared modules)
178
- // These are generated with replacement '$1' and should not trigger warnings
179
- if (replacement === '$1') continue;
180
- // Check if alias pattern matches the shared module
181
- let isMatch = false;
182
- if (typeof findPattern === 'string') {
183
- isMatch = findPattern === sharedKey || sharedKey.startsWith(findPattern + '/');
184
- } else if (findPattern instanceof RegExp) {
185
- isMatch = findPattern.test(sharedKey);
186
- }
187
- if (isMatch) {
188
- conflicts.push({
189
- sharedModule: sharedKey,
190
- alias: String(findPattern),
191
- target: replacement
192
- });
193
- }
194
- }
195
- }
196
- if (conflicts.length > 0) {
197
- config.logger.warn('\n[Module Federation] Detected alias conflicts with shared modules:');
198
- conflicts.forEach(({
199
- sharedModule,
200
- alias,
201
- target
202
- }) => {
203
- config.logger.warn(` - Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
204
- });
205
- config.logger.warn(" This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
206
- }
207
- }
208
- };
209
- }
210
-
211
- /**
212
- * Solve the problem that dev mode dependency prebunding does not support top-level await syntax
213
- */
214
- function PluginDevProxyModuleTopLevelAwait() {
215
- const filterFunction = createFilter();
216
- const processedFlag = '/* already-processed-by-dev-proxy-module-top-level-await */';
217
- return {
218
- name: 'dev-proxy-module-top-level-await',
219
- apply: 'serve',
220
- transform(code, id) {
221
- if (code.includes(processedFlag)) {
222
- return null;
223
- }
224
- if (!code.includes('/*mf top-level-await placeholder replacement mf*/')) {
225
- return null;
226
- }
227
- if (!filterFunction(id)) return null;
228
- let ast;
229
- try {
230
- ast = this.parse(code, {
231
- allowReturnOutsideFunction: true
232
- });
233
- } catch (e) {
234
- throw new Error(`${id}: ${e}`);
235
- }
236
- const magicString = new MagicString(code);
237
- walk(ast, {
238
- enter(node) {
239
- if (node.type === 'ExportNamedDeclaration' && node.specifiers) {
240
- const exportSpecifiers = node.specifiers.map(specifier => specifier.exported.name);
241
- const proxyStatements = exportSpecifiers.map(name => `
242
- const __mfproxy__await${name} = await ${name}();
243
- const __mfproxy__${name} = () => __mfproxy__await${name};
244
- `).join('\n');
245
- const exportStatements = exportSpecifiers.map(name => `__mfproxy__${name} as ${name}`).join(', ');
246
- const start = node.start;
247
- const end = node.end;
248
- const replacement = `${proxyStatements}\nexport { ${exportStatements} };`;
249
- magicString.overwrite(start, end, replacement);
250
- }
251
- if (node.type === 'ExportDefaultDeclaration') {
252
- const declaration = node.declaration;
253
- const start = node.start;
254
- const end = node.end;
255
- let proxyStatement;
256
- let exportStatement = 'default';
257
- if (declaration.type === 'Identifier') {
258
- // example: export default foo;
259
- proxyStatement = `
260
- const __mfproxy__awaitdefault = await ${declaration.name}();
261
- const __mfproxy__default = __mfproxy__awaitdefault;
262
- `;
263
- } else if (declaration.type === 'CallExpression' || declaration.type === 'FunctionDeclaration') {
264
- // example: export default someFunction();
265
- const declarationCode = code.slice(declaration.start, declaration.end);
266
- proxyStatement = `
267
- const __mfproxy__awaitdefault = await (${declarationCode});
268
- const __mfproxy__default = __mfproxy__awaitdefault;
269
- `;
270
- } else {
271
- // other
272
- proxyStatement = `
273
- const __mfproxy__awaitdefault = await (${code.slice(declaration.start, declaration.end)});
274
- const __mfproxy__default = __mfproxy__awaitdefault;
275
- `;
276
- }
277
- const replacement = `${proxyStatement}\nexport { __mfproxy__default as ${exportStatement} };`;
278
- magicString.overwrite(start, end, replacement);
279
- }
280
- }
281
- });
282
- const transformedCode = magicString.toString();
283
- return {
284
- code: `${processedFlag}\n${transformedCode}`,
285
- map: magicString.generateMap({
286
- hires: true
287
- })
288
- };
289
- }
290
- };
291
- }
292
-
293
- function _extends() {
294
- return _extends = Object.assign ? Object.assign.bind() : function (n) {
295
- for (var e = 1; e < arguments.length; e++) {
296
- var t = arguments[e];
297
- for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
298
- }
299
- return n;
300
- }, _extends.apply(null, arguments);
301
- }
302
-
303
- const DEFAULT_DEV_OPTIONS = {
304
- disableLiveReload: true,
305
- disableHotTypesReload: false,
306
- disableDynamicRemoteTypeHints: false
307
- };
308
- const DYNAMIC_HINTS_PLUGIN = '@module-federation/dts-plugin/dynamic-remote-type-hints-plugin';
309
- const getIPv4 = () => process.env['FEDERATION_IPV4'] || '127.0.0.1';
310
- const forkDevWorkerPath = (() => {
311
- // eslint-disable-next-line @typescript-eslint/no-var-requires
312
- return require.resolve('@module-federation/dts-plugin/dist/fork-dev-worker.js');
313
- })();
314
- class DevWorker {
315
- constructor(options) {
316
- this.worker = rpc.createRpcWorker(forkDevWorkerPath, {}, undefined, false);
317
- this.worker.connect(options);
318
- }
319
- update() {
320
- var _this$worker$process;
321
- (_this$worker$process = this.worker.process) == null || _this$worker$process.send == null || _this$worker$process.send({
322
- type: rpc.RpcGMCallTypes.CALL,
323
- id: this.worker.id,
324
- args: [undefined, 'update']
325
- });
326
- }
327
- exit() {
328
- this.worker.terminate();
329
- }
330
- }
331
- const normalizeDevOptions = dev => {
332
- if (dev === false) {
333
- return false;
334
- }
335
- if (dev === true || typeof dev === 'undefined') {
336
- return _extends({}, DEFAULT_DEV_OPTIONS);
337
- }
338
- return _extends({}, DEFAULT_DEV_OPTIONS, dev);
339
- };
340
- const buildDtsModuleFederationConfig = options => {
341
- const exposes = {};
342
- Object.entries(options.exposes).forEach(([key, value]) => {
343
- if (typeof value === 'string') {
344
- exposes[key] = value;
345
- return;
346
- }
347
- const importValue = Array.isArray(value.import) ? value.import[0] : value.import;
348
- if (importValue) {
349
- exposes[key] = importValue;
350
- }
351
- });
352
- const remotes = {};
353
- Object.entries(options.remotes).forEach(([key, remote]) => {
354
- var _remote$entryGlobalNa, _remote$entryGlobalNa2;
355
- if (typeof remote === 'string') {
356
- remotes[key] = remote;
357
- return;
358
- }
359
- if (!remote.entry) {
360
- return;
361
- }
362
- const entryLooksLikeUrl = ((_remote$entryGlobalNa = remote.entryGlobalName) == null ? void 0 : _remote$entryGlobalNa.startsWith('http')) || ((_remote$entryGlobalNa2 = remote.entryGlobalName) == null ? void 0 : _remote$entryGlobalNa2.includes('.json'));
363
- const entryGlobalName = entryLooksLikeUrl ? remote.name || key : remote.entryGlobalName || remote.name || key;
364
- remotes[key] = `${entryGlobalName}@${remote.entry}`;
365
- });
366
- return _extends({}, options, {
367
- exposes,
368
- remotes
369
- });
370
- };
371
- const resolveOutputDir = config => {
372
- const {
373
- outDir
374
- } = config.build;
375
- if (path.isAbsolute(outDir)) {
376
- return path.relative(config.root, outDir);
377
- }
378
- return outDir;
379
- };
380
- const ensureRuntimePlugin = (options, pluginId) => {
381
- const hasPlugin = options.runtimePlugins.some(plugin => {
382
- if (typeof plugin === 'string') {
383
- return plugin === pluginId;
384
- }
385
- return plugin[0] === pluginId;
386
- });
387
- if (!hasPlugin) {
388
- options.runtimePlugins.push(pluginId);
389
- }
390
- };
391
- const normalizeDevDtsOptions = (dts, context) => {
392
- const defaultGenerateTypes = {
393
- compileInChildProcess: true
394
- };
395
- const defaultConsumeTypes = {
396
- consumeAPITypes: true
397
- };
398
- return normalizeOptions(isTSProject(dts, context), {
399
- generateTypes: defaultGenerateTypes,
400
- consumeTypes: defaultConsumeTypes,
401
- extraOptions: {},
402
- displayErrorInTerminal: typeof dts === 'object' && dts ? dts.displayErrorInTerminal : undefined
403
- }, 'mfOptions.dts')(dts);
404
- };
405
- const logDtsError = (error, dtsOptions) => {
406
- if (dtsOptions === false) {
407
- return;
408
- }
409
- if (typeof dtsOptions === 'object' && dtsOptions && dtsOptions.displayErrorInTerminal === false) {
410
- return;
411
- }
412
- console.error(error);
413
- };
414
- function pluginDts(options) {
415
- if (options.dts === false) {
416
- return [];
417
- }
418
- const dtsModuleFederationConfig = buildDtsModuleFederationConfig(options);
419
- let resolvedConfig;
420
- let devWorker;
421
- let normalizedDevOptions;
422
- let hasGeneratedBundle = false;
423
- const devPlugin = {
424
- name: 'module-federation-dts-dev',
425
- apply: 'serve',
426
- config(config) {
427
- normalizedDevOptions = normalizeDevOptions(options.dev);
428
- if (!normalizedDevOptions) {
429
- return;
430
- }
431
- if (normalizedDevOptions.disableDynamicRemoteTypeHints) {
432
- return;
433
- }
434
- ensureRuntimePlugin(options, DYNAMIC_HINTS_PLUGIN);
435
- const define = config.define ? _extends({}, config.define) : {};
436
- if (!('FEDERATION_IPV4' in define)) {
437
- define.FEDERATION_IPV4 = JSON.stringify(getIPv4());
438
- }
439
- config.define = define;
440
- },
441
- configResolved(config) {
442
- resolvedConfig = config;
443
- },
444
- configureServer(server) {
445
- if (!normalizedDevOptions || !resolvedConfig) {
446
- return;
447
- }
448
- const devOptions = normalizedDevOptions;
449
- if (devOptions.disableDynamicRemoteTypeHints && devOptions.disableHotTypesReload && devOptions.disableLiveReload) {
450
- return;
451
- }
452
- if (!options.name) {
453
- throw new Error('name is required if you want to enable dev server!');
454
- }
455
- const outputDir = resolveOutputDir(resolvedConfig);
456
- const normalizedDtsOptions = normalizeDevDtsOptions(options.dts, resolvedConfig.root);
457
- if (typeof normalizedDtsOptions !== 'object') {
458
- return;
459
- }
460
- const normalizedGenerateTypes = normalizeOptions(Boolean(normalizedDtsOptions), {
461
- compileInChildProcess: true
462
- }, 'mfOptions.dts.generateTypes')(normalizedDtsOptions.generateTypes);
463
- const remote = normalizedGenerateTypes === false ? undefined : _extends({
464
- implementation: normalizedDtsOptions.implementation,
465
- context: resolvedConfig.root,
466
- outputDir,
467
- moduleFederationConfig: _extends({}, dtsModuleFederationConfig),
468
- hostRemoteTypesFolder: normalizedGenerateTypes.typesFolder || '@mf-types'
469
- }, normalizedGenerateTypes, {
470
- typesFolder: '.dev-server'
471
- });
472
- if (remote && !remote.tsConfigPath && typeof normalizedDtsOptions === 'object' && normalizedDtsOptions.tsConfigPath) {
473
- remote.tsConfigPath = normalizedDtsOptions.tsConfigPath;
474
- }
475
- const normalizedConsumeTypes = normalizeOptions(Boolean(normalizedDtsOptions), {
476
- consumeAPITypes: true
477
- }, 'mfOptions.dts.consumeTypes')(normalizedDtsOptions.consumeTypes);
478
- const host = normalizedConsumeTypes === false ? undefined : _extends({
479
- implementation: normalizedDtsOptions.implementation,
480
- context: resolvedConfig.root,
481
- moduleFederationConfig: dtsModuleFederationConfig,
482
- typesFolder: normalizedConsumeTypes.typesFolder || '@mf-types',
483
- abortOnError: false
484
- }, normalizedConsumeTypes);
485
- const extraOptions = normalizedDtsOptions.extraOptions || {};
486
- if (!remote && !host && devOptions.disableLiveReload) {
487
- return;
488
- }
489
- const startDevWorker = async () => {
490
- var _server$httpServer;
491
- let remoteTypeUrls;
492
- if (host) {
493
- remoteTypeUrls = await new Promise(resolve => {
494
- consumeTypesAPI({
495
- host,
496
- extraOptions,
497
- displayErrorInTerminal: normalizedDtsOptions.displayErrorInTerminal
498
- }, resolve);
499
- });
500
- }
501
- devWorker = new DevWorker({
502
- name: options.name,
503
- remote,
504
- host: host ? _extends({}, host, {
505
- remoteTypeUrls
506
- }) : undefined,
507
- extraOptions,
508
- disableLiveReload: devOptions.disableLiveReload,
509
- disableHotTypesReload: devOptions.disableHotTypesReload
510
- });
511
- const update = () => {
512
- var _devWorker;
513
- return (_devWorker = devWorker) == null ? void 0 : _devWorker.update();
514
- };
515
- server.watcher.on('change', update);
516
- server.watcher.on('add', update);
517
- server.watcher.on('unlink', update);
518
- (_server$httpServer = server.httpServer) == null || _server$httpServer.once('close', () => {
519
- var _devWorker2;
520
- (_devWorker2 = devWorker) == null || _devWorker2.exit();
521
- server.watcher.off('change', update);
522
- server.watcher.off('add', update);
523
- server.watcher.off('unlink', update);
524
- });
525
- };
526
- startDevWorker().catch(error => {
527
- logDtsError(error, normalizedDtsOptions);
528
- });
529
- }
530
- };
531
- const buildPlugin = {
532
- name: 'module-federation-dts-build',
533
- apply: 'build',
534
- configResolved(config) {
535
- resolvedConfig = config;
536
- },
537
- async generateBundle() {
538
- var _consumeOptions;
539
- if (hasGeneratedBundle) {
540
- return;
541
- }
542
- hasGeneratedBundle = true;
543
- if (!resolvedConfig) {
544
- return;
545
- }
546
- let normalizedDtsOptions;
547
- try {
548
- normalizedDtsOptions = normalizeDtsOptions(dtsModuleFederationConfig, resolvedConfig.root);
549
- } catch (error) {
550
- logDtsError(error, options.dts);
551
- return;
552
- }
553
- if (typeof normalizedDtsOptions !== 'object') {
554
- return;
555
- }
556
- const context = resolvedConfig.root;
557
- const outputDir = resolveOutputDir(resolvedConfig);
558
- let consumeOptions;
559
- try {
560
- consumeOptions = normalizeConsumeTypesOptions({
561
- context,
562
- dtsOptions: normalizedDtsOptions,
563
- pluginOptions: dtsModuleFederationConfig
564
- });
565
- } catch (error) {
566
- logDtsError(error, normalizedDtsOptions);
567
- return;
568
- }
569
- if ((_consumeOptions = consumeOptions) != null && (_consumeOptions = _consumeOptions.host) != null && _consumeOptions.typesOnBuild) {
570
- try {
571
- await consumeTypesAPI(consumeOptions);
572
- } catch (error) {
573
- logDtsError(error, normalizedDtsOptions);
574
- }
575
- }
576
- let generateOptions;
577
- try {
578
- generateOptions = normalizeGenerateTypesOptions({
579
- context,
580
- outputDir,
581
- dtsOptions: normalizedDtsOptions,
582
- pluginOptions: dtsModuleFederationConfig
583
- });
584
- } catch (error) {
585
- logDtsError(error, normalizedDtsOptions);
586
- return;
587
- }
588
- if (!generateOptions) {
589
- return;
590
- }
591
- try {
592
- await generateTypesAPI({
593
- dtsManagerOptions: generateOptions
594
- });
595
- } catch (error) {
596
- logDtsError(error, normalizedDtsOptions);
597
- }
598
- }
599
- };
600
- return [devPlugin, buildPlugin];
601
- }
602
-
603
- function normalizeExposesItem(key, item) {
604
- let importPath = '';
605
- if (typeof item === 'string') {
606
- importPath = item;
607
- }
608
- if (typeof item === 'object') {
609
- importPath = item.import;
610
- }
611
- return {
612
- import: importPath
613
- };
614
- }
615
- function normalizeExposes(exposes) {
616
- if (!exposes) return {};
617
- const res = {};
618
- Object.keys(exposes).forEach(key => {
619
- res[key] = normalizeExposesItem(key, exposes[key]);
620
- });
621
- return res;
622
- }
623
- function normalizeRemotes(remotes) {
624
- if (!remotes) return {};
625
- const result = {};
626
- if (typeof remotes === 'object') {
627
- Object.keys(remotes).forEach(key => {
628
- result[key] = normalizeRemoteItem(key, remotes[key]);
629
- });
630
- }
631
- return result;
632
- }
633
- function normalizeRemoteItem(key, remote) {
634
- if (typeof remote === 'string') {
635
- const [entryGlobalName] = remote.split('@');
636
- const entry = remote.replace(entryGlobalName + '@', '');
637
- return {
638
- type: 'var',
639
- name: key,
640
- entry,
641
- entryGlobalName,
642
- shareScope: 'default'
643
- };
644
- }
645
- return Object.assign({
646
- type: 'var',
647
- name: key,
648
- shareScope: 'default',
649
- entryGlobalName: key
650
- }, remote);
651
- }
652
- function removePathFromNpmPackage(packageString) {
653
- // 匹配npm包名的正则表达式,忽略路径部分
654
- const regex = /^(?:@[^/]+\/)?[^/]+/;
655
- // 使用正则表达式匹配并提取包名
656
- const match = packageString.match(regex);
657
- // 返回匹配到的包名,如果没有匹配到则返回原字符串
658
- return match ? match[0] : packageString;
659
- }
660
- /**
661
- * Tries to find the package.json's version of a shared package
662
- * if `package.json` is not declared in `exports`
663
- * @param {string} sharedName
664
- * @returns {string | undefined}
665
- */
666
- function searchPackageVersion(sharedName) {
667
- try {
668
- const sharedPath = require.resolve(sharedName);
669
- let potentialPackageJsonDir = path.dirname(sharedPath);
670
- const rootDir = path.parse(potentialPackageJsonDir).root;
671
- while (path.parse(potentialPackageJsonDir).base !== 'node_modules' && potentialPackageJsonDir !== rootDir) {
672
- const potentialPackageJsonPath = path.join(potentialPackageJsonDir, 'package.json');
673
- if (fs.existsSync(potentialPackageJsonPath)) {
674
- const potentialPackageJson = require(potentialPackageJsonPath);
675
- if (typeof potentialPackageJson == 'object' && potentialPackageJson !== null && typeof potentialPackageJson.version === 'string' && potentialPackageJson.name === sharedName) {
676
- return potentialPackageJson.version;
677
- }
678
- }
679
- potentialPackageJsonDir = path.dirname(potentialPackageJsonDir);
680
- }
681
- } catch (_) {}
682
- return undefined;
683
- }
684
- function normalizeShareItem(key, shareItem) {
685
- let version;
686
- try {
687
- try {
688
- version = require(path.join(removePathFromNpmPackage(key), 'package.json')).version;
689
- } catch (e1) {
690
- try {
691
- const localPath = path.join(process.cwd(), 'node_modules', removePathFromNpmPackage(key), 'package.json');
692
- version = require(localPath).version;
693
- } catch (e2) {
694
- version = searchPackageVersion(key);
695
- if (!version) console.error(e1);
696
- }
697
- }
698
- } catch (e) {
699
- console.error(`Unexpected error resolving version for ${key}:`, e);
700
- }
701
- if (typeof shareItem === 'string') {
702
- return {
703
- name: shareItem,
704
- version,
705
- scope: 'default',
706
- from: '',
707
- shareConfig: {
708
- import: undefined,
709
- singleton: false,
710
- requiredVersion: version ? `^${version}` : '*'
711
- }
712
- };
713
- }
714
- return {
715
- name: key,
716
- from: '',
717
- version: shareItem.version || version,
718
- scope: shareItem.shareScope || 'default',
719
- shareConfig: {
720
- import: typeof shareItem === 'object' ? shareItem.import : undefined,
721
- singleton: shareItem.singleton || false,
722
- requiredVersion: shareItem.requiredVersion || (version ? `^${version}` : '*'),
723
- strictVersion: !!shareItem.strictVersion
724
- }
725
- };
726
- }
727
- function normalizeShared(shared) {
728
- if (!shared) return {};
729
- const result = {};
730
- if (Array.isArray(shared)) {
731
- shared.forEach(key => {
732
- result[key] = normalizeShareItem(key, key);
733
- });
734
- return result;
735
- }
736
- if (typeof shared === 'object') {
737
- Object.keys(shared).forEach(key => {
738
- result[key] = normalizeShareItem(key, shared[key]);
739
- });
740
- }
741
- return result;
742
- }
743
- function normalizeLibrary(library) {
744
- if (!library) return undefined;
745
- return library;
746
- }
747
- function normalizeManifest(manifest = false) {
748
- if (typeof manifest === 'boolean') {
749
- return manifest;
750
- }
751
- return Object.assign({
752
- filePath: '',
753
- disableAssetsAnalyze: false,
754
- fileName: 'mf-manifest.json'
755
- }, manifest);
756
- }
757
- let config;
758
- function getNormalizeModuleFederationOptions() {
759
- return config;
760
- }
761
- function getNormalizeShareItem(key) {
762
- const options = getNormalizeModuleFederationOptions();
763
- const shareItem = options.shared[key] || options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + '/'];
764
- return shareItem;
765
- }
766
- function normalizeModuleFederationOptions(options) {
767
- if (options.virtualModuleDir && options.virtualModuleDir.includes('/')) {
768
- throw new Error(`Invalid virtualModuleDir: "${options.virtualModuleDir}". ` + `The virtualModuleDir option cannot contain slashes (/). ` + `Please use a single directory name like '__mf__virtual__your_app_name'.`);
769
- }
770
- return config = {
771
- exposes: normalizeExposes(options.exposes),
772
- filename: options.filename || 'remoteEntry-[hash]',
773
- library: normalizeLibrary(options.library),
774
- name: options.name,
775
- // remoteType: options.remoteType,
776
- remotes: normalizeRemotes(options.remotes),
777
- runtime: options.runtime,
778
- shareScope: options.shareScope || 'default',
779
- shared: normalizeShared(options.shared),
780
- runtimePlugins: options.runtimePlugins || [],
781
- implementation: options.implementation || require.resolve('@module-federation/runtime'),
782
- manifest: normalizeManifest(options.manifest),
783
- dev: options.dev,
784
- dts: options.dts,
785
- getPublicPath: options.getPublicPath,
786
- publicPath: options.publicPath,
787
- shareStrategy: options.shareStrategy || 'version-first',
788
- ignoreOrigin: options.ignoreOrigin || false,
789
- virtualModuleDir: options.virtualModuleDir || '__mf__virtual',
790
- hostInitInjectLocation: options.hostInitInjectLocation || 'html',
791
- bundleAllCSS: options.bundleAllCSS || false,
792
- moduleParseTimeout: options.moduleParseTimeout || 10
793
- };
794
- }
795
-
796
- /**
797
- * Escaping rules:
798
- * Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
799
- * @ => 1
800
- * / => 2
801
- * - => 3
802
- * . => 4
803
- */
804
- /**
805
- * Encodes a package name into a valid file name.
806
- * @param {string} name - The package name, e.g., "@scope/xx-xx.xx".
807
- * @returns {string} - The encoded file name.
808
- */
809
- function packageNameEncode(name) {
810
- if (typeof name !== 'string') throw new Error('A string package name is required');
811
- return name.replace(/@/g, '_mf_0_').replace(/\//g, '_mf_1_').replace(/-/g, '_mf_2_').replace(/\./g, '_mf_3_');
812
- }
813
- /**
814
- * Decodes an encoded file name back to the original package name.
815
- * @param {string} encoded - The encoded file name, e.g., "_mf_0_scope_mf_1_xx_mf_2_xx_mf_3_xx".
816
- * @returns {string} - The decoded package name.
817
- */
818
- function packageNameDecode(encoded) {
819
- if (typeof encoded !== 'string') throw new Error('A string encoded file name is required');
820
- return encoded.replace(/_mf_0_/g, '@').replace(/_mf_1_/g, '/').replace(/_mf_2_/g, '-').replace(/_mf_3_/g, '.');
821
- }
822
-
823
- /**
824
- * https://github.com/module-federation/vite/issues/68
825
- */
826
- function getLocalSharedImportMapPath_temp() {
827
- const {
828
- name
829
- } = getNormalizeModuleFederationOptions();
830
- return path__default.resolve('.__mf__temp', packageNameEncode(name), 'localSharedImportMap');
831
- }
832
- function writeLocalSharedImportMap_temp(content) {
833
- const localSharedImportMapId = getLocalSharedImportMapPath_temp();
834
- createFile(localSharedImportMapId + '.js', '\n// Windows temporarily needs this file, https://github.com/module-federation/vite/issues/68\n' + content);
835
- }
836
- function createFile(filePath, content) {
837
- const dir = path__default.dirname(filePath);
838
- mkdirSync(dir, {
839
- recursive: true
840
- });
841
- writeFileSync(filePath, content);
842
- }
843
-
844
- /**
845
- * Serializes a JavaScript object into a string of source code that can be evaluated.
846
- * This function is used to create runtime plugin options without relying solely on JSON.stringify,
847
- * allowing support for non-JSON types like RegExp, Date, Map, Set, and Functions.
848
- * It also safely handles circular references.
849
- *
850
- * @param {Record<string, unknown>} options - The options object to serialize.
851
- * @returns {string} The resulting JavaScript source code string.
852
- */
853
- function serializeRuntimeOptions(options) {
854
- // Use a WeakSet to track objects already encountered, which helps in detecting circular references.
855
- const seenObjects = new WeakSet();
856
- /**
857
- * Recursive inner function to serialize any value into a source code string.
858
- */
859
- function valueToCode(val) {
860
- // 1. Handle primitive values
861
- if (val === null) return 'null';
862
- const type = typeof val;
863
- if (type === 'string') return JSON.stringify(val);
864
- if (type === 'number' || type === 'boolean') return String(val);
865
- if (type === 'undefined') return 'undefined';
866
- // Handle Symbol
867
- if (type === 'symbol') {
868
- var _val$description;
869
- const desc = (_val$description = val.description) != null ? _val$description : '';
870
- return `Symbol(${JSON.stringify(desc)})`;
871
- }
872
- // Handle Function (returns the function's source code)
873
- if (type === 'function') return val.toString();
874
- // 2. Handle special built-in objects
875
- if (val instanceof Date) return `new Date(${JSON.stringify(val.toISOString())})`;
876
- if (val instanceof RegExp) {
877
- return `new RegExp(${JSON.stringify(val.source)}, ${JSON.stringify(val.flags)})`;
878
- }
879
- // 3. Check for circular references and mark object as seen
880
- // This applies to objects, arrays, maps, and sets.
881
- if (type === 'object') {
882
- if (seenObjects.has(val)) {
883
- // This object has been seen previously in the recursion path
884
- return `"__circular__"`;
885
- }
886
- seenObjects.add(val);
887
- }
888
- // 4. Handle Array, Map, Set
889
- if (Array.isArray(val)) {
890
- // Recursively serialize each element
891
- return `[${val.map(valueToCode).join(', ')}]`;
892
- }
893
- if (val instanceof Map) {
894
- // Serialize Map entries into an array of [key, value] pairs
895
- const entries = Array.from(val.entries()).map(([k, v]) => `[${valueToCode(k)}, ${valueToCode(v)}]`);
896
- return `new Map([${entries.join(', ')}])`;
897
- }
898
- if (val instanceof Set) {
899
- // Serialize Set values into an array
900
- const items = Array.from(val.values()).map(valueToCode);
901
- return `new Set([${items.join(', ')}])`;
902
- }
903
- // 5. Handle plain objects (the default object type)
904
- if (type === 'object') {
905
- const properties = [];
906
- // Iterate over the object's own enumerable properties
907
- for (const key in val) {
908
- if (Object.prototype.hasOwnProperty.call(val, key)) {
909
- // Wrap the key in JSON.stringify to handle non-identifier keys
910
- properties.push(`${JSON.stringify(key)}: ${valueToCode(val[key])}`);
911
- }
912
- }
913
- return `{${properties.join(', ')}}`;
914
- }
915
- // 6. Fallback case (e.g., BigInt, other object types)
916
- // Coerce to string and then JSON.stringify that string for safety
917
- return JSON.stringify(String(val));
918
- }
919
- // Start serialization for the top-level object
920
- const topLevelProps = [];
921
- // Iterate over the properties of the root 'options' object
922
- for (const key in options) {
923
- if (Object.prototype.hasOwnProperty.call(options, key)) {
924
- topLevelProps.push(`${JSON.stringify(key)}: ${valueToCode(options[key])}`);
925
- }
926
- }
927
- return `{${topLevelProps.join(', ')}}`;
928
- }
929
-
930
- // Cache root path
931
- let rootDir;
932
- function findNodeModulesDir(root = process.cwd()) {
933
- let currentDir = root;
934
- while (currentDir !== parse(currentDir).root) {
935
- const nodeModulesPath = join(currentDir, 'node_modules');
936
- if (existsSync(nodeModulesPath)) {
937
- return nodeModulesPath;
938
- }
939
- currentDir = dirname(currentDir);
940
- }
941
- return '';
942
- }
943
- // Cache nodeModulesDir result to avoid repeated calculations
944
- let cachedNodeModulesDir;
945
- function getNodeModulesDir() {
946
- if (!cachedNodeModulesDir) {
947
- cachedNodeModulesDir = findNodeModulesDir(rootDir);
948
- }
949
- return cachedNodeModulesDir;
950
- }
951
- function getSuffix(name) {
952
- const base = basename(name);
953
- const dotIndex = base.lastIndexOf('.');
954
- if (dotIndex > 0 && dotIndex < base.length - 1) {
955
- return base.slice(dotIndex);
956
- }
957
- return '.js';
958
- }
959
- const patternMap = {};
960
- const cacheMap = {};
961
- /**
962
- * Physically generate files as virtual modules under node_modules/__mf__virtual/*
963
- */
964
- function assertModuleFound(tag, str = '') {
965
- const module = VirtualModule.findModule(tag, str);
966
- if (!module) {
967
- throw new Error(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
968
- }
969
- return module;
970
- }
971
- class VirtualModule {
972
- /**
973
- * Set the root path for finding node_modules
974
- * @param root - Root path
975
- */
976
- static setRoot(root) {
977
- rootDir = root;
978
- // Reset cache to ensure using the new root path
979
- cachedNodeModulesDir = undefined;
980
- }
981
- /**
982
- * Ensure virtual package directory exists
983
- */
984
- static ensureVirtualPackageExists() {
985
- const nodeModulesDir = getNodeModulesDir();
986
- const {
987
- virtualModuleDir
988
- } = getNormalizeModuleFederationOptions();
989
- const virtualPackagePath = resolve(nodeModulesDir, virtualModuleDir);
990
- if (!existsSync(virtualPackagePath)) {
991
- mkdirSync(virtualPackagePath);
992
- writeFileSync(resolve(virtualPackagePath, 'empty.js'), '');
993
- writeFileSync(resolve(virtualPackagePath, 'package.json'), JSON.stringify({
994
- name: virtualModuleDir,
995
- main: 'empty.js'
996
- }));
997
- }
998
- }
999
- static findModule(tag, str = '') {
1000
- if (!patternMap[tag]) patternMap[tag] = new RegExp(`(.*${packageNameEncode(tag)}(.+?)${packageNameEncode(tag)}.*)`);
1001
- const moduleName = (str.match(patternMap[tag]) || [])[2];
1002
- if (moduleName) return cacheMap[tag][packageNameDecode(moduleName)];
1003
- return undefined;
1004
- }
1005
- constructor(name, tag = '__mf_v__', suffix = '') {
1006
- this.name = void 0;
1007
- this.tag = void 0;
1008
- this.suffix = void 0;
1009
- this.inited = false;
1010
- this.name = name;
1011
- this.tag = tag;
1012
- this.suffix = suffix || getSuffix(name);
1013
- if (!cacheMap[this.tag]) cacheMap[this.tag] = {};
1014
- cacheMap[this.tag][this.name] = this;
1015
- }
1016
- getPath() {
1017
- return resolve(getNodeModulesDir(), this.getImportId());
1018
- }
1019
- getImportId() {
1020
- const {
1021
- name: mfName,
1022
- virtualModuleDir
1023
- } = getNormalizeModuleFederationOptions();
1024
- return `${virtualModuleDir}/${packageNameEncode(`${mfName}${this.tag}${this.name}${this.tag}`)}${this.suffix}`;
1025
- }
1026
- writeSync(code, force) {
1027
- if (!force && this.inited) return;
1028
- if (!this.inited) {
1029
- this.inited = true;
1030
- }
1031
- writeFileSync(this.getPath(), code);
1032
- }
1033
- write(code) {
1034
- writeFile(this.getPath(), code, function () {});
1035
- }
1036
- }
1037
-
1038
- const VIRTUAL_EXPOSES = 'virtual:mf-exposes';
1039
- function generateExposes() {
1040
- const options = getNormalizeModuleFederationOptions();
1041
- return `
1042
- export default {
1043
- ${Object.keys(options.exposes).map(key => {
1044
- return `
1045
- ${JSON.stringify(key)}: async () => {
1046
- const importModule = await import(${JSON.stringify(options.exposes[key].import)})
1047
- const exportModule = {}
1048
- Object.assign(exportModule, importModule)
1049
- Object.defineProperty(exportModule, "__esModule", {
1050
- value: true,
1051
- enumerable: false
1052
- })
1053
- return exportModule
1054
- }
1055
- `;
1056
- }).join(',')}
1057
- }
1058
- `;
1059
- }
1060
-
1061
- const virtualRuntimeInitStatus = new VirtualModule('runtimeInit');
1062
- function writeRuntimeInitStatus() {
1063
- // Use globalThis singleton to ensure only one initPromise exists
1064
- const globalKey = `__mf_init__${virtualRuntimeInitStatus.getImportId()}__`;
1065
- virtualRuntimeInitStatus.writeSync(`
1066
- const globalKey = ${JSON.stringify(globalKey)}
1067
- if (!globalThis[globalKey]) {
1068
- let initResolve, initReject
1069
- const initPromise = new Promise((re, rj) => {
1070
- initResolve = re
1071
- initReject = rj
1072
- })
1073
- globalThis[globalKey] = {
1074
- initPromise,
1075
- initResolve,
1076
- initReject
1077
- }
1078
- }
1079
- module.exports = globalThis[globalKey]
1080
- `);
1081
- }
1082
-
1083
- const cacheRemoteMap = {};
1084
- const LOAD_REMOTE_TAG = '__loadRemote__';
1085
- function getRemoteVirtualModule(remote, command) {
1086
- if (!cacheRemoteMap[remote]) {
1087
- cacheRemoteMap[remote] = new VirtualModule(remote, LOAD_REMOTE_TAG, '.js');
1088
- cacheRemoteMap[remote].writeSync(generateRemotes(remote, command));
1089
- }
1090
- const virtual = cacheRemoteMap[remote];
1091
- return virtual;
1092
- }
1093
- const usedRemotesMap = {
1094
- // remote1: {remote1/App, remote1, remote1/Button}
1095
- };
1096
- function addUsedRemote(remoteKey, remoteModule) {
1097
- if (!usedRemotesMap[remoteKey]) usedRemotesMap[remoteKey] = new Set();
1098
- usedRemotesMap[remoteKey].add(remoteModule);
1099
- }
1100
- function getUsedRemotesMap() {
1101
- return usedRemotesMap;
1102
- }
1103
- function generateRemotes(id, command) {
1104
- return `
1105
- const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")
1106
- const res = initPromise.then(runtime => runtime.loadRemote(${JSON.stringify(id)}))
1107
- const exportModule = ${command !== 'build' ? '/*mf top-level-await placeholder replacement mf*/' : 'await '}initPromise.then(_ => res)
1108
- module.exports = exportModule
1109
- `;
1110
- }
1111
-
1112
- /**
1113
- * Even the resolveId hook cannot interfere with vite pre-build,
1114
- * and adding query parameter virtual modules will also fail.
1115
- * You can only proxy to the real file through alias
1116
- */
1117
- // *** __prebuild__
1118
- const preBuildCacheMap = {};
1119
- const PREBUILD_TAG = '__prebuild__';
1120
- function writePreBuildLibPath(pkg) {
1121
- if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
1122
- preBuildCacheMap[pkg].writeSync('');
1123
- }
1124
- function getPreBuildLibImportId(pkg) {
1125
- if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
1126
- const importId = preBuildCacheMap[pkg].getImportId();
1127
- return importId;
1128
- }
1129
- // *** __loadShare__
1130
- const LOAD_SHARE_TAG = '__loadShare__';
1131
- const loadShareCacheMap = {};
1132
- function getLoadShareModulePath(pkg) {
1133
- if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, '.js');
1134
- const filepath = loadShareCacheMap[pkg].getPath();
1135
- return filepath;
1136
- }
1137
- function writeLoadShareModule(pkg, shareItem, command) {
1138
- loadShareCacheMap[pkg].writeSync(`
1139
- ;() => import(${JSON.stringify(getPreBuildLibImportId(pkg))}).catch(() => {});
1140
- // dev uses dynamic import to separate chunks
1141
- ${command !== 'build' ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ''}
1142
- const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")
1143
- const res = initPromise.then(runtime => runtime.loadShare(${JSON.stringify(pkg)}, {
1144
- customShareInfo: {shareConfig:{
1145
- singleton: ${shareItem.shareConfig.singleton},
1146
- strictVersion: ${shareItem.shareConfig.strictVersion},
1147
- requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
1148
- }}
1149
- }))
1150
- const exportModule = ${command !== 'build' ? '/*mf top-level-await placeholder replacement mf*/' : 'await '}res.then(factory => factory())
1151
- module.exports = exportModule
1152
- `);
1153
- }
1154
-
1155
- let usedShares = new Set();
1156
- function getUsedShares() {
1157
- return usedShares;
1158
- }
1159
- function addUsedShares(pkg) {
1160
- usedShares.add(pkg);
1161
- }
1162
- // *** Expose locally provided shared modules here
1163
- new VirtualModule('localSharedImportMap');
1164
- function getLocalSharedImportMapPath() {
1165
- return getLocalSharedImportMapPath_temp();
1166
- // return localSharedImportMapModule.getPath()
1167
- }
1168
- let prevSharedCount;
1169
- function writeLocalSharedImportMap() {
1170
- const sharedCount = getUsedShares().size;
1171
- if (prevSharedCount !== sharedCount) {
1172
- prevSharedCount = sharedCount;
1173
- writeLocalSharedImportMap_temp(generateLocalSharedImportMap());
1174
- // localSharedImportMapModule.writeSync(generateLocalSharedImportMap(), true)
1175
- }
1176
- }
1177
- function generateLocalSharedImportMap() {
1178
- const options = getNormalizeModuleFederationOptions();
1179
- return `
1180
- import {loadShare} from "@module-federation/runtime";
1181
- const importMap = {
1182
- ${Array.from(getUsedShares()).sort().map(pkg => {
1183
- const shareItem = getNormalizeShareItem(pkg);
1184
- return `
1185
- ${JSON.stringify(pkg)}: async () => {
1186
- ${(shareItem == null ? void 0 : shareItem.shareConfig.import) === false ? `throw new Error(\`Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` : `let pkg = await import("${getPreBuildLibImportId(pkg)}");
1187
- return pkg;`}
1188
- }
1189
- `;
1190
- }).join(',')}
1191
- }
1192
- const usedShared = {
1193
- ${Array.from(getUsedShares()).sort().map(key => {
1194
- const shareItem = getNormalizeShareItem(key);
1195
- if (!shareItem) return null;
1196
- return `
1197
- ${JSON.stringify(key)}: {
1198
- name: ${JSON.stringify(key)},
1199
- version: ${JSON.stringify(shareItem.version)},
1200
- scope: [${JSON.stringify(shareItem.scope)}],
1201
- loaded: false,
1202
- from: ${JSON.stringify(options.name)},
1203
- async get () {
1204
- if (${shareItem.shareConfig.import === false}) {
1205
- throw new Error(\`Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
1206
- }
1207
- usedShared[${JSON.stringify(key)}].loaded = true
1208
- const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
1209
- const res = await pkgDynamicImport()
1210
- const exportModule = {...res}
1211
- // All npm packages pre-built by vite will be converted to esm
1212
- Object.defineProperty(exportModule, "__esModule", {
1213
- value: true,
1214
- enumerable: false
1215
- })
1216
- return function () {
1217
- return exportModule
1218
- }
1219
- },
1220
- shareConfig: {
1221
- singleton: ${shareItem.shareConfig.singleton},
1222
- requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)},
1223
- ${shareItem.shareConfig.import === false ? 'import: false,' : ''}
1224
- }
1225
- }
1226
- `;
1227
- }).filter(x => x !== null).join(',')}
1228
- }
1229
- const usedRemotes = [${Object.keys(getUsedRemotesMap()).map(key => {
1230
- var _JSON$stringify;
1231
- const remote = options.remotes[key];
1232
- if (!remote) return null;
1233
- return `
1234
- {
1235
- entryGlobalName: ${JSON.stringify(remote.entryGlobalName)},
1236
- name: ${JSON.stringify(remote.name)},
1237
- type: ${JSON.stringify(remote.type)},
1238
- entry: ${JSON.stringify(remote.entry)},
1239
- shareScope: ${(_JSON$stringify = JSON.stringify(remote.shareScope)) != null ? _JSON$stringify : 'default'},
1240
- }
1241
- `;
1242
- }).filter(x => x !== null).join(',')}
1243
- ]
1244
- export {
1245
- usedShared,
1246
- usedRemotes
1247
- }
1248
- `;
1249
- }
1250
- const REMOTE_ENTRY_ID = 'virtual:mf-REMOTE_ENTRY_ID';
1251
- function generateRemoteEntry(options) {
1252
- const pluginImportNames = options.runtimePlugins.map((p, i) => {
1253
- if (typeof p === 'string') {
1254
- return [`$runtimePlugin_${i}`, `import $runtimePlugin_${i} from "${p}";`, `undefined`];
1255
- } else {
1256
- return [`$runtimePlugin_${i}`, `import $runtimePlugin_${i} from "${p[0]}";`, serializeRuntimeOptions(p[1])];
1257
- }
1258
- });
1259
- return `
1260
- import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
1261
- ${pluginImportNames.map(item => item[1]).join('\n')}
1262
- import exposesMap from "${VIRTUAL_EXPOSES}"
1263
- import {usedShared, usedRemotes} from "${getLocalSharedImportMapPath()}"
1264
- import {
1265
- initResolve
1266
- } from "${virtualRuntimeInitStatus.getImportId()}"
1267
- const initTokens = {}
1268
- const shareScopeName = ${JSON.stringify(options.shareScope)}
1269
- const mfName = ${JSON.stringify(options.name)}
1270
- async function init(shared = {}, initScope = []) {
1271
- const initRes = runtimeInit({
1272
- name: mfName,
1273
- remotes: usedRemotes,
1274
- shared: usedShared,
1275
- plugins: [${pluginImportNames.map(item => `${item[0]}(${item[2]})`).join(', ')}],
1276
- ${options.shareStrategy ? `shareStrategy: '${options.shareStrategy}'` : ''}
1277
- });
1278
- // handling circular init calls
1279
- var initToken = initTokens[shareScopeName];
1280
- if (!initToken)
1281
- initToken = initTokens[shareScopeName] = { from: mfName };
1282
- if (initScope.indexOf(initToken) >= 0) return;
1283
- initScope.push(initToken);
1284
- initRes.initShareScopeMap('${options.shareScope}', shared);
1285
- try {
1286
- await Promise.all(await initRes.initializeSharing('${options.shareScope}', {
1287
- strategy: '${options.shareStrategy}',
1288
- from: "build",
1289
- initScope
1290
- }));
1291
- } catch (e) {
1292
- console.error(e)
1293
- }
1294
- initResolve(initRes)
1295
- return initRes
1296
- }
1297
-
1298
- function getExposes(moduleName) {
1299
- if (!(moduleName in exposesMap)) throw new Error(\`Module \${moduleName} does not exist in container.\`)
1300
- return (exposesMap[moduleName])().then(res => () => res)
1301
- }
1302
- export {
1303
- init,
1304
- getExposes as get
1305
- }
1306
- `;
1307
- }
1308
- /**
1309
- * Inject entry file, automatically init when used as host,
1310
- * and will not inject remoteEntry
1311
- */
1312
- const HOST_AUTO_INIT_TAG = '__H_A_I__';
1313
- const hostAutoInitModule = new VirtualModule('hostAutoInit', HOST_AUTO_INIT_TAG);
1314
- function writeHostAutoInit() {
1315
- hostAutoInitModule.writeSync(`
1316
- const remoteEntryPromise = import("${REMOTE_ENTRY_ID}")
1317
- // __tla only serves as a hack for vite-plugin-top-level-await.
1318
- Promise.resolve(remoteEntryPromise)
1319
- .then(remoteEntry => {
1320
- return Promise.resolve(remoteEntry.__tla)
1321
- .then(remoteEntry.init).catch(remoteEntry.init)
1322
- })
1323
- `);
1324
- }
1325
- function getHostAutoInitImportId() {
1326
- return hostAutoInitModule.getImportId();
1327
- }
1328
- function getHostAutoInitPath() {
1329
- return hostAutoInitModule.getPath();
1330
- }
1331
-
1332
- function initVirtualModules() {
1333
- writeLocalSharedImportMap();
1334
- writeHostAutoInit();
1335
- writeRuntimeInitStatus();
1336
- }
1337
-
1338
- const ASSET_TYPES = ['js', 'css'];
1339
- const LOAD_TIMINGS = ['sync', 'async'];
1340
- const JS_EXTENSIONS = ['.ts', '.tsx', '.jsx', '.mjs', '.cjs'];
1341
- /**
1342
- * Creates an empty asset map structure for tracking JS and CSS assets
1343
- * @returns Initialized asset map with sync/async arrays for JS and CSS
1344
- */
1345
- const createEmptyAssetMap = () => ({
1346
- js: {
1347
- sync: [],
1348
- async: []
1349
- },
1350
- css: {
1351
- sync: [],
1352
- async: []
1353
- }
1354
- });
1355
- /**
1356
- * Tracks an asset in the preload map with deduplication
1357
- * @param map - The preload map to update
1358
- * @param key - The module key to track under
1359
- * @param fileName - The asset filename to track
1360
- * @param isAsync - Whether the asset is loaded async
1361
- * @param type - The asset type ('js' or 'css')
1362
- */
1363
- const trackAsset = (map, key, fileName, isAsync, type) => {
1364
- if (!map[key]) {
1365
- map[key] = createEmptyAssetMap();
1366
- }
1367
- const target = isAsync ? map[key][type].async : map[key][type].sync;
1368
- if (!target.includes(fileName)) {
1369
- target.push(fileName);
1370
- }
1371
- };
1372
- /**
1373
- * Checks if a file is a CSS file by extension
1374
- * @param fileName - The filename to check
1375
- * @returns True if file has a CSS extension (.css, .scss, .less)
1376
- */
1377
- const isCSSFile = fileName => {
1378
- return fileName.endsWith('.css') || fileName.endsWith('.scss') || fileName.endsWith('.less');
1379
- };
1380
- /**
1381
- * Collects all CSS assets from the bundle
1382
- * @param bundle - The Rollup output bundle
1383
- * @returns Set of CSS asset filenames
1384
- */
1385
- const collectCssAssets = bundle => {
1386
- const cssAssets = new Set();
1387
- for (const [fileName, fileData] of Object.entries(bundle)) {
1388
- if (fileData.type === 'asset' && isCSSFile(fileName)) {
1389
- cssAssets.add(fileName);
1390
- }
1391
- }
1392
- return cssAssets;
1393
- };
1394
- /**
1395
- * Processes module assets and tracks them in the files map
1396
- * @param bundle - The Rollup output bundle
1397
- * @param filesMap - The preload map to populate
1398
- * @param moduleMatcher - Function that matches module paths to keys
1399
- */
1400
- const processModuleAssets = (bundle, filesMap, moduleMatcher) => {
1401
- for (const [fileName, fileData] of Object.entries(bundle)) {
1402
- if (fileData.type !== 'chunk') continue;
1403
- if (!fileData.modules) continue;
1404
- for (const modulePath of Object.keys(fileData.modules)) {
1405
- const matchKey = moduleMatcher(modulePath);
1406
- if (!matchKey) continue;
1407
- // Track main JS chunk
1408
- trackAsset(filesMap, matchKey, fileName, false, 'js');
1409
- // Handle dynamic imports
1410
- if (fileData.dynamicImports) {
1411
- for (const dynamicImport of fileData.dynamicImports) {
1412
- const importData = bundle[dynamicImport];
1413
- if (!importData) continue;
1414
- const isCss = isCSSFile(dynamicImport);
1415
- trackAsset(filesMap, matchKey, dynamicImport, true, isCss ? 'css' : 'js');
1416
- }
1417
- }
1418
- }
1419
- }
1420
- };
1421
- /**
1422
- * Deduplicates assets in the files map
1423
- * @param filesMap - The preload map to deduplicate
1424
- * @returns New deduplicated preload map
1425
- */
1426
- const deduplicateAssets = filesMap => {
1427
- const result = {};
1428
- for (const [key, assetMaps] of Object.entries(filesMap)) {
1429
- result[key] = createEmptyAssetMap();
1430
- for (const type of ASSET_TYPES) {
1431
- for (const timing of LOAD_TIMINGS) {
1432
- result[key][type][timing] = Array.from(new Set(assetMaps[type][timing]));
1433
- }
1434
- }
1435
- }
1436
- return result;
1437
- };
1438
- /**
1439
- * Builds a mapping between module files and their share keys
1440
- * @param shareKeys - Set of share keys to map
1441
- * @param resolveFn - Function to resolve module paths
1442
- * @returns Map of file paths to their corresponding share keys
1443
- */
1444
- const buildFileToShareKeyMap = async (shareKeys, resolveFn) => {
1445
- const fileToShareKey = new Map();
1446
- const resolutions = await Promise.all(Array.from(shareKeys).map(shareKey => resolveFn(getPreBuildLibImportId(shareKey)).then(resolution => {
1447
- var _resolution$id;
1448
- return {
1449
- shareKey,
1450
- file: resolution == null || (_resolution$id = resolution.id) == null ? void 0 : _resolution$id.split('?')[0]
1451
- };
1452
- }).catch(() => null)));
1453
- for (const resolution of resolutions) {
1454
- if (resolution != null && resolution.file) {
1455
- fileToShareKey.set(resolution.file, resolution.shareKey);
1456
- }
1457
- }
1458
- return fileToShareKey;
1459
- };
1460
-
1461
- /**
1462
- * Resolves the public path for remote entries
1463
- * @param options - Module Federation options
1464
- * @param viteBase - Vite's base config value
1465
- * @param originalBase - Original base config before any transformations
1466
- * @returns The resolved public path
1467
- */
1468
- function resolvePublicPath(options, viteBase, originalBase) {
1469
- // Use explicitly set publicPath if provided
1470
- if (options.publicPath) {
1471
- return options.publicPath;
1472
- }
1473
- // Handle empty original base case
1474
- if (originalBase === '') {
1475
- return 'auto';
1476
- }
1477
- // Use viteBase if available, ensuring it ends with a slash
1478
- if (viteBase) {
1479
- return viteBase.replace(/\/?$/, '/');
1480
- }
1481
- // Fallback to auto if no base is specified
1482
- return 'auto';
1483
- }
1484
-
1485
- const Manifest = () => {
1486
- const mfOptions = getNormalizeModuleFederationOptions();
1487
- const {
1488
- name,
1489
- filename,
1490
- getPublicPath,
1491
- manifest: manifestOptions
1492
- } = mfOptions;
1493
- let mfManifestName = '';
1494
- if (manifestOptions === true) {
1495
- mfManifestName = 'mf-manifest.json';
1496
- }
1497
- if (typeof manifestOptions !== 'boolean') {
1498
- mfManifestName = path.join((manifestOptions == null ? void 0 : manifestOptions.filePath) || '', (manifestOptions == null ? void 0 : manifestOptions.fileName) || '');
1499
- }
1500
- let root;
1501
- let remoteEntryFile;
1502
- let publicPath;
1503
- let _command;
1504
- let _originalConfigBase;
1505
- let viteConfig;
1506
- /**
1507
- * Adds global CSS assets to all module exports
1508
- * @param filesMap - The preload map to update
1509
- * @param cssAssets - Set of CSS asset filenames to add
1510
- */
1511
- const addCssAssetsToAllExports = (filesMap, cssAssets) => {
1512
- Object.keys(filesMap).forEach(key => {
1513
- cssAssets.forEach(cssAsset => {
1514
- trackAsset(filesMap, key, cssAsset, false, 'css');
1515
- });
1516
- });
1517
- };
1518
- return [{
1519
- name: 'module-federation-manifest',
1520
- apply: 'serve',
1521
- /**
1522
- * Stores resolved Vite config for later use
1523
- */
1524
- /**
1525
- * Finalizes configuration after all plugins are resolved
1526
- * @param config - Fully resolved Vite config
1527
- */
1528
- configResolved(config) {
1529
- viteConfig = config;
1530
- },
1531
- /**
1532
- * Configures dev server middleware to handle manifest requests
1533
- * @param server - Vite dev server instance
1534
- */
1535
- configureServer(server) {
1536
- server.middlewares.use((req, res, next) => {
1537
- var _req$url;
1538
- if (!mfManifestName) {
1539
- next();
1540
- return;
1541
- }
1542
- if (((_req$url = req.url) == null ? void 0 : _req$url.replace(/\?.*/, '')) === (viteConfig.base + mfManifestName).replace(/^\/?/, '/')) {
1543
- res.setHeader('Content-Type', 'application/json');
1544
- res.setHeader('Access-Control-Allow-Origin', '*');
1545
- res.end(JSON.stringify(_extends({}, generateMFManifest({}), {
1546
- id: name,
1547
- name: name,
1548
- metaData: {
1549
- name: name,
1550
- type: 'app',
1551
- buildInfo: {
1552
- buildVersion: '1.0.0',
1553
- buildName: name
1554
- },
1555
- remoteEntry: {
1556
- name: filename,
1557
- path: '',
1558
- type: 'module'
1559
- },
1560
- ssrRemoteEntry: {
1561
- name: filename,
1562
- path: '',
1563
- type: 'module'
1564
- },
1565
- types: {
1566
- path: '',
1567
- name: ''
1568
- },
1569
- globalName: name,
1570
- pluginVersion: '0.2.5',
1571
- publicPath
1572
- }
1573
- })));
1574
- } else {
1575
- next();
1576
- }
1577
- });
1578
- }
1579
- }, {
1580
- name: 'module-federation-manifest',
1581
- enforce: 'post',
1582
- /**
1583
- * Initial plugin configuration
1584
- * @param config - Vite config object
1585
- * @param command - Current Vite command (serve/build)
1586
- */
1587
- config(config, {
1588
- command
1589
- }) {
1590
- if (!config.build) config.build = {};
1591
- if (!config.build.manifest) {
1592
- config.build.manifest = config.build.manifest || !!manifestOptions;
1593
- }
1594
- _command = command;
1595
- _originalConfigBase = config.base;
1596
- },
1597
- configResolved(config) {
1598
- root = config.root;
1599
- let base = config.base;
1600
- if (_command === 'serve') {
1601
- base = (config.server.origin || '') + config.base;
1602
- }
1603
- publicPath = resolvePublicPath(mfOptions, base, _originalConfigBase);
1604
- },
1605
- /**
1606
- * Generates the module federation manifest file
1607
- * @param options - Rollup output options
1608
- * @param bundle - Generated bundle assets
1609
- */
1610
- async generateBundle(options, bundle) {
1611
- if (!mfManifestName) return;
1612
- let filesMap = {};
1613
- // First pass: Find remoteEntry file
1614
- for (const [_, fileData] of Object.entries(bundle)) {
1615
- if (mfOptions.filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
1616
- remoteEntryFile = fileData.fileName;
1617
- break; // We can break early since we only need to find remoteEntry once
1618
- }
1619
- }
1620
- // Second pass: Collect all CSS assets
1621
- const allCssAssets = mfOptions.bundleAllCSS ? collectCssAssets(bundle) : new Set();
1622
- const exposesModules = Object.keys(mfOptions.exposes).map(item => mfOptions.exposes[item].import);
1623
- // Process exposed modules
1624
- processModuleAssets(bundle, filesMap, modulePath => {
1625
- const absoluteModulePath = path.resolve(root, modulePath);
1626
- return exposesModules.find(exposeModule => {
1627
- const exposePath = path.resolve(root, exposeModule);
1628
- // First try exact path match
1629
- if (absoluteModulePath === exposePath) {
1630
- return true;
1631
- }
1632
- // Then try path match without known extensions
1633
- const getPathWithoutKnownExt = filePath => {
1634
- const ext = path.extname(filePath);
1635
- return JS_EXTENSIONS.includes(ext) ? path.join(path.dirname(filePath), path.basename(filePath, ext)) : filePath;
1636
- };
1637
- const modulePathNoExt = getPathWithoutKnownExt(absoluteModulePath);
1638
- const exposePathNoExt = getPathWithoutKnownExt(exposePath);
1639
- return modulePathNoExt === exposePathNoExt;
1640
- });
1641
- });
1642
- // Process shared modules
1643
- const fileToShareKey = await buildFileToShareKeyMap(getUsedShares(), this.resolve.bind(this));
1644
- processModuleAssets(bundle, filesMap, modulePath => fileToShareKey.get(modulePath));
1645
- // Add all CSS assets to every export if bundleAllCSS is enabled
1646
- if (mfOptions.bundleAllCSS) {
1647
- addCssAssetsToAllExports(filesMap, allCssAssets);
1648
- }
1649
- // Final deduplication of all assets
1650
- filesMap = deduplicateAssets(filesMap);
1651
- this.emitFile({
1652
- type: 'asset',
1653
- fileName: mfManifestName,
1654
- source: JSON.stringify(generateMFManifest(filesMap))
1655
- });
1656
- }
1657
- }];
1658
- /**
1659
- * Generates the final manifest JSON structure
1660
- * @param preloadMap - Map of module assets to include
1661
- * @returns Complete manifest object
1662
- */
1663
- function generateMFManifest(preloadMap) {
1664
- const options = getNormalizeModuleFederationOptions();
1665
- const {
1666
- name
1667
- } = options;
1668
- const remoteEntry = {
1669
- name: remoteEntryFile,
1670
- path: '',
1671
- type: 'module'
1672
- };
1673
- // Process remotes
1674
- const remotes = Array.from(Object.entries(getUsedRemotesMap())).flatMap(([remoteKey, modules]) => Array.from(modules).map(moduleKey => ({
1675
- federationContainerName: options.remotes[remoteKey].entry,
1676
- moduleName: moduleKey.replace(remoteKey, '').replace('/', ''),
1677
- alias: remoteKey,
1678
- entry: '*'
1679
- })));
1680
- // Process shared dependencies
1681
- const shared = Array.from(getUsedShares()).map(shareKey => {
1682
- const shareItem = getNormalizeShareItem(shareKey);
1683
- const assets = preloadMap[shareKey] || createEmptyAssetMap();
1684
- return {
1685
- id: `${name}:${shareKey}`,
1686
- name: shareKey,
1687
- version: shareItem.version,
1688
- requiredVersion: shareItem.shareConfig.requiredVersion,
1689
- assets: {
1690
- js: {
1691
- async: assets.js.async,
1692
- sync: assets.js.sync
1693
- },
1694
- css: {
1695
- async: assets.css.async,
1696
- sync: assets.css.sync
1697
- }
1698
- }
1699
- };
1700
- }).filter(Boolean);
1701
- // Process exposed modules
1702
- const exposes = Object.entries(options.exposes).map(([key, value]) => {
1703
- const formatKey = key.replace('./', '');
1704
- const sourceFile = value.import;
1705
- const assets = preloadMap[sourceFile] || createEmptyAssetMap();
1706
- return {
1707
- id: `${name}:${formatKey}`,
1708
- name: formatKey,
1709
- assets: {
1710
- js: {
1711
- async: assets.js.async,
1712
- sync: assets.js.sync
1713
- },
1714
- css: {
1715
- async: assets.css.async,
1716
- sync: assets.css.sync
1717
- }
1718
- },
1719
- path: key
1720
- };
1721
- }).filter(Boolean);
1722
- return {
1723
- id: name,
1724
- name,
1725
- metaData: _extends({
1726
- name,
1727
- type: 'app',
1728
- buildInfo: {
1729
- buildVersion: '1.0.0',
1730
- buildName: name
1731
- },
1732
- remoteEntry,
1733
- ssrRemoteEntry: remoteEntry,
1734
- types: {
1735
- path: '',
1736
- name: ''
1737
- },
1738
- globalName: name,
1739
- pluginVersion: '0.2.5'
1740
- }, !!getPublicPath ? {
1741
- getPublicPath
1742
- } : {
1743
- publicPath
1744
- }),
1745
- shared,
1746
- remotes,
1747
- exposes
1748
- };
1749
- }
1750
- };
1751
-
1752
- let _resolve, _parseTimeout;
1753
- const promise = new Promise((resolve, reject) => {
1754
- _resolve = v => {
1755
- clearTimeout(_parseTimeout);
1756
- _parseTimeout = null;
1757
- resolve(v);
1758
- };
1759
- });
1760
- function setParseTimeout(timeout) {
1761
- if (!_parseTimeout) {
1762
- _parseTimeout = setTimeout(() => {
1763
- console.warn(`Parse timeout (${timeout}s) - forcing resolve`);
1764
- _resolve(1);
1765
- }, timeout * 1000);
1766
- }
1767
- }
1768
- let parsePromise = promise;
1769
- let exposesParseEnd = false;
1770
- const parseStartSet = new Set();
1771
- const parseEndSet = new Set();
1772
- function pluginModuleParseEnd (excludeFn, options) {
1773
- setParseTimeout(options.moduleParseTimeout);
1774
- return [{
1775
- name: '_',
1776
- apply: 'serve',
1777
- config() {
1778
- // No waiting in development mode
1779
- _resolve(1);
1780
- }
1781
- }, {
1782
- enforce: 'pre',
1783
- name: 'parseStart',
1784
- apply: 'build',
1785
- load(id) {
1786
- if (excludeFn(id)) {
1787
- return;
1788
- }
1789
- parseStartSet.add(id);
1790
- }
1791
- }, {
1792
- enforce: 'post',
1793
- name: 'parseEnd',
1794
- apply: 'build',
1795
- moduleParsed(module) {
1796
- const id = module.id;
1797
- if (id === VIRTUAL_EXPOSES) {
1798
- // When the entry JS file is empty and only contains exposes export code, it’s necessary to wait for the exposes modules to be resolved in order to collect the dependencies being used.
1799
- exposesParseEnd = true;
1800
- }
1801
- if (excludeFn(id)) {
1802
- return;
1803
- }
1804
- parseEndSet.add(id);
1805
- if (exposesParseEnd && parseStartSet.size === parseEndSet.size) {
1806
- _resolve(1);
1807
- }
1808
- }
1809
- }];
1810
- }
1811
-
1812
- const filter = createFilter();
1813
- function pluginProxyRemoteEntry () {
1814
- let viteConfig, _command;
1815
- return {
1816
- name: 'proxyRemoteEntry',
1817
- enforce: 'post',
1818
- configResolved(config) {
1819
- viteConfig = config;
1820
- },
1821
- config(config, {
1822
- command
1823
- }) {
1824
- _command = command;
1825
- },
1826
- resolveId(id) {
1827
- if (id === REMOTE_ENTRY_ID) {
1828
- return REMOTE_ENTRY_ID;
1829
- }
1830
- if (id === VIRTUAL_EXPOSES) {
1831
- return VIRTUAL_EXPOSES;
1832
- }
1833
- if (_command === 'serve' && id.includes(getHostAutoInitPath())) {
1834
- return id;
1835
- }
1836
- },
1837
- load(id) {
1838
- if (id === REMOTE_ENTRY_ID) {
1839
- return parsePromise.then(_ => generateRemoteEntry(getNormalizeModuleFederationOptions()));
1840
- }
1841
- if (id === VIRTUAL_EXPOSES) {
1842
- return generateExposes();
1843
- }
1844
- if (_command === 'serve' && id.includes(getHostAutoInitPath())) {
1845
- return id;
1846
- }
1847
- },
1848
- transform(code, id) {
1849
- const transformedCode = (() => {
1850
- if (!filter(id)) return;
1851
- if (id.includes(REMOTE_ENTRY_ID)) {
1852
- return parsePromise.then(_ => generateRemoteEntry(getNormalizeModuleFederationOptions()));
1853
- }
1854
- if (id === VIRTUAL_EXPOSES) {
1855
- return generateExposes();
1856
- }
1857
- if (id.includes(getHostAutoInitPath())) {
1858
- const options = getNormalizeModuleFederationOptions();
1859
- if (_command === 'serve') {
1860
- var _viteConfig$server, _viteConfig$server2;
1861
- const host = typeof ((_viteConfig$server = viteConfig.server) == null ? void 0 : _viteConfig$server.host) === 'string' && viteConfig.server.host !== '0.0.0.0' ? viteConfig.server.host : 'localhost';
1862
- const publicPath = JSON.stringify(resolvePublicPath(options, viteConfig.base) + options.filename);
1863
- return `
1864
- const origin = (window && ${!options.ignoreOrigin}) ? window.origin : "//${host}:${(_viteConfig$server2 = viteConfig.server) == null ? void 0 : _viteConfig$server2.port}"
1865
- const remoteEntryPromise = await import(origin + ${publicPath})
1866
- // __tla only serves as a hack for vite-plugin-top-level-await.
1867
- Promise.resolve(remoteEntryPromise)
1868
- .then(remoteEntry => {
1869
- return Promise.resolve(remoteEntry.__tla)
1870
- .then(remoteEntry.init).catch(remoteEntry.init)
1871
- })
1872
- `;
1873
- }
1874
- return code;
1875
- }
1876
- })();
1877
- return mapCodeToCodeWithSourcemap(transformedCode);
1878
- }
1879
- };
1880
- }
1881
-
1882
- createFilter();
1883
- function pluginProxyRemotes (options) {
1884
- const {
1885
- remotes
1886
- } = options;
1887
- return {
1888
- name: 'proxyRemotes',
1889
- config(config, {
1890
- command: _command
1891
- }) {
1892
- Object.keys(remotes).forEach(key => {
1893
- const remote = remotes[key];
1894
- config.resolve.alias.push({
1895
- find: new RegExp(`^(${remote.name}(\/.*|$))`),
1896
- replacement: '$1',
1897
- customResolver(source) {
1898
- const remoteModule = getRemoteVirtualModule(source, _command);
1899
- addUsedRemote(remote.name, source);
1900
- return remoteModule.getPath();
1901
- }
1902
- });
1903
- });
1904
- }
1905
- };
1906
- }
1907
-
1908
- /**
1909
- * example:
1910
- * const store = new PromiseStore<number>();
1911
- * store.get("example").then((result) => {
1912
- * console.log("Result from example:", result); // 42
1913
- * });
1914
- * setTimeout(() => {
1915
- * store.set("example", Promise.resolve(42));
1916
- * }, 2000);
1917
- */
1918
- class PromiseStore {
1919
- constructor() {
1920
- this.promiseMap = new Map();
1921
- this.resolveMap = new Map();
1922
- }
1923
- set(id, promise) {
1924
- if (this.resolveMap.has(id)) {
1925
- promise.then(this.resolveMap.get(id));
1926
- this.resolveMap.delete(id);
1927
- }
1928
- this.promiseMap.set(id, promise);
1929
- }
1930
- get(id) {
1931
- if (this.promiseMap.has(id)) {
1932
- return this.promiseMap.get(id);
1933
- }
1934
- const pendingPromise = new Promise(resolve => {
1935
- this.resolveMap.set(id, resolve);
1936
- });
1937
- this.promiseMap.set(id, pendingPromise);
1938
- return pendingPromise;
1939
- }
1940
- }
1941
-
1942
- function proxySharedModule(options) {
1943
- let {
1944
- shared = {},
1945
- include,
1946
- exclude
1947
- } = options;
1948
- let _config;
1949
- return [{
1950
- name: 'generateLocalSharedImportMap',
1951
- enforce: 'post',
1952
- load(id) {
1953
- if (id.includes(getLocalSharedImportMapPath())) {
1954
- return parsePromise.then(_ => generateLocalSharedImportMap());
1955
- }
1956
- },
1957
- transform(_, id) {
1958
- if (id.includes(getLocalSharedImportMapPath())) {
1959
- return mapCodeToCodeWithSourcemap(parsePromise.then(_ => generateLocalSharedImportMap()));
1960
- }
1961
- }
1962
- }, {
1963
- name: 'proxyPreBuildShared',
1964
- enforce: 'post',
1965
- configResolved(config) {
1966
- _config = config;
1967
- },
1968
- config(config, {
1969
- command
1970
- }) {
1971
- config.resolve.alias.push(...Object.keys(shared).map(key => {
1972
- const pattern = key.endsWith('/') ? `(^${key.replace(/\/$/, '')}(\/.+)?$)` : `(^${key}$)`;
1973
- return {
1974
- // Intercept all shared requests and proxy them to loadShare
1975
- find: new RegExp(pattern),
1976
- replacement: '$1',
1977
- customResolver(source, importer) {
1978
- if (/\.css$/.test(source)) return;
1979
- const loadSharePath = getLoadShareModulePath(source);
1980
- writeLoadShareModule(source, shared[key], command);
1981
- writePreBuildLibPath(source);
1982
- addUsedShares(source);
1983
- writeLocalSharedImportMap();
1984
- return this.resolve(loadSharePath, importer);
1985
- }
1986
- };
1987
- }));
1988
- const savePrebuild = new PromiseStore();
1989
- config.resolve.alias.push(...Object.keys(shared).map(key => {
1990
- return command === 'build' ? {
1991
- find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
1992
- replacement: function ($1) {
1993
- const module = assertModuleFound(PREBUILD_TAG, $1);
1994
- const pkgName = module.name;
1995
- return pkgName;
1996
- }
1997
- } : {
1998
- find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
1999
- replacement: '$1',
2000
- async customResolver(source, importer) {
2001
- const module = assertModuleFound(PREBUILD_TAG, source);
2002
- const pkgName = module.name;
2003
- const result = await this.resolve(pkgName, importer).then(item => item.id);
2004
- if (!result.includes(_config.cacheDir)) {
2005
- // save pre-bunding module id
2006
- savePrebuild.set(pkgName, Promise.resolve(result));
2007
- }
2008
- // Fix localSharedImportMap import id
2009
- return await this.resolve(await savePrebuild.get(pkgName), importer);
2010
- }
2011
- };
2012
- }));
2013
- }
2014
- }];
2015
- }
2016
-
2017
- var aliasToArrayPlugin = {
2018
- name: 'alias-transform-plugin',
2019
- config: (config, {
2020
- command
2021
- }) => {
2022
- if (!config.resolve) config.resolve = {};
2023
- if (!config.resolve.alias) config.resolve.alias = [];
2024
- const {
2025
- alias
2026
- } = config.resolve;
2027
- if (typeof alias === 'object' && !Array.isArray(alias)) {
2028
- config.resolve.alias = Object.entries(alias).map(([find, replacement]) => ({
2029
- find,
2030
- replacement
2031
- }));
2032
- }
2033
- }
2034
- };
2035
-
2036
- var normalizeOptimizeDepsPlugin = {
2037
- name: 'normalizeOptimizeDeps',
2038
- config: (config, {
2039
- command
2040
- }) => {
2041
- let {
2042
- optimizeDeps
2043
- } = config;
2044
- if (!optimizeDeps) {
2045
- config.optimizeDeps = {};
2046
- optimizeDeps = config.optimizeDeps;
2047
- }
2048
- // todo: fix this workaround
2049
- optimizeDeps.force = true;
2050
- if (!optimizeDeps.include) optimizeDeps.include = [];
2051
- if (!optimizeDeps.needsInterop) optimizeDeps.needsInterop = [];
2052
- }
2053
- };
2054
-
2055
- function federation(mfUserOptions) {
2056
- const options = normalizeModuleFederationOptions(mfUserOptions);
2057
- const {
2058
- name,
2059
- remotes,
2060
- shared,
2061
- filename,
2062
- hostInitInjectLocation
2063
- } = options;
2064
- if (!name) throw new Error('name is required');
2065
- return [{
2066
- name: 'vite:module-federation-config',
2067
- enforce: 'pre',
2068
- configResolved(config) {
2069
- // Set root path
2070
- VirtualModule.setRoot(config.root);
2071
- // Ensure virtual package directory exists
2072
- VirtualModule.ensureVirtualPackageExists();
2073
- initVirtualModules();
2074
- }
2075
- }, aliasToArrayPlugin, checkAliasConflicts({
2076
- shared
2077
- }), normalizeOptimizeDepsPlugin, ...pluginDts(options), ...addEntry({
2078
- entryName: 'remoteEntry',
2079
- entryPath: REMOTE_ENTRY_ID,
2080
- fileName: filename
2081
- }), ...addEntry({
2082
- entryName: 'hostInit',
2083
- entryPath: getHostAutoInitPath(),
2084
- inject: hostInitInjectLocation
2085
- }), ...addEntry({
2086
- entryName: 'virtualExposes',
2087
- entryPath: VIRTUAL_EXPOSES
2088
- }), pluginProxyRemoteEntry(), pluginProxyRemotes(options), ...pluginModuleParseEnd(id => {
2089
- return id.includes(getHostAutoInitImportId()) || id.includes(REMOTE_ENTRY_ID) || id.includes(VIRTUAL_EXPOSES) || id.includes(getLocalSharedImportMapPath());
2090
- }, {
2091
- moduleParseTimeout: options.moduleParseTimeout
2092
- }), ...proxySharedModule({
2093
- shared
2094
- }), PluginDevProxyModuleTopLevelAwait(), {
2095
- name: 'module-federation-vite',
2096
- enforce: 'post',
2097
- // @ts-expect-error
2098
- // used to expose plugin options: https://github.com/rolldown/rolldown/discussions/2577#discussioncomment-11137593
2099
- _options: options,
2100
- config(config, {
2101
- command: _command
2102
- }) {
2103
- var _config$optimizeDeps, _config$optimizeDeps2, _config$optimizeDeps3, _config$optimizeDeps4;
2104
- // TODO: singleton
2105
- config.resolve.alias.push({
2106
- find: '@module-federation/runtime',
2107
- replacement: options.implementation
2108
- });
2109
- config.build = defu(config.build || {}, {
2110
- commonjsOptions: {
2111
- strictRequires: 'auto'
2112
- }
2113
- });
2114
- const virtualDir = options.virtualModuleDir || '__mf__virtual';
2115
- (_config$optimizeDeps = config.optimizeDeps) == null || (_config$optimizeDeps = _config$optimizeDeps.include) == null || _config$optimizeDeps.push('@module-federation/runtime');
2116
- (_config$optimizeDeps2 = config.optimizeDeps) == null || (_config$optimizeDeps2 = _config$optimizeDeps2.include) == null || _config$optimizeDeps2.push(virtualDir);
2117
- (_config$optimizeDeps3 = config.optimizeDeps) == null || (_config$optimizeDeps3 = _config$optimizeDeps3.needsInterop) == null || _config$optimizeDeps3.push(virtualDir);
2118
- (_config$optimizeDeps4 = config.optimizeDeps) == null || (_config$optimizeDeps4 = _config$optimizeDeps4.needsInterop) == null || _config$optimizeDeps4.push(getLocalSharedImportMapPath());
2119
- }
2120
- }, ...Manifest()];
2121
- }
2122
-
2123
- export { federation };