@module-federation/vite 1.0.0 → 1.1.0

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.
@@ -12,13 +12,13 @@ const addEntry = ({
12
12
  entryPath,
13
13
  fileName
14
14
  }) => {
15
- const devEntryPath = entryPath.startsWith("virtual:mf") ? "/@id/" + entryPath : entryPath;
15
+ const devEntryPath = entryPath.startsWith('virtual:mf') ? '/@id/' + entryPath : entryPath;
16
16
  let entryFiles = [];
17
17
  let htmlFilePath;
18
18
  let _command;
19
19
  return [{
20
20
  name: 'add-entry',
21
- apply: "serve",
21
+ apply: 'serve',
22
22
  config(config, {
23
23
  command
24
24
  }) {
@@ -47,8 +47,8 @@ const addEntry = ({
47
47
  return c.replace('<head>', `<head><script type="module" src=${JSON.stringify(devEntryPath.replace(/.+?\:([/\\])[/\\]?/, '$1').replace(/\\\\?/g, '/'))}></script>`);
48
48
  }
49
49
  }, {
50
- name: "add-entry",
51
- enforce: "post",
50
+ name: 'add-entry',
51
+ enforce: 'post',
52
52
  configResolved(config) {
53
53
  const inputOptions = config.build.rollupOptions.input;
54
54
  if (!inputOptions) {
@@ -65,8 +65,8 @@ const addEntry = ({
65
65
  }
66
66
  },
67
67
  buildStart() {
68
- if (_command === "serve") return;
69
- const hasHash = fileName == null || fileName.includes == null ? void 0 : fileName.includes("[hash");
68
+ if (_command === 'serve') return;
69
+ const hasHash = fileName == null || fileName.includes == null ? void 0 : fileName.includes('[hash');
70
70
  const emitFileOptions = {
71
71
  name: entryName,
72
72
  type: 'chunk',
@@ -103,10 +103,10 @@ const addEntry = ({
103
103
  function PluginDevProxyModuleTopLevelAwait() {
104
104
  const filterFunction = createFilter();
105
105
  return {
106
- name: "dev-proxy-module-top-level-await",
107
- apply: "serve",
106
+ name: 'dev-proxy-module-top-level-await',
107
+ apply: 'serve',
108
108
  transform(code, id) {
109
- if (!code.includes("/*mf top-level-await placeholder replacement mf*/")) {
109
+ if (!code.includes('/*mf top-level-await placeholder replacement mf*/')) {
110
110
  return null;
111
111
  }
112
112
  if (!filterFunction(id)) return null;
@@ -174,6 +174,18 @@ function PluginDevProxyModuleTopLevelAwait() {
174
174
  };
175
175
  }
176
176
 
177
+ function _extends() {
178
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
179
+ for (var e = 1; e < arguments.length; e++) {
180
+ var t = arguments[e];
181
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
182
+ }
183
+ return n;
184
+ }, _extends.apply(null, arguments);
185
+ }
186
+
187
+ const warn = message => message.split('\n').forEach(msg => console.warn('\x1b[33m%s\x1b[0m', msg));
188
+
177
189
  function normalizeExposesItem(key, item) {
178
190
  let importPath = '';
179
191
  if (typeof item === 'string') {
@@ -246,7 +258,7 @@ function normalizeShareItem(key, shareItem) {
246
258
  from: '',
247
259
  shareConfig: {
248
260
  singleton: false,
249
- requiredVersion: `^${version}` || '*'
261
+ requiredVersion: version ? `^${version}` : '*'
250
262
  }
251
263
  };
252
264
  }
@@ -257,7 +269,7 @@ function normalizeShareItem(key, shareItem) {
257
269
  scope: shareItem.shareScope || 'default',
258
270
  shareConfig: {
259
271
  singleton: shareItem.singleton || false,
260
- requiredVersion: shareItem.requiredVersion || `^${version}` || '*',
272
+ requiredVersion: shareItem.requiredVersion || (version ? `^${version}` : '*'),
261
273
  strictVersion: !!shareItem.strictVersion
262
274
  }
263
275
  };
@@ -283,13 +295,13 @@ function normalizeLibrary(library) {
283
295
  return library;
284
296
  }
285
297
  function normalizeManifest(manifest = false) {
286
- if (typeof manifest === "boolean") {
298
+ if (typeof manifest === 'boolean') {
287
299
  return manifest;
288
300
  }
289
301
  return Object.assign({
290
- filePath: "",
302
+ filePath: '',
291
303
  disableAssetsAnalyze: false,
292
- fileName: "mf-manifest.json"
304
+ fileName: 'mf-manifest.json'
293
305
  }, manifest);
294
306
  }
295
307
  let config;
@@ -298,10 +310,13 @@ function getNormalizeModuleFederationOptions() {
298
310
  }
299
311
  function getNormalizeShareItem(key) {
300
312
  const options = getNormalizeModuleFederationOptions();
301
- const shareItem = options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + "/"];
313
+ const shareItem = options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + '/'];
302
314
  return shareItem;
303
315
  }
304
316
  function normalizeModuleFederationOptions(options) {
317
+ if (options.getPublicPath || options.publicPath) {
318
+ warn(`We are ignoring the getPublicPath and publicPath options because they are natively supported by Vite\nwith the "experimental.renderBuiltUrl" configuration https://vitejs.dev/guide/build#advanced-base-options`);
319
+ }
305
320
  return config = {
306
321
  exposes: normalizeExposes(options.exposes),
307
322
  filename: options.filename || 'remoteEntry-[hash]',
@@ -313,11 +328,11 @@ function normalizeModuleFederationOptions(options) {
313
328
  shareScope: options.shareScope || 'default',
314
329
  shared: normalizeShared(options.shared),
315
330
  runtimePlugins: options.runtimePlugins || [],
316
- getPublicPath: options.getPublicPath,
317
331
  implementation: options.implementation,
318
332
  manifest: normalizeManifest(options.manifest),
319
333
  dev: options.dev,
320
- dts: options.dts
334
+ dts: options.dts,
335
+ shareStrategy: options.shareStrategy
321
336
  };
322
337
  }
323
338
 
@@ -335,8 +350,8 @@ function normalizeModuleFederationOptions(options) {
335
350
  * @returns {string} - The encoded file name.
336
351
  */
337
352
  function packageNameEncode(name) {
338
- if (typeof name !== "string") throw new Error("A string package name is required");
339
- return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
353
+ if (typeof name !== 'string') throw new Error('A string package name is required');
354
+ return name.replace(/@/g, '_mf_0_').replace(/\//g, '_mf_1_').replace(/-/g, '_mf_2_').replace(/\./g, '_mf_3_');
340
355
  }
341
356
  /**
342
357
  * Decodes an encoded file name back to the original package name.
@@ -344,8 +359,8 @@ function packageNameEncode(name) {
344
359
  * @returns {string} - The decoded package name.
345
360
  */
346
361
  function packageNameDecode(encoded) {
347
- if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
348
- return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
362
+ if (typeof encoded !== 'string') throw new Error('A string encoded file name is required');
363
+ return encoded.replace(/_mf_0_/g, '@').replace(/_mf_1_/g, '/').replace(/_mf_2_/g, '-').replace(/_mf_3_/g, '.');
349
364
  }
350
365
 
351
366
  /**
@@ -355,11 +370,11 @@ function getLocalSharedImportMapPath_temp() {
355
370
  const {
356
371
  name
357
372
  } = getNormalizeModuleFederationOptions();
358
- return path__default.resolve(".__mf__temp", packageNameEncode(name), "localSharedImportMap");
373
+ return path__default.resolve('.__mf__temp', packageNameEncode(name), 'localSharedImportMap');
359
374
  }
360
375
  function writeLocalSharedImportMap_temp(content) {
361
376
  const localSharedImportMapId = getLocalSharedImportMapPath_temp();
362
- createFile(localSharedImportMapId + ".js", "\n// Windows temporarily needs this file, https://github.com/module-federation/vite/issues/68\n" + content);
377
+ createFile(localSharedImportMapId + '.js', '\n// Windows temporarily needs this file, https://github.com/module-federation/vite/issues/68\n' + content);
363
378
  }
364
379
  function createFile(filePath, content) {
365
380
  const dir = path__default.dirname(filePath);
@@ -378,16 +393,16 @@ const nodeModulesDir = function findNodeModulesDir(startDir = process.cwd()) {
378
393
  }
379
394
  currentDir = dirname(currentDir);
380
395
  }
381
- return "";
396
+ return '';
382
397
  }();
383
- const virtualPackageName = "__mf__virtual";
398
+ const virtualPackageName = '__mf__virtual';
384
399
  if (!existsSync(resolve(nodeModulesDir, virtualPackageName))) {
385
400
  mkdirSync(resolve(nodeModulesDir, virtualPackageName));
386
401
  }
387
- writeFileSync(resolve(nodeModulesDir, virtualPackageName, "empty.js"), "");
388
- writeFileSync(resolve(nodeModulesDir, virtualPackageName, "package.json"), JSON.stringify({
402
+ writeFileSync(resolve(nodeModulesDir, virtualPackageName, 'empty.js'), '');
403
+ writeFileSync(resolve(nodeModulesDir, virtualPackageName, 'package.json'), JSON.stringify({
389
404
  name: virtualPackageName,
390
- main: "empty.js"
405
+ main: 'empty.js'
391
406
  }));
392
407
  const patternMap = {};
393
408
  const cacheMap = {};
@@ -395,13 +410,13 @@ const cacheMap = {};
395
410
  * Physically generate files as virtual modules under node_modules/__mf__virtual/*
396
411
  */
397
412
  class VirtualModule {
398
- static findModule(tag, str = "") {
413
+ static findModule(tag, str = '') {
399
414
  if (!patternMap[tag]) patternMap[tag] = new RegExp(`(.*${packageNameEncode(tag)}(.+?)${packageNameEncode(tag)}.*)`);
400
415
  const moduleName = (str.match(patternMap[tag]) || [])[2];
401
416
  if (moduleName) return cacheMap[tag][packageNameDecode(moduleName)];
402
417
  return undefined;
403
418
  }
404
- constructor(name, tag = '__mf_v__', suffix = "") {
419
+ constructor(name, tag = '__mf_v__', suffix = '') {
405
420
  var _name$split$slice$pop;
406
421
  this.name = void 0;
407
422
  this.tag = void 0;
@@ -409,7 +424,7 @@ class VirtualModule {
409
424
  this.inited = false;
410
425
  this.name = name;
411
426
  this.tag = tag;
412
- this.suffix = suffix || ((_name$split$slice$pop = name.split(".").slice(1).pop()) == null ? void 0 : _name$split$slice$pop.replace(/(.)/, ".$1")) || ".js";
427
+ this.suffix = suffix || ((_name$split$slice$pop = name.split('.').slice(1).pop()) == null ? void 0 : _name$split$slice$pop.replace(/(.)/, '.$1')) || '.js';
413
428
  if (!cacheMap[this.tag]) cacheMap[this.tag] = {};
414
429
  cacheMap[this.tag][this.name] = this;
415
430
  }
@@ -434,7 +449,30 @@ class VirtualModule {
434
449
  }
435
450
  }
436
451
 
437
- const virtualRuntimeInitStatus = new VirtualModule("runtimeInit");
452
+ const VIRTUAL_EXPOSES = 'virtual:mf-exposes';
453
+ function generateExposes() {
454
+ const options = getNormalizeModuleFederationOptions();
455
+ return `
456
+ export default {
457
+ ${Object.keys(options.exposes).map(key => {
458
+ return `
459
+ ${JSON.stringify(key)}: async () => {
460
+ const importModule = await import(${JSON.stringify(options.exposes[key].import)})
461
+ const exportModule = {}
462
+ Object.assign(exportModule, importModule)
463
+ Object.defineProperty(exportModule, "__esModule", {
464
+ value: true,
465
+ enumerable: false
466
+ })
467
+ return exportModule
468
+ }
469
+ `;
470
+ }).join(',')}
471
+ }
472
+ `;
473
+ }
474
+
475
+ const virtualRuntimeInitStatus = new VirtualModule('runtimeInit');
438
476
  function writeRuntimeInitStatus() {
439
477
  virtualRuntimeInitStatus.writeSync(`
440
478
  let initResolve, initReject
@@ -454,7 +492,7 @@ const cacheRemoteMap = {};
454
492
  const LOAD_REMOTE_TAG = '__loadRemote__';
455
493
  function getRemoteVirtualModule(remote, command) {
456
494
  if (!cacheRemoteMap[remote]) {
457
- cacheRemoteMap[remote] = new VirtualModule(remote, LOAD_REMOTE_TAG, ".js");
495
+ cacheRemoteMap[remote] = new VirtualModule(remote, LOAD_REMOTE_TAG, '.js');
458
496
  cacheRemoteMap[remote].writeSync(generateRemotes(remote, command));
459
497
  }
460
498
  const virtual = cacheRemoteMap[remote];
@@ -475,7 +513,7 @@ function generateRemotes(id, command) {
475
513
  const {loadRemote} = require("@module-federation/runtime")
476
514
  const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")
477
515
  const res = initPromise.then(_ => loadRemote(${JSON.stringify(id)}))
478
- const exportModule = ${command !== "build" ? "/*mf top-level-await placeholder replacement mf*/" : "await "}initPromise.then(_ => res)
516
+ const exportModule = ${command !== 'build' ? '/*mf top-level-await placeholder replacement mf*/' : 'await '}initPromise.then(_ => res)
479
517
  module.exports = exportModule
480
518
  `;
481
519
  }
@@ -487,10 +525,10 @@ function generateRemotes(id, command) {
487
525
  */
488
526
  // *** __prebuild__
489
527
  const preBuildCacheMap = {};
490
- const PREBUILD_TAG = "__prebuild__";
528
+ const PREBUILD_TAG = '__prebuild__';
491
529
  function writePreBuildLibPath(pkg) {
492
530
  if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
493
- preBuildCacheMap[pkg].writeSync("");
531
+ preBuildCacheMap[pkg].writeSync('');
494
532
  }
495
533
  function getPreBuildLibImportId(pkg) {
496
534
  if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
@@ -498,10 +536,10 @@ function getPreBuildLibImportId(pkg) {
498
536
  return importId;
499
537
  }
500
538
  // *** __loadShare__
501
- const LOAD_SHARE_TAG = "__loadShare__";
539
+ const LOAD_SHARE_TAG = '__loadShare__';
502
540
  const loadShareCacheMap = {};
503
541
  function getLoadShareModulePath(pkg) {
504
- if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, ".js");
542
+ if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, '.js');
505
543
  const filepath = loadShareCacheMap[pkg].getPath();
506
544
  return filepath;
507
545
  }
@@ -510,7 +548,7 @@ function writeLoadShareModule(pkg, shareItem, command) {
510
548
 
511
549
  ;() => import(${JSON.stringify(getPreBuildLibImportId(pkg))}).catch(() => {});
512
550
  // dev uses dynamic import to separate chunks
513
- ${command !== "build" ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ''}
551
+ ${command !== 'build' ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ''}
514
552
  const {loadShare} = require("@module-federation/runtime")
515
553
  const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")
516
554
  const res = initPromise.then(_ => loadShare(${JSON.stringify(pkg)}, {
@@ -519,7 +557,7 @@ function writeLoadShareModule(pkg, shareItem, command) {
519
557
  strictVersion: ${shareItem.shareConfig.strictVersion},
520
558
  requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
521
559
  }}}))
522
- const exportModule = ${command !== "build" ? "/*mf top-level-await placeholder replacement mf*/" : "await "}res.then(factory => factory())
560
+ const exportModule = ${command !== 'build' ? '/*mf top-level-await placeholder replacement mf*/' : 'await '}res.then(factory => factory())
523
561
  module.exports = exportModule
524
562
  `);
525
563
  }
@@ -532,7 +570,7 @@ function addUsedShares(pkg) {
532
570
  usedShares.add(pkg);
533
571
  }
534
572
  // *** Expose locally provided shared modules here
535
- new VirtualModule("localSharedImportMap");
573
+ new VirtualModule('localSharedImportMap');
536
574
  function getLocalSharedImportMapPath() {
537
575
  return getLocalSharedImportMapPath_temp();
538
576
  // return localSharedImportMapModule.getPath()
@@ -555,7 +593,7 @@ function generateLocalSharedImportMap() {
555
593
  let pkg = await import("${getPreBuildLibImportId(pkg)}")
556
594
  return pkg
557
595
  }
558
- `).join(",")}
596
+ `).join(',')}
559
597
  }
560
598
  const usedShared = {
561
599
  ${Array.from(getUsedShares()).map(key => {
@@ -613,23 +651,7 @@ function generateRemoteEntry(options) {
613
651
  return `
614
652
  import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
615
653
  ${pluginImportNames.map(item => item[1]).join('\n')}
616
-
617
- const exposesMap = {
618
- ${Object.keys(options.exposes).map(key => {
619
- return `
620
- ${JSON.stringify(key)}: async () => {
621
- const importModule = await import(${JSON.stringify(options.exposes[key].import)})
622
- const exportModule = {}
623
- Object.assign(exportModule, importModule)
624
- Object.defineProperty(exportModule, "__esModule", {
625
- value: true,
626
- enumerable: false
627
- })
628
- return exportModule
629
- }
630
- `;
631
- }).join(',')}
632
- }
654
+ import exposesMap from "${VIRTUAL_EXPOSES}"
633
655
  import {usedShared, usedRemotes} from "${getLocalSharedImportMapPath()}"
634
656
  import {
635
657
  initResolve
@@ -639,7 +661,8 @@ function generateRemoteEntry(options) {
639
661
  name: ${JSON.stringify(options.name)},
640
662
  remotes: usedRemotes,
641
663
  shared: usedShared,
642
- plugins: [${pluginImportNames.map(item => `${item[0]}()`).join(', ')}]
664
+ plugins: [${pluginImportNames.map(item => `${item[0]}()`).join(', ')}],
665
+ ${options.shareStrategy ? `shareStrategy: ${options.shareStrategy}` : ''}
643
666
  });
644
667
  initRes.initShareScopeMap('${options.shareScope}', shared);
645
668
  initResolve(initRes)
@@ -660,7 +683,7 @@ function generateRemoteEntry(options) {
660
683
  * Inject entry file, automatically init when used as host,
661
684
  * and will not inject remoteEntry
662
685
  */
663
- const hostAutoInitModule = new VirtualModule("hostAutoInit");
686
+ const hostAutoInitModule = new VirtualModule('hostAutoInit');
664
687
  function writeHostAutoInit() {
665
688
  hostAutoInitModule.writeSync(`
666
689
  import {init} from "${REMOTE_ENTRY_ID}"
@@ -687,20 +710,19 @@ const Manifest = () => {
687
710
  filename,
688
711
  manifest: manifestOptions
689
712
  } = mfOptions;
690
- let mfManifestName = "";
713
+ let mfManifestName = '';
691
714
  if (manifestOptions === true) {
692
- mfManifestName = "mf-manifest.json";
715
+ mfManifestName = 'mf-manifest.json';
693
716
  }
694
- if (typeof manifestOptions !== "boolean") {
695
- mfManifestName = join((manifestOptions == null ? void 0 : manifestOptions.filePath) || "", (manifestOptions == null ? void 0 : manifestOptions.fileName) || "");
717
+ if (typeof manifestOptions !== 'boolean') {
718
+ mfManifestName = join((manifestOptions == null ? void 0 : manifestOptions.filePath) || '', (manifestOptions == null ? void 0 : manifestOptions.fileName) || '');
696
719
  }
697
720
  let extensions;
698
721
  let root;
699
722
  let remoteEntryFile;
700
- let publicPath;
701
723
  let _command;
702
724
  return [{
703
- name: 'moddule-federation-manifest',
725
+ name: 'module-federation-manifest',
704
726
  apply: 'serve',
705
727
  configureServer(server) {
706
728
  server.middlewares.use((req, res, next) => {
@@ -708,10 +730,10 @@ const Manifest = () => {
708
730
  next();
709
731
  return;
710
732
  }
711
- if (req.url === mfManifestName.replace(/^\/?/, "/")) {
733
+ if (req.url === mfManifestName.replace(/^\/?/, '/')) {
712
734
  res.setHeader('Content-Type', 'application/json');
713
735
  res.setHeader('Access-Control-Allow-Origin', '*');
714
- res.end(JSON.stringify({
736
+ res.end(JSON.stringify(_extends({}, generateMFManifest({}), {
715
737
  id: name,
716
738
  name: name,
717
739
  metaData: {
@@ -736,70 +758,16 @@ const Manifest = () => {
736
758
  name: ''
737
759
  },
738
760
  globalName: name,
739
- pluginVersion: '0.2.5',
740
- publicPath
741
- },
742
- shared: Array.from(getUsedShares()).map(shareKey => {
743
- const shareItem = getNormalizeShareItem(shareKey);
744
- return {
745
- id: `${name}:${shareKey}`,
746
- name: shareKey,
747
- version: shareItem.version,
748
- requiredVersion: shareItem.shareConfig.requiredVersion,
749
- assets: {
750
- js: {
751
- async: [],
752
- sync: []
753
- },
754
- css: {
755
- async: [],
756
- sync: []
757
- }
758
- }
759
- };
760
- }),
761
- remotes: function () {
762
- const remotes = [];
763
- const usedRemotesMap = getUsedRemotesMap();
764
- Object.keys(usedRemotesMap).forEach(remoteKey => {
765
- const usedModules = Array.from(usedRemotesMap[remoteKey]);
766
- usedModules.forEach(moduleKey => {
767
- remotes.push({
768
- federationContainerName: mfOptions.remotes[remoteKey].entry,
769
- moduleName: moduleKey.replace(remoteKey, '').replace('/', ''),
770
- alias: remoteKey,
771
- entry: '*'
772
- });
773
- });
774
- });
775
- return remotes;
776
- }(),
777
- exposes: Object.keys(mfOptions.exposes).map(key => {
778
- const formatKey = key.replace('./', '');
779
- return {
780
- id: name + ':' + formatKey,
781
- name: formatKey,
782
- assets: {
783
- js: {
784
- async: [],
785
- sync: []
786
- },
787
- css: {
788
- sync: [],
789
- async: []
790
- }
791
- },
792
- path: key
793
- };
794
- })
795
- }));
761
+ pluginVersion: '0.2.5'
762
+ }
763
+ })));
796
764
  } else {
797
765
  next();
798
766
  }
799
767
  });
800
768
  }
801
769
  }, {
802
- name: 'moddule-federation-manifest',
770
+ name: 'module-federation-manifest',
803
771
  enforce: 'post',
804
772
  config(config, {
805
773
  command
@@ -811,10 +779,10 @@ const Manifest = () => {
811
779
  configResolved(config) {
812
780
  root = config.root;
813
781
  extensions = config.resolve.extensions || ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'];
814
- publicPath = config.base ? config.base.replace(/\/?$/, "/") : "auto";
815
- if (_command === "serve") {
782
+ config.base ? config.base.replace(/\/?$/, '/') : 'auto';
783
+ if (_command === 'serve') {
816
784
  const origin = config.server.origin;
817
- publicPath = origin ? origin.replace(/\/?$/, "/") : "auto";
785
+ origin ? origin.replace(/\/?$/, '/') : 'auto';
818
786
  }
819
787
  },
820
788
  async generateBundle(options, bundle) {
@@ -835,7 +803,7 @@ const Manifest = () => {
835
803
  };
836
804
  // 遍历打包生成的每个文件
837
805
  for (const [fileName, fileData] of Object.entries(bundle)) {
838
- if (mfOptions.filename.replace(/[\[\]]/g, "_") === fileData.name || fileData.name === "remoteEntry") {
806
+ if (mfOptions.filename.replace(/[\[\]]/g, '_') === fileData.name || fileData.name === 'remoteEntry') {
839
807
  remoteEntryFile = fileData.fileName;
840
808
  }
841
809
  if (fileData.type === 'chunk') {
@@ -845,7 +813,7 @@ const Manifest = () => {
845
813
  const relativeModulePath = relative(root, modulePath);
846
814
  // 检查模块是否在 preloadModules 列表中
847
815
  for (const preloadModule of exposesModules) {
848
- const formatPreloadModule = preloadModule.replace("./", "");
816
+ const formatPreloadModule = preloadModule.replace('./', '');
849
817
  if (isModuleMatched(relativeModulePath, formatPreloadModule)) {
850
818
  if (!filesContainingModules[preloadModule]) {
851
819
  filesContainingModules[preloadModule] = {
@@ -878,7 +846,7 @@ const Manifest = () => {
878
846
  }
879
847
  const fileToShareKey = {};
880
848
  await Promise.all(Array.from(getUsedShares()).map(async shareKey => {
881
- const file = (await this.resolve(getPreBuildLibImportId(shareKey))).id.split("?")[0];
849
+ const file = (await this.resolve(getPreBuildLibImportId(shareKey))).id.split('?')[0];
882
850
  fileToShareKey[file] = shareKey;
883
851
  }));
884
852
  // 遍历打包生成的每个文件
@@ -909,7 +877,7 @@ const Manifest = () => {
909
877
  this.emitFile({
910
878
  type: 'asset',
911
879
  fileName: mfManifestName,
912
- source: generateMFManifest(filesContainingModules)
880
+ source: JSON.stringify(generateMFManifest(filesContainingModules))
913
881
  });
914
882
  }
915
883
  }];
@@ -938,8 +906,7 @@ const Manifest = () => {
938
906
  });
939
907
  // @ts-ignore
940
908
  const shared = Array.from(getUsedShares()).map(shareKey => {
941
- // assets(.css, .jpg, .svg等)其他资源, 不重要, 暂未处理
942
- if (!preloadMap[shareKey]) return;
909
+ var _preloadMap$shareKey, _preloadMap$shareKey2;
943
910
  const shareItem = getNormalizeShareItem(shareKey);
944
911
  return {
945
912
  id: `${name}:${shareKey}`,
@@ -948,8 +915,8 @@ const Manifest = () => {
948
915
  requiredVersion: shareItem.shareConfig.requiredVersion,
949
916
  assets: {
950
917
  js: {
951
- async: preloadMap[shareKey].async,
952
- sync: preloadMap[shareKey].sync
918
+ async: (preloadMap == null || (_preloadMap$shareKey = preloadMap[shareKey]) == null ? void 0 : _preloadMap$shareKey.async) || [],
919
+ sync: (preloadMap == null || (_preloadMap$shareKey2 = preloadMap[shareKey]) == null ? void 0 : _preloadMap$shareKey2.sync) || []
953
920
  },
954
921
  css: {
955
922
  async: [],
@@ -959,17 +926,17 @@ const Manifest = () => {
959
926
  };
960
927
  }).filter(item => item);
961
928
  const exposes = Object.keys(options.exposes).map(key => {
929
+ var _preloadMap$sourceFil, _preloadMap$sourceFil2;
962
930
  // assets(.css, .jpg, .svg等)其他资源, 不重要, 暂未处理
963
931
  const formatKey = key.replace('./', '');
964
932
  const sourceFile = options.exposes[key].import;
965
- if (!preloadMap[sourceFile]) return;
966
933
  return {
967
934
  id: name + ':' + formatKey,
968
935
  name: formatKey,
969
936
  assets: {
970
937
  js: {
971
- async: preloadMap[sourceFile].async,
972
- sync: preloadMap[sourceFile].sync
938
+ async: (preloadMap == null || (_preloadMap$sourceFil = preloadMap[sourceFile]) == null ? void 0 : _preloadMap$sourceFil.async) || [],
939
+ sync: (preloadMap == null || (_preloadMap$sourceFil2 = preloadMap[sourceFile]) == null ? void 0 : _preloadMap$sourceFil2.sync) || []
973
940
  },
974
941
  css: {
975
942
  sync: [],
@@ -998,14 +965,13 @@ const Manifest = () => {
998
965
  // "api": "@mf-types.d.ts"
999
966
  },
1000
967
  globalName: name,
1001
- pluginVersion: '0.2.5',
1002
- publicPath
968
+ pluginVersion: '0.2.5'
1003
969
  },
1004
970
  shared,
1005
971
  remotes,
1006
972
  exposes
1007
973
  };
1008
- return JSON.stringify(result);
974
+ return result;
1009
975
  }
1010
976
  };
1011
977
 
@@ -1014,20 +980,21 @@ let _resolve,
1014
980
  _resolve = resolve;
1015
981
  });
1016
982
  let parsePromise = promise;
983
+ let exposesParseEnd = false;
1017
984
  const parseStartSet = new Set();
1018
985
  const parseEndSet = new Set();
1019
986
  function pluginModuleParseEnd (excludeFn) {
1020
987
  return [{
1021
- name: "_",
1022
- apply: "serve",
988
+ name: '_',
989
+ apply: 'serve',
1023
990
  config() {
1024
991
  // No waiting in development mode
1025
992
  _resolve(1);
1026
993
  }
1027
994
  }, {
1028
- enforce: "pre",
1029
- name: "parseStart",
1030
- apply: "build",
995
+ enforce: 'pre',
996
+ name: 'parseStart',
997
+ apply: 'build',
1031
998
  load(id) {
1032
999
  if (excludeFn(id)) {
1033
1000
  return;
@@ -1035,16 +1002,20 @@ function pluginModuleParseEnd (excludeFn) {
1035
1002
  parseStartSet.add(id);
1036
1003
  }
1037
1004
  }, {
1038
- enforce: "post",
1039
- name: "parseEnd",
1040
- apply: "build",
1005
+ enforce: 'post',
1006
+ name: 'parseEnd',
1007
+ apply: 'build',
1041
1008
  moduleParsed(module) {
1042
1009
  const id = module.id;
1043
1010
  if (excludeFn(id)) {
1044
1011
  return;
1045
1012
  }
1013
+ if (id === VIRTUAL_EXPOSES) {
1014
+ // 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.
1015
+ exposesParseEnd = true;
1016
+ }
1046
1017
  parseEndSet.add(id);
1047
- if (parseStartSet.size === parseEndSet.size) {
1018
+ if (exposesParseEnd && parseStartSet.size === parseEndSet.size) {
1048
1019
  _resolve(1);
1049
1020
  }
1050
1021
  }
@@ -1060,17 +1031,26 @@ function pluginProxyRemoteEntry () {
1060
1031
  if (id === REMOTE_ENTRY_ID) {
1061
1032
  return REMOTE_ENTRY_ID;
1062
1033
  }
1034
+ if (id === VIRTUAL_EXPOSES) {
1035
+ return VIRTUAL_EXPOSES;
1036
+ }
1063
1037
  },
1064
1038
  load(id) {
1065
1039
  if (id === REMOTE_ENTRY_ID) {
1066
1040
  return parsePromise.then(_ => generateRemoteEntry(getNormalizeModuleFederationOptions()));
1067
1041
  }
1042
+ if (id === VIRTUAL_EXPOSES) {
1043
+ return generateExposes();
1044
+ }
1068
1045
  },
1069
1046
  async transform(code, id) {
1070
1047
  if (!filter(id)) return;
1071
1048
  if (id.includes(REMOTE_ENTRY_ID)) {
1072
1049
  return parsePromise.then(_ => generateRemoteEntry(getNormalizeModuleFederationOptions()));
1073
1050
  }
1051
+ if (id === VIRTUAL_EXPOSES) {
1052
+ return generateExposes();
1053
+ }
1074
1054
  }
1075
1055
  };
1076
1056
  }
@@ -1081,7 +1061,7 @@ function pluginProxyRemotes (options) {
1081
1061
  remotes
1082
1062
  } = options;
1083
1063
  return {
1084
- name: "proxyRemotes",
1064
+ name: 'proxyRemotes',
1085
1065
  config(config, {
1086
1066
  command: _command
1087
1067
  }) {
@@ -1089,7 +1069,7 @@ function pluginProxyRemotes (options) {
1089
1069
  const remote = remotes[key];
1090
1070
  config.resolve.alias.push({
1091
1071
  find: new RegExp(`^(${remote.name}(\/.*|$))`),
1092
- replacement: "$1",
1072
+ replacement: '$1',
1093
1073
  customResolver(source) {
1094
1074
  const remoteModule = getRemoteVirtualModule(source, _command);
1095
1075
  addUsedRemote(remote.name, source);
@@ -1143,8 +1123,8 @@ function proxySharedModule(options) {
1143
1123
  } = options;
1144
1124
  let _config;
1145
1125
  return [{
1146
- name: "generateLocalSharedImportMap",
1147
- enforce: "post",
1126
+ name: 'generateLocalSharedImportMap',
1127
+ enforce: 'post',
1148
1128
  load(id) {
1149
1129
  if (id.includes(getLocalSharedImportMapPath())) {
1150
1130
  return parsePromise.then(_ => generateLocalSharedImportMap());
@@ -1165,11 +1145,11 @@ function proxySharedModule(options) {
1165
1145
  command
1166
1146
  }) {
1167
1147
  config.resolve.alias.push(...Object.keys(shared).map(key => {
1168
- const pattern = key.endsWith("/") ? `(^${key.replace(/\/$/, "")}(\/.+)?$)` : `(^${key}$)`;
1148
+ const pattern = key.endsWith('/') ? `(^${key.replace(/\/$/, '')}(\/.+)?$)` : `(^${key}$)`;
1169
1149
  return {
1170
1150
  // Intercept all shared requests and proxy them to loadShare
1171
1151
  find: new RegExp(pattern),
1172
- replacement: "$1",
1152
+ replacement: '$1',
1173
1153
  customResolver(source, importer) {
1174
1154
  if (/\.css$/.test(source)) return;
1175
1155
  const loadSharePath = getLoadShareModulePath(source);
@@ -1183,7 +1163,7 @@ function proxySharedModule(options) {
1183
1163
  }));
1184
1164
  const savePrebuild = new PromiseStore();
1185
1165
  config.resolve.alias.push(...Object.keys(shared).map(key => {
1186
- return command === "build" ? {
1166
+ return command === 'build' ? {
1187
1167
  find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
1188
1168
  replacement: function ($1) {
1189
1169
  const pkgName = VirtualModule.findModule(PREBUILD_TAG, $1).name;
@@ -1191,7 +1171,7 @@ function proxySharedModule(options) {
1191
1171
  }
1192
1172
  } : {
1193
1173
  find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
1194
- replacement: "$1",
1174
+ replacement: '$1',
1195
1175
  async customResolver(source, importer) {
1196
1176
  const pkgName = VirtualModule.findModule(PREBUILD_TAG, source).name;
1197
1177
  const result = await this.resolve(pkgName).then(item => item.id);
@@ -1206,8 +1186,8 @@ function proxySharedModule(options) {
1206
1186
  }));
1207
1187
  }
1208
1188
  }, {
1209
- name: "watchLocalSharedImportMap",
1210
- apply: "serve",
1189
+ name: 'watchLocalSharedImportMap',
1190
+ apply: 'serve',
1211
1191
  config(config) {
1212
1192
  config.optimizeDeps = defu(config.optimizeDeps, {
1213
1193
  exclude: [getLocalSharedImportMapPath()]
@@ -1271,7 +1251,7 @@ function federation(mfUserOptions) {
1271
1251
  shared,
1272
1252
  filename
1273
1253
  } = options;
1274
- if (!name) throw new Error("name is required");
1254
+ if (!name) throw new Error('name is required');
1275
1255
  return [aliasToArrayPlugin, normalizeOptimizeDepsPlugin, ...addEntry({
1276
1256
  entryName: 'remoteEntry',
1277
1257
  entryPath: REMOTE_ENTRY_ID,
@@ -1279,6 +1259,9 @@ function federation(mfUserOptions) {
1279
1259
  }), ...addEntry({
1280
1260
  entryName: 'hostInit',
1281
1261
  entryPath: getHostAutoInitPath()
1262
+ }), ...addEntry({
1263
+ entryName: 'virtualExposes',
1264
+ entryPath: VIRTUAL_EXPOSES
1282
1265
  }), pluginProxyRemoteEntry(), pluginProxyRemotes(options), ...pluginModuleParseEnd(id => {
1283
1266
  return id.includes(getHostAutoInitImportId()) || id.includes(REMOTE_ENTRY_ID) || id.includes(getLocalSharedImportMapPath());
1284
1267
  }), ...proxySharedModule({
@@ -1290,6 +1273,7 @@ function federation(mfUserOptions) {
1290
1273
  command: _command
1291
1274
  }) {
1292
1275
  var _config$optimizeDeps;
1276
+ // TODO: singleton
1293
1277
  config.resolve.alias.push({
1294
1278
  find: '@module-federation/runtime',
1295
1279
  replacement: require.resolve('@module-federation/runtime')