@module-federation/vite 1.0.0-alpha-2f53b4e → 1.0.0-alpha-b1bba84

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.
@@ -1,29 +1,36 @@
1
1
  import * as fs from 'fs';
2
- import { existsSync, mkdirSync, writeFileSync, writeFile } from 'fs';
2
+ import { mkdirSync, writeFileSync, existsSync, writeFile } from 'fs';
3
3
  import * as path from 'pathe';
4
- import path__default, { parse, join, dirname, resolve } from 'pathe';
4
+ import path__default, { parse, join, dirname, resolve, relative } from 'pathe';
5
5
  import { createFilter } from '@rollup/pluginutils';
6
- import { defu } from 'defu';
7
6
  import { walk } from 'estree-walker';
8
7
  import MagicString from 'magic-string';
8
+ import { defu } from 'defu';
9
9
 
10
10
  const addEntry = ({
11
11
  entryName,
12
12
  entryPath,
13
13
  fileName
14
14
  }) => {
15
+ const devEntryPath = entryPath.startsWith("virtual:mf") ? "/@id/" + entryPath : entryPath;
15
16
  let entryFiles = [];
16
17
  let htmlFilePath;
18
+ let _command;
17
19
  return [{
18
20
  name: 'add-entry',
19
21
  apply: "serve",
22
+ config(config, {
23
+ command
24
+ }) {
25
+ _command = command;
26
+ },
20
27
  configureServer(server) {
21
28
  var _server$httpServer;
22
29
  (_server$httpServer = server.httpServer) == null || _server$httpServer.once == null || _server$httpServer.once('listening', () => {
23
30
  const {
24
31
  port
25
32
  } = server.config.server;
26
- fetch(path.join(`http://localhost:${port}`, `${entryPath}`)).catch(e => {});
33
+ fetch(path.join(`http://localhost:${port}`, `${devEntryPath}`)).catch(e => {});
27
34
  });
28
35
  server.middlewares.use((req, res, next) => {
29
36
  if (!fileName) {
@@ -31,18 +38,17 @@ const addEntry = ({
31
38
  return;
32
39
  }
33
40
  if (req.url && req.url.startsWith(fileName.replace(/^\/?/, '/'))) {
34
- req.url = entryPath;
41
+ req.url = devEntryPath;
35
42
  }
36
43
  next();
37
44
  });
38
45
  },
39
46
  transformIndexHtml(c) {
40
- return c.replace('<head>', `<head><script type="module" src=${JSON.stringify(entryPath.replace(/.+?\:([/\\])[/\\]?/, '$1').replace(/\\\\?/g, '/'))}></script>`);
47
+ return c.replace('<head>', `<head><script type="module" src=${JSON.stringify(devEntryPath.replace(/.+?\:([/\\])[/\\]?/, '$1').replace(/\\\\?/g, '/'))}></script>`);
41
48
  }
42
49
  }, {
43
50
  name: "add-entry",
44
51
  enforce: "post",
45
- apply: "build",
46
52
  configResolved(config) {
47
53
  const inputOptions = config.build.rollupOptions.input;
48
54
  if (!inputOptions) {
@@ -59,6 +65,7 @@ const addEntry = ({
59
65
  }
60
66
  },
61
67
  buildStart() {
68
+ if (_command === "serve") return;
62
69
  const hasHash = fileName == null || fileName.includes == null ? void 0 : fileName.includes("[hash");
63
70
  this.emitFile({
64
71
  name: entryName,
@@ -87,46 +94,81 @@ const addEntry = ({
87
94
  }];
88
95
  };
89
96
 
90
- let _resolve,
91
- promise = new Promise((resolve, reject) => {
92
- _resolve = resolve;
93
- });
94
- let parsePromise = promise;
95
- const parseStartSet = new Set();
96
- const parseEndSet = new Set();
97
- function pluginModuleParseEnd (excludeFn) {
98
- return [{
99
- name: "_",
97
+ /**
98
+ * Solve the problem that dev mode dependency prebunding does not support top-level await syntax
99
+ */
100
+ function PluginDevProxyModuleTopLevelAwait() {
101
+ const filterFunction = createFilter();
102
+ return {
103
+ name: "dev-proxy-module-top-level-await",
100
104
  apply: "serve",
101
- config() {
102
- // No waiting in development mode
103
- _resolve(1);
104
- }
105
- }, {
106
- enforce: "pre",
107
- name: "parseStart",
108
- apply: "build",
109
- load(id) {
110
- if (excludeFn(id)) {
111
- return;
112
- }
113
- parseStartSet.add(id);
114
- }
115
- }, {
116
- enforce: "post",
117
- name: "parseEnd",
118
- apply: "build",
119
- moduleParsed(module) {
120
- const id = module.id;
121
- if (excludeFn(id)) {
122
- return;
105
+ transform(code, id) {
106
+ if (!code.includes("/*mf top-level-await placeholder replacement mf*/")) {
107
+ return null;
123
108
  }
124
- parseEndSet.add(id);
125
- if (parseStartSet.size === parseEndSet.size) {
126
- _resolve(1);
109
+ if (!filterFunction(id)) return null;
110
+ let ast;
111
+ try {
112
+ ast = this.parse(code, {
113
+ allowReturnOutsideFunction: true
114
+ });
115
+ } catch (e) {
116
+ throw new Error(`${id}: ${e}`);
127
117
  }
118
+ const magicString = new MagicString(code);
119
+ walk(ast, {
120
+ enter(node) {
121
+ if (node.type === 'ExportNamedDeclaration' && node.specifiers) {
122
+ const exportSpecifiers = node.specifiers.map(specifier => specifier.exported.name);
123
+ const proxyStatements = exportSpecifiers.map(name => `
124
+ const __mfproxy__await${name} = await ${name}();
125
+ const __mfproxy__${name} = () => __mfproxy__await${name};
126
+ `).join('\n');
127
+ const exportStatements = exportSpecifiers.map(name => `__mfproxy__${name} as ${name}`).join(', ');
128
+ const start = node.start;
129
+ const end = node.end;
130
+ const replacement = `${proxyStatements}\nexport { ${exportStatements} };`;
131
+ magicString.overwrite(start, end, replacement);
132
+ }
133
+ if (node.type === 'ExportDefaultDeclaration') {
134
+ const declaration = node.declaration;
135
+ const start = node.start;
136
+ const end = node.end;
137
+ let proxyStatement;
138
+ let exportStatement = 'default';
139
+ if (declaration.type === 'Identifier') {
140
+ // example: export default foo;
141
+ proxyStatement = `
142
+ const __mfproxy__awaitdefault = await ${declaration.name}();
143
+ const __mfproxy__default = __mfproxy__awaitdefault;
144
+ `;
145
+ } else if (declaration.type === 'CallExpression' || declaration.type === 'FunctionDeclaration') {
146
+ // example: export default someFunction();
147
+ const declarationCode = code.slice(declaration.start, declaration.end);
148
+ proxyStatement = `
149
+ const __mfproxy__awaitdefault = await (${declarationCode});
150
+ const __mfproxy__default = __mfproxy__awaitdefault;
151
+ `;
152
+ } else {
153
+ // other
154
+ proxyStatement = `
155
+ const __mfproxy__awaitdefault = await (${code.slice(declaration.start, declaration.end)});
156
+ const __mfproxy__default = __mfproxy__awaitdefault;
157
+ `;
158
+ }
159
+ const replacement = `${proxyStatement}\nexport { __mfproxy__default as ${exportStatement} };`;
160
+ magicString.overwrite(start, end, replacement);
161
+ }
162
+ }
163
+ });
164
+ return {
165
+ code: magicString.toString(),
166
+ map: magicString.generateMap({
167
+ hires: true
168
+ })
169
+ };
128
170
  }
129
- }];
171
+ };
130
172
  }
131
173
 
132
174
  function normalizeExposesItem(key, item) {
@@ -178,7 +220,7 @@ function normalizeRemoteItem(key, remote) {
178
220
  entryGlobalName: key
179
221
  }, remote);
180
222
  }
181
- function removePathFromNpmPackage$1(packageString) {
223
+ function removePathFromNpmPackage(packageString) {
182
224
  // 匹配npm包名的正则表达式,忽略路径部分
183
225
  const regex = /^(?:@[^/]+\/)?[^/]+/;
184
226
  // 使用正则表达式匹配并提取包名
@@ -189,7 +231,7 @@ function removePathFromNpmPackage$1(packageString) {
189
231
  function normalizeShareItem(key, shareItem) {
190
232
  let version;
191
233
  try {
192
- version = require(path.join(removePathFromNpmPackage$1(key), 'package.json')).version;
234
+ version = require(path.join(removePathFromNpmPackage(key), 'package.json')).version;
193
235
  } catch (e) {
194
236
  console.log(e);
195
237
  }
@@ -237,10 +279,25 @@ function normalizeLibrary(library) {
237
279
  if (!library) return undefined;
238
280
  return library;
239
281
  }
282
+ function normalizeManifest(manifest = false) {
283
+ if (typeof manifest === "boolean") {
284
+ return manifest;
285
+ }
286
+ return Object.assign({
287
+ filePath: "",
288
+ disableAssetsAnalyze: false,
289
+ fileName: "mf-manifest.json"
290
+ }, manifest);
291
+ }
240
292
  let config;
241
293
  function getNormalizeModuleFederationOptions() {
242
294
  return config;
243
295
  }
296
+ function getNormalizeShareItem(key) {
297
+ const options = getNormalizeModuleFederationOptions();
298
+ const shareItem = options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + "/"];
299
+ return shareItem;
300
+ }
244
301
  function normalizeModuleFederationOptions(options) {
245
302
  return config = {
246
303
  exposes: normalizeExposes(options.exposes),
@@ -255,7 +312,7 @@ function normalizeModuleFederationOptions(options) {
255
312
  runtimePlugins: options.runtimePlugins || [],
256
313
  getPublicPath: options.getPublicPath,
257
314
  implementation: options.implementation,
258
- manifest: options.manifest,
315
+ manifest: normalizeManifest(options.manifest),
259
316
  dev: options.dev,
260
317
  dts: options.dts
261
318
  };
@@ -270,33 +327,43 @@ function normalizeModuleFederationOptions(options) {
270
327
  * . => 4
271
328
  */
272
329
  /**
273
- * @param {*} name "@scope/xx-xx.xx" => "__$1__scope__$2__xx__$3__xx$__4__xx"
330
+ * Encodes a package name into a valid file name.
331
+ * @param {string} name - The package name, e.g., "@scope/xx-xx.xx".
332
+ * @returns {string} - The encoded file name.
274
333
  */
275
334
  function packageNameEncode(name) {
276
335
  if (typeof name !== "string") throw new Error("A string package name is required");
277
- return name.replace(/\@/g, "__$1__").replace(/\//g, "__$2__").replace(/\-/g, "__$3__").replace(/\./g, "__$4__");
336
+ return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
278
337
  }
279
338
  /**
280
- * @param {*} global "__$1__scope__$2__xx__$3__xx$__4__xx" => "@scope/xx-xx.xx"
339
+ * Decodes an encoded file name back to the original package name.
340
+ * @param {string} encoded - The encoded file name, e.g., "_mf_0_scope_mf_1_xx_mf_2_xx_mf_3_xx".
341
+ * @returns {string} - The decoded package name.
281
342
  */
282
- function packageNameDecode(global) {
283
- if (typeof global !== "string") throw new Error("A string global variable name is required");
284
- return global.replace(/\_\_\$1\_\_/g, "@").replace(/\_\_\$2\_\_/g, "/").replace(/\_\_\$3\_\_/g, "-").replace(/\_\_\$4\_\_/g, ".");
343
+ function packageNameDecode(encoded) {
344
+ if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
345
+ return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
285
346
  }
286
- function removePathFromNpmPackage(packageString) {
287
- // Regular expression to match npm package name, ignoring path parts
288
- const regex = /^(?:@[^/]+\/)?[^/]+/;
289
- // Use regular expression to match and extract the package name
290
- const match = packageString.match(regex);
291
- // Return the matched package name or the original string if no match is found
292
- return match ? match[0] : packageString;
347
+
348
+ /**
349
+ * https://github.com/module-federation/vite/issues/68
350
+ */
351
+ function getLocalSharedImportMapPath_windows() {
352
+ const {
353
+ name
354
+ } = getNormalizeModuleFederationOptions();
355
+ return path__default.resolve(".__mf__win", packageNameEncode(name), "localSharedImportMap");
293
356
  }
294
- function getExtFromNpmPackage(packageString) {
295
- const pkgName = removePathFromNpmPackage(packageString);
296
- const subpath = packageString.replace(pkgName, "");
297
- const parts = subpath.split('.');
298
- const ext = parts.length > 1 ? "." + parts.pop() : undefined;
299
- return ext;
357
+ function writeLocalSharedImportMap_windows(content) {
358
+ const localSharedImportMapId = getLocalSharedImportMapPath_windows();
359
+ createFile(localSharedImportMapId + ".js", "\n// Windows temporarily needs this file, https://github.com/module-federation/vite/issues/68\n" + content);
360
+ }
361
+ function createFile(filePath, content) {
362
+ const dir = path__default.dirname(filePath);
363
+ mkdirSync(dir, {
364
+ recursive: true
365
+ });
366
+ writeFileSync(filePath, content);
300
367
  }
301
368
 
302
369
  const nodeModulesDir = function findNodeModulesDir(startDir = process.cwd()) {
@@ -319,25 +386,38 @@ writeFileSync(resolve(nodeModulesDir, virtualPackageName, "package.json"), JSON.
319
386
  name: virtualPackageName,
320
387
  main: "empty.js"
321
388
  }));
389
+ const patternMap = {};
390
+ const cacheMap = {};
322
391
  /**
323
392
  * Physically generate files as virtual modules under node_modules/__mf__virtual/*
324
393
  */
325
394
  class VirtualModule {
326
- constructor(name, ext = ".js") {
327
- this.originName = void 0;
395
+ static findModule(tag, str = "") {
396
+ if (!patternMap[tag]) patternMap[tag] = new RegExp(`(.*${packageNameEncode(tag)}(.+?)${packageNameEncode(tag)}.*)`);
397
+ const moduleName = (str.match(patternMap[tag]) || [])[2];
398
+ if (moduleName) return cacheMap[tag][packageNameDecode(moduleName)];
399
+ return undefined;
400
+ }
401
+ constructor(name, tag = '__mf_v__', suffix = "") {
402
+ var _name$split$slice$pop;
403
+ this.name = void 0;
404
+ this.tag = void 0;
405
+ this.suffix = void 0;
328
406
  this.inited = false;
329
- this.ext = void 0;
330
- this.originName = name;
331
- this.ext = ext;
407
+ this.name = name;
408
+ this.tag = tag;
409
+ this.suffix = suffix || ((_name$split$slice$pop = name.split(".").slice(1).pop()) == null ? void 0 : _name$split$slice$pop.replace(/(.)/, ".$1")) || ".js";
410
+ if (!cacheMap[this.tag]) cacheMap[this.tag] = {};
411
+ cacheMap[this.tag][this.name] = this;
332
412
  }
333
413
  getPath() {
334
414
  return resolve(nodeModulesDir, this.getImportId());
335
415
  }
336
416
  getImportId() {
337
417
  const {
338
- name
418
+ name: mfName
339
419
  } = getNormalizeModuleFederationOptions();
340
- return `${virtualPackageName}/${packageNameEncode(name)}-${packageNameEncode(this.originName)}${this.ext}`;
420
+ return `${virtualPackageName}/${packageNameEncode(`${mfName}${this.tag}${this.name}${this.tag}`)}${this.suffix}`;
341
421
  }
342
422
  writeSync(code, force) {
343
423
  if (!force && this.inited) return;
@@ -351,25 +431,50 @@ class VirtualModule {
351
431
  }
352
432
  }
353
433
 
354
- /**
355
- * https://github.com/module-federation/vite/issues/68
356
- */
357
- function getLocalSharedImportMapPath_windows() {
358
- const {
359
- name
360
- } = getNormalizeModuleFederationOptions();
361
- return path__default.resolve(".__mf__win", packageNameEncode(name), "localSharedImportMap");
434
+ const virtualRuntimeInitStatus = new VirtualModule("runtimeInit");
435
+ function writeRuntimeInitStatus() {
436
+ virtualRuntimeInitStatus.writeSync(`
437
+ let initResolve, initReject
438
+ const initPromise = new Promise((re, rj) => {
439
+ initResolve = re
440
+ initReject = rj
441
+ })
442
+ export {
443
+ initPromise,
444
+ initResolve,
445
+ initReject
446
+ }
447
+ `);
362
448
  }
363
- function writeLocalSharedImportMap_windows(content) {
364
- const localSharedImportMapId = getLocalSharedImportMapPath_windows();
365
- createFile(localSharedImportMapId + ".js", "\n// Windows temporarily needs this file, https://github.com/module-federation/vite/issues/68\n" + content);
449
+
450
+ const cacheRemoteMap = {};
451
+ const LOAD_REMOTE_TAG = '__loadRemote__';
452
+ function getRemoteVirtualModule(remote, command) {
453
+ if (!cacheRemoteMap[remote]) {
454
+ cacheRemoteMap[remote] = new VirtualModule(remote, LOAD_REMOTE_TAG, ".js");
455
+ cacheRemoteMap[remote].writeSync(generateRemotes(remote, command));
456
+ }
457
+ const virtual = cacheRemoteMap[remote];
458
+ return virtual;
366
459
  }
367
- function createFile(filePath, content) {
368
- const dir = path__default.dirname(filePath);
369
- mkdirSync(dir, {
370
- recursive: true
371
- });
372
- writeFileSync(filePath, content);
460
+ const usedRemotesMap = {
461
+ // remote1: {remote1/App, remote1, remote1/Button}
462
+ };
463
+ function addUsedRemote(remoteKey, remoteModule) {
464
+ if (!usedRemotesMap[remoteKey]) usedRemotesMap[remoteKey] = new Set();
465
+ usedRemotesMap[remoteKey].add(remoteModule);
466
+ }
467
+ function getUsedRemotesMap() {
468
+ return usedRemotesMap;
469
+ }
470
+ function generateRemotes(id, command) {
471
+ return `
472
+ const {loadRemote} = require("@module-federation/runtime")
473
+ const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")
474
+ const res = initPromise.then(_ => loadRemote(${JSON.stringify(id)}))
475
+ const exportModule = ${command !== "build" ? "/*mf top-level-await placeholder replacement mf*/" : "await "}initPromise.then(_ => res)
476
+ module.exports = exportModule
477
+ `;
373
478
  }
374
479
 
375
480
  /**
@@ -381,17 +486,47 @@ function createFile(filePath, content) {
381
486
  const preBuildCacheMap = {};
382
487
  const PREBUILD_TAG = "__prebuild__";
383
488
  function writePreBuildLibPath(pkg) {
384
- if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(PREBUILD_TAG + pkg, getExtFromNpmPackage(pkg));
489
+ if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
385
490
  preBuildCacheMap[pkg].writeSync("");
386
491
  }
387
492
  function getPreBuildLibImportId(pkg) {
388
- if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(PREBUILD_TAG + pkg, getExtFromNpmPackage(pkg));
493
+ if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
389
494
  const importId = preBuildCacheMap[pkg].getImportId();
390
495
  return importId;
391
496
  }
392
- let shareds = new Set();
393
- function addShare(pkg) {
394
- shareds.add(pkg);
497
+ // *** __loadShare__
498
+ const LOAD_SHARE_TAG = "__loadShare__";
499
+ const loadShareCacheMap = {};
500
+ function getLoadShareModulePath(pkg) {
501
+ if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, ".js");
502
+ const filepath = loadShareCacheMap[pkg].getPath();
503
+ return filepath;
504
+ }
505
+ function writeLoadShareModule(pkg, shareItem, command) {
506
+ loadShareCacheMap[pkg].writeSync(`
507
+
508
+ ;() => import(${JSON.stringify(getPreBuildLibImportId(pkg))}).catch(() => {});
509
+ // dev uses dynamic import to separate chunks
510
+ ${command !== "build" ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ''}
511
+ const {loadShare} = require("@module-federation/runtime")
512
+ const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")
513
+ const res = initPromise.then(_ => loadShare(${JSON.stringify(pkg)}, {
514
+ customShareInfo: {shareConfig:{
515
+ singleton: ${shareItem.shareConfig.singleton},
516
+ strictVersion: ${shareItem.shareConfig.strictVersion},
517
+ requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
518
+ }}}))
519
+ const exportModule = ${command !== "build" ? "/*mf top-level-await placeholder replacement mf*/" : "await "}res.then(factory => factory())
520
+ module.exports = exportModule
521
+ `);
522
+ }
523
+
524
+ let usedShares = new Set();
525
+ function getUsedShares() {
526
+ return usedShares;
527
+ }
528
+ function addUsedShares(pkg) {
529
+ usedShares.add(pkg);
395
530
  }
396
531
  // *** Expose locally provided shared modules here
397
532
  const localSharedImportMapModule = new VirtualModule("localSharedImportMap");
@@ -401,32 +536,32 @@ function getLocalSharedImportMapPath() {
401
536
  }
402
537
  return localSharedImportMapModule.getPath();
403
538
  }
404
- let prevSharedCount = 0;
405
- async function writeLocalSharedImportMap() {
406
- const sharedCount = shareds.size;
539
+ let prevSharedCount;
540
+ function writeLocalSharedImportMap() {
541
+ const sharedCount = getUsedShares().size;
407
542
  if (prevSharedCount !== sharedCount) {
408
543
  prevSharedCount = sharedCount;
409
544
  if (process.platform === "win32") {
410
- return writeLocalSharedImportMap_windows(await generateLocalSharedImportMap());
545
+ writeLocalSharedImportMap_windows(generateLocalSharedImportMap());
546
+ } else {
547
+ localSharedImportMapModule.writeSync(generateLocalSharedImportMap(), true);
411
548
  }
412
- return localSharedImportMapModule.writeSync(await generateLocalSharedImportMap(), true);
413
549
  }
414
550
  }
415
- async function generateLocalSharedImportMap() {
416
- await parsePromise;
551
+ function generateLocalSharedImportMap() {
417
552
  const options = getNormalizeModuleFederationOptions();
418
553
  return `
419
- const localSharedImportMap = {
420
- ${Array.from(shareds).map(pkg => `
554
+ const importMap = {
555
+ ${Array.from(getUsedShares()).map(pkg => `
421
556
  ${JSON.stringify(pkg)}: async () => {
422
557
  let pkg = await import("${getPreBuildLibImportId(pkg)}")
423
558
  return pkg
424
559
  }
425
560
  `).join(",")}
426
561
  }
427
- const localShared = {
428
- ${Array.from(shareds).map(key => {
429
- const shareItem = options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + "/"];
562
+ const usedShared = {
563
+ ${Array.from(getUsedShares()).map(key => {
564
+ const shareItem = getNormalizeShareItem(key);
430
565
  return `
431
566
  ${JSON.stringify(key)}: {
432
567
  name: ${JSON.stringify(key)},
@@ -435,8 +570,8 @@ async function generateLocalSharedImportMap() {
435
570
  loaded: false,
436
571
  from: ${JSON.stringify(options.name)},
437
572
  async get () {
438
- localShared[${JSON.stringify(key)}].loaded = true
439
- const {${JSON.stringify(key)}: pkgDynamicImport} = localSharedImportMap
573
+ usedShared[${JSON.stringify(key)}].loaded = true
574
+ const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
440
575
  const res = await pkgDynamicImport()
441
576
  const exportModule = {...res}
442
577
  // All npm packages pre-built by vite will be converted to esm
@@ -456,40 +591,29 @@ async function generateLocalSharedImportMap() {
456
591
  `;
457
592
  }).join(',')}
458
593
  }
459
- export default localShared
594
+ const usedRemotes = [${Object.keys(getUsedRemotesMap()).map(key => {
595
+ const remote = options.remotes[key];
596
+ return `
597
+ {
598
+ entryGlobalName: ${JSON.stringify(remote.entryGlobalName)},
599
+ name: ${JSON.stringify(remote.name)},
600
+ type: ${JSON.stringify(remote.type)},
601
+ entry: ${JSON.stringify(remote.entry)},
602
+ }
603
+ `;
604
+ }).join(',')}
605
+ ]
606
+ export {
607
+ usedShared,
608
+ usedRemotes
609
+ }
460
610
  `;
461
611
  }
462
- // *** __loadShare__
463
- const LOAD_SHARE_TAG = "__loadShare__";
464
- const loadShareCacheMap = {};
465
- function getLoadShareModulePath(pkg) {
466
- if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(LOAD_SHARE_TAG + pkg);
467
- const filepath = loadShareCacheMap[pkg].getPath();
468
- return filepath;
469
- }
470
- function writeLoadShareModule(pkg, shareItem, command) {
471
- loadShareCacheMap[pkg].writeSync(`
472
- () => import(${JSON.stringify(getPreBuildLibImportId(pkg))}).catch(() => {});
473
- // dev uses dynamic import to separate chunks
474
- ${command !== "build" ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ''}
475
- const {loadShare} = require("@module-federation/runtime")
476
- const res = loadShare(${JSON.stringify(pkg)}, {
477
- customShareInfo: {shareConfig:{
478
- singleton: ${shareItem.shareConfig.singleton},
479
- strictVersion: ${shareItem.shareConfig.strictVersion},
480
- requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
481
- }}})
482
- const exportModule = ${command !== "build" ? "/*mf top-level-await placeholder replacement mf*/" : "await "}res.then(factory => factory())
483
- module.exports = exportModule
484
- `);
485
- }
486
-
487
- const REMOTE_ENTRY_ID = 'REMOTE_ENTRY_ID';
612
+ const REMOTE_ENTRY_ID = 'virtual:mf-REMOTE_ENTRY_ID';
488
613
  function generateRemoteEntry(options) {
489
614
  const pluginImportNames = options.runtimePlugins.map((p, i) => [`$runtimePlugin_${i}`, `import $runtimePlugin_${i} from "${p}";`]);
490
615
  return `
491
616
  import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
492
-
493
617
  ${pluginImportNames.map(item => item[1]).join('\n')}
494
618
 
495
619
  const exposesMap = {
@@ -508,26 +632,19 @@ function generateRemoteEntry(options) {
508
632
  `;
509
633
  }).join(',')}
510
634
  }
511
- import localSharedImportMap from "${getLocalSharedImportMapPath()}"
635
+ import {usedShared, usedRemotes} from "${getLocalSharedImportMapPath()}"
636
+ import {
637
+ initResolve
638
+ } from "${virtualRuntimeInitStatus.getImportId()}"
512
639
  async function init(shared = {}) {
513
640
  const initRes = runtimeInit({
514
641
  name: ${JSON.stringify(options.name)},
515
- remotes: [${Object.keys(options.remotes).map(key => {
516
- const remote = options.remotes[key];
517
- return `
518
- {
519
- entryGlobalName: ${JSON.stringify(remote.entryGlobalName)},
520
- name: ${JSON.stringify(remote.name)},
521
- type: ${JSON.stringify(remote.type)},
522
- entry: ${JSON.stringify(remote.entry)},
523
- }
524
- `;
525
- }).join(',')}
526
- ],
527
- shared: localSharedImportMap,
642
+ remotes: usedRemotes,
643
+ shared: usedShared,
528
644
  plugins: [${pluginImportNames.map(item => `${item[0]}()`).join(', ')}]
529
645
  });
530
646
  initRes.initShareScopeMap('${options.shareScope}', shared);
647
+ initResolve(initRes)
531
648
  return initRes
532
649
  }
533
650
 
@@ -541,19 +658,6 @@ function generateRemoteEntry(options) {
541
658
  }
542
659
  `;
543
660
  }
544
- const wrapRemoteEntryModule = new VirtualModule("wrapRemoteEntry");
545
- function writeWrapRemoteEntry() {
546
- wrapRemoteEntryModule.writeSync(`
547
- import {init, get} from "${REMOTE_ENTRY_ID}"
548
- export {init, get}
549
- `);
550
- }
551
- function getWrapRemoteEntryImportId() {
552
- return wrapRemoteEntryModule.getImportId();
553
- }
554
- function getWrapRemoteEntryPath() {
555
- return wrapRemoteEntryModule.getPath();
556
- }
557
661
  /**
558
662
  * Inject entry file, automatically init when used as host,
559
663
  * and will not inject remoteEntry
@@ -572,37 +676,374 @@ function getHostAutoInitPath() {
572
676
  return hostAutoInitModule.getPath();
573
677
  }
574
678
 
575
- const remoteVirtualModule = new VirtualModule("remoteModule");
576
- function writeRemote() {
577
- remoteVirtualModule.writeSync("");
578
- }
579
- function generateRemotes(id, command) {
580
- return {
581
- code: `
582
- import {loadRemote} from "@module-federation/runtime"
583
- const exportModule = await loadRemote(${JSON.stringify(id)})
584
- ${command === "build" && `
585
- export default 'default' in (exportModule || {}) ? exportModule.default : undefined
586
- export const __mf__dynamicExports = exportModule
587
- ` || ""}
588
- ${command !== "build" && `
589
- export default exportModule
590
- ` || ""}
591
- `,
592
- map: null,
593
- // TODO: vite dev mode invalid, use optimizeDeps.needsInterop
594
- syntheticNamedExports: '__mf__dynamicExports'
595
- };
596
- }
597
-
598
679
  function initVirtualModules() {
599
680
  writeLocalSharedImportMap();
600
- writeWrapRemoteEntry();
601
681
  writeHostAutoInit();
602
- writeRemote();
682
+ writeRuntimeInitStatus();
603
683
  }
604
684
 
605
- const filter$1 = createFilter();
685
+ const Manifest = () => {
686
+ const mfOptions = getNormalizeModuleFederationOptions();
687
+ const {
688
+ name,
689
+ filename,
690
+ manifest: manifestOptions
691
+ } = mfOptions;
692
+ let mfManifestName = "";
693
+ if (manifestOptions === true) {
694
+ mfManifestName = "mf-manifest.json";
695
+ }
696
+ if (typeof manifestOptions !== "boolean") {
697
+ mfManifestName = join((manifestOptions == null ? void 0 : manifestOptions.filePath) || "", (manifestOptions == null ? void 0 : manifestOptions.fileName) || "");
698
+ }
699
+ let extensions;
700
+ let root;
701
+ let remoteEntryFile;
702
+ return [{
703
+ name: 'moddule-federation-manifest',
704
+ apply: 'serve',
705
+ configureServer(server) {
706
+ server.middlewares.use((req, res, next) => {
707
+ if (!mfManifestName) {
708
+ next();
709
+ return;
710
+ }
711
+ if (req.url === mfManifestName.replace(/^\/?/, "/")) {
712
+ res.setHeader('Content-Type', 'application/json');
713
+ res.setHeader('Access-Control-Allow-Origin', '*');
714
+ res.end(JSON.stringify({
715
+ id: name,
716
+ name: name,
717
+ metaData: {
718
+ name: name,
719
+ type: 'app',
720
+ buildInfo: {
721
+ buildVersion: '1.0.0',
722
+ buildName: name
723
+ },
724
+ remoteEntry: {
725
+ name: filename,
726
+ path: '',
727
+ type: 'module'
728
+ },
729
+ ssrRemoteEntry: {
730
+ name: filename,
731
+ path: '',
732
+ type: 'module'
733
+ },
734
+ types: {
735
+ path: '',
736
+ name: ''
737
+ },
738
+ globalName: name,
739
+ pluginVersion: '0.2.5',
740
+ publicPath: 'auto'
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
+ }));
796
+ } else {
797
+ next();
798
+ }
799
+ });
800
+ }
801
+ }, {
802
+ name: 'moddule-federation-manifest',
803
+ enforce: 'post',
804
+ config(config) {
805
+ if (!config.build) config.build = {};
806
+ if (!config.build.manifest) config.build.manifest = config.build.manifest || !!manifestOptions;
807
+ },
808
+ configResolved(config) {
809
+ root = config.root;
810
+ extensions = config.resolve.extensions || ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'];
811
+ },
812
+ async generateBundle(options, bundle) {
813
+ if (!mfManifestName) return;
814
+ const exposesModules = Object.keys(mfOptions.exposes).map(item => mfOptions.exposes[item].import); // 获取你提供的 moduleIds
815
+ const filesContainingModules = {};
816
+ // 帮助函数:检查模块路径是否匹配
817
+ const isModuleMatched = (relativeModulePath, preloadModule) => {
818
+ // 先尝试直接匹配
819
+ if (relativeModulePath === preloadModule) return true;
820
+ // 如果 preloadModule 没有后缀,尝试添加可能的后缀进行匹配
821
+ for (const ext of extensions) {
822
+ if (relativeModulePath === `${preloadModule}${ext}`) {
823
+ return true;
824
+ }
825
+ }
826
+ return false;
827
+ };
828
+ // 遍历打包生成的每个文件
829
+ for (const [fileName, fileData] of Object.entries(bundle)) {
830
+ if (mfOptions.filename.replace(/[\[\]]/g, "_") === fileData.name) {
831
+ remoteEntryFile = fileData.fileName;
832
+ }
833
+ if (fileData.type === 'chunk') {
834
+ // 遍历该文件的所有模块
835
+ for (const modulePath of Object.keys(fileData.modules)) {
836
+ // 将绝对路径转换为相对于 Vite root 的相对路径
837
+ const relativeModulePath = relative(root, modulePath);
838
+ // 检查模块是否在 preloadModules 列表中
839
+ for (const preloadModule of exposesModules) {
840
+ const formatPreloadModule = preloadModule.replace("./", "");
841
+ if (isModuleMatched(relativeModulePath, formatPreloadModule)) {
842
+ if (!filesContainingModules[preloadModule]) {
843
+ filesContainingModules[preloadModule] = {
844
+ sync: [],
845
+ async: []
846
+ };
847
+ }
848
+ console.log(Object.keys(fileData.modules));
849
+ filesContainingModules[preloadModule].sync.push(fileName);
850
+ filesContainingModules[preloadModule].async.push(...(fileData.dynamicImports || []));
851
+ findSynchronousImports(fileName, filesContainingModules[preloadModule].sync);
852
+ break; // 如果找到匹配,跳出循环
853
+ }
854
+ }
855
+ }
856
+ }
857
+ }
858
+ // 递归查找模块的同步导入文件
859
+ function findSynchronousImports(fileName, array) {
860
+ const fileData = bundle[fileName];
861
+ if (fileData && fileData.type === 'chunk') {
862
+ array.push(fileName); // 将当前文件加入预加载列表
863
+ // 遍历该文件的同步导入文件
864
+ fileData.imports.forEach(importedFile => {
865
+ if (array.indexOf(importedFile) === -1) {
866
+ findSynchronousImports(importedFile, array); // 递归查找同步导入的文件
867
+ }
868
+ });
869
+ }
870
+ }
871
+ const fileToShareKey = {};
872
+ await Promise.all(Array.from(getUsedShares()).map(async shareKey => {
873
+ const file = (await this.resolve(getPreBuildLibImportId(shareKey))).id.split("?")[0];
874
+ fileToShareKey[file] = shareKey;
875
+ }));
876
+ // 遍历打包生成的每个文件
877
+ for (const [fileName, fileData] of Object.entries(bundle)) {
878
+ if (fileData.type === 'chunk') {
879
+ // 遍历该文件的所有模块
880
+ for (const modulePath of Object.keys(fileData.modules)) {
881
+ const sharedKey = fileToShareKey[modulePath];
882
+ if (sharedKey) {
883
+ if (!filesContainingModules[sharedKey]) {
884
+ filesContainingModules[sharedKey] = {
885
+ sync: [],
886
+ async: []
887
+ };
888
+ }
889
+ filesContainingModules[sharedKey].sync.push(fileName);
890
+ filesContainingModules[sharedKey].async.push(...(fileData.dynamicImports || []));
891
+ findSynchronousImports(fileName, filesContainingModules[sharedKey].sync);
892
+ break; // 如果找到匹配,跳出循环
893
+ }
894
+ }
895
+ }
896
+ }
897
+ Object.keys(filesContainingModules).forEach(key => {
898
+ filesContainingModules[key].sync = Array.from(new Set(filesContainingModules[key].sync));
899
+ filesContainingModules[key].async = Array.from(new Set(filesContainingModules[key].async));
900
+ });
901
+ this.emitFile({
902
+ type: 'asset',
903
+ fileName: mfManifestName,
904
+ source: generateMFManifest(filesContainingModules)
905
+ });
906
+ }
907
+ }];
908
+ function generateMFManifest(preloadMap) {
909
+ const options = getNormalizeModuleFederationOptions();
910
+ const {
911
+ name
912
+ } = options;
913
+ const remoteEntry = {
914
+ name: remoteEntryFile,
915
+ path: '',
916
+ type: 'module'
917
+ };
918
+ const remotes = [];
919
+ const usedRemotesMap = getUsedRemotesMap();
920
+ Object.keys(usedRemotesMap).forEach(remoteKey => {
921
+ const usedModules = Array.from(usedRemotesMap[remoteKey]);
922
+ usedModules.forEach(moduleKey => {
923
+ remotes.push({
924
+ federationContainerName: options.remotes[remoteKey].entry,
925
+ moduleName: moduleKey.replace(remoteKey, '').replace('/', ''),
926
+ alias: remoteKey,
927
+ entry: '*'
928
+ });
929
+ });
930
+ });
931
+ // @ts-ignore
932
+ const shared = Array.from(getUsedShares()).map(shareKey => {
933
+ // assets(.css, .jpg, .svg等)其他资源, 不重要, 暂未处理
934
+ if (!preloadMap[shareKey]) return;
935
+ const shareItem = getNormalizeShareItem(shareKey);
936
+ return {
937
+ id: `${name}:${shareKey}`,
938
+ name: shareKey,
939
+ version: shareItem.version,
940
+ requiredVersion: shareItem.shareConfig.requiredVersion,
941
+ assets: {
942
+ js: {
943
+ async: preloadMap[shareKey].async,
944
+ sync: preloadMap[shareKey].sync
945
+ },
946
+ css: {
947
+ async: [],
948
+ sync: []
949
+ }
950
+ }
951
+ };
952
+ }).filter(item => item);
953
+ const exposes = Object.keys(options.exposes).map(key => {
954
+ // assets(.css, .jpg, .svg等)其他资源, 不重要, 暂未处理
955
+ const formatKey = key.replace('./', '');
956
+ const sourceFile = options.exposes[key].import;
957
+ if (!preloadMap[sourceFile]) return;
958
+ return {
959
+ id: name + ':' + formatKey,
960
+ name: formatKey,
961
+ assets: {
962
+ js: {
963
+ async: preloadMap[sourceFile].async,
964
+ sync: preloadMap[sourceFile].sync
965
+ },
966
+ css: {
967
+ sync: [],
968
+ async: []
969
+ }
970
+ },
971
+ path: key
972
+ };
973
+ }).filter(item => item); // Filter out any null values
974
+ const result = {
975
+ id: name,
976
+ name: name,
977
+ metaData: {
978
+ name: name,
979
+ type: 'app',
980
+ buildInfo: {
981
+ buildVersion: '1.0.0',
982
+ buildName: name
983
+ },
984
+ remoteEntry,
985
+ ssrRemoteEntry: remoteEntry,
986
+ types: {
987
+ path: '',
988
+ name: ''
989
+ // "zip": "@mf-types.zip",
990
+ // "api": "@mf-types.d.ts"
991
+ },
992
+ globalName: name,
993
+ pluginVersion: '0.2.5',
994
+ publicPath: 'auto'
995
+ },
996
+ shared,
997
+ remotes,
998
+ exposes
999
+ };
1000
+ return JSON.stringify(result);
1001
+ }
1002
+ };
1003
+
1004
+ let _resolve,
1005
+ promise = new Promise((resolve, reject) => {
1006
+ _resolve = resolve;
1007
+ });
1008
+ let parsePromise = promise;
1009
+ const parseStartSet = new Set();
1010
+ const parseEndSet = new Set();
1011
+ function pluginModuleParseEnd (excludeFn) {
1012
+ return [{
1013
+ name: "_",
1014
+ apply: "serve",
1015
+ config() {
1016
+ // No waiting in development mode
1017
+ _resolve(1);
1018
+ }
1019
+ }, {
1020
+ enforce: "pre",
1021
+ name: "parseStart",
1022
+ apply: "build",
1023
+ load(id) {
1024
+ if (excludeFn(id)) {
1025
+ return;
1026
+ }
1027
+ parseStartSet.add(id);
1028
+ }
1029
+ }, {
1030
+ enforce: "post",
1031
+ name: "parseEnd",
1032
+ apply: "build",
1033
+ moduleParsed(module) {
1034
+ const id = module.id;
1035
+ if (excludeFn(id)) {
1036
+ return;
1037
+ }
1038
+ parseEndSet.add(id);
1039
+ if (parseStartSet.size === parseEndSet.size) {
1040
+ _resolve(1);
1041
+ }
1042
+ }
1043
+ }];
1044
+ }
1045
+
1046
+ const filter = createFilter();
606
1047
  function pluginProxyRemoteEntry () {
607
1048
  return {
608
1049
  name: 'proxyRemoteEntry',
@@ -614,56 +1055,40 @@ function pluginProxyRemoteEntry () {
614
1055
  },
615
1056
  load(id) {
616
1057
  if (id === REMOTE_ENTRY_ID) {
617
- return generateRemoteEntry(getNormalizeModuleFederationOptions());
1058
+ return parsePromise.then(_ => generateRemoteEntry(getNormalizeModuleFederationOptions()));
618
1059
  }
619
1060
  },
620
1061
  async transform(code, id) {
621
- if (!filter$1(id)) return;
1062
+ if (!filter(id)) return;
622
1063
  if (id.includes(REMOTE_ENTRY_ID)) {
623
- return generateRemoteEntry(getNormalizeModuleFederationOptions());
1064
+ return parsePromise.then(_ => generateRemoteEntry(getNormalizeModuleFederationOptions()));
624
1065
  }
625
1066
  }
626
1067
  };
627
1068
  }
628
1069
 
629
- const filter = createFilter();
1070
+ createFilter();
630
1071
  function pluginProxyRemotes (options) {
631
- let command;
632
1072
  const {
633
1073
  remotes
634
1074
  } = options;
635
- const matchRemotesList = Object.keys(remotes).map(item => item.replace(/\//g, "_"));
636
1075
  return {
637
1076
  name: "proxyRemotes",
638
1077
  config(config, {
639
1078
  command: _command
640
1079
  }) {
641
- command = _command;
642
1080
  Object.keys(remotes).forEach(key => {
643
1081
  const remote = remotes[key];
644
1082
  config.resolve.alias.push({
645
- find: new RegExp(`(${remote.name}(\/.*|$)?)`),
646
- replacement: '$1',
1083
+ find: new RegExp(`^(${remote.name}(\/.*|$))`),
1084
+ replacement: "$1",
647
1085
  customResolver(source) {
648
- const requestPath = remoteVirtualModule.getImportId() + '?__moduleRemote__=' + encodeURIComponent(source);
649
- if (!config.optimizeDeps) config.optimizeDeps = {};
650
- if (!config.optimizeDeps.needsInterop) config.optimizeDeps.needsInterop = [];
651
- if (config.optimizeDeps.needsInterop.indexOf(requestPath) === -1) config.optimizeDeps.needsInterop.push(requestPath);
652
- return this.resolve(requestPath);
1086
+ const remoteModule = getRemoteVirtualModule(source, _command);
1087
+ addUsedRemote(remote.name, source);
1088
+ return remoteModule.getPath();
653
1089
  }
654
1090
  });
655
1091
  });
656
- },
657
- async transform(code, id) {
658
- if (!filter(id)) return;
659
- let [devRemoteModuleName] = matchRemotesList.length && id.match(new RegExp(`\/(${matchRemotesList.join('|')})(\_.*\.js|\.js)`)) || [];
660
- if (devRemoteModuleName) {
661
- return generateRemotes(devRemoteModuleName.replace('/', '').replace(/_/g, '/').replace('.js', ''), command);
662
- }
663
- let [prodRemoteName] = id.match(/\_\_moduleRemote\_\_=[^&]+/) || [];
664
- if (prodRemoteName) {
665
- return generateRemotes(decodeURIComponent(prodRemoteName.replace('__moduleRemote__=', '')), command);
666
- }
667
1092
  }
668
1093
  };
669
1094
  }
@@ -702,42 +1127,23 @@ class PromiseStore {
702
1127
  }
703
1128
  }
704
1129
 
705
- function wrapManualChunks(output, manualChunksCb) {
706
- if (!output.manualChunks) output.manualChunks = {};
707
- const wrapManualChunks = original => (id, ...args) => {
708
- const customRes = manualChunksCb == null ? void 0 : manualChunksCb(id, ...args);
709
- if (customRes) return customRes;
710
- if (typeof original === 'function') {
711
- return original(id, ...args);
712
- }
713
- if (typeof original === 'object' && original) {
714
- return original[id];
715
- }
716
- };
717
- output.manualChunks = wrapManualChunks(output.manualChunks);
718
- }
719
-
720
1130
  function proxySharedModule(options) {
721
1131
  let {
722
1132
  shared = {},
723
1133
  include,
724
1134
  exclude
725
1135
  } = options;
726
- const filterFunction = createFilter(include, exclude);
727
1136
  return [{
728
1137
  name: "generateLocalSharedImportMap",
729
1138
  enforce: "post",
730
- resolveId(id) {
731
- if (id.includes(getLocalSharedImportMapPath())) return id;
732
- },
733
1139
  load(id) {
734
1140
  if (id.includes(getLocalSharedImportMapPath())) {
735
- return generateLocalSharedImportMap();
1141
+ return parsePromise.then(_ => generateLocalSharedImportMap());
736
1142
  }
737
1143
  },
738
1144
  transform(code, id) {
739
1145
  if (id.includes(getLocalSharedImportMapPath())) {
740
- return generateLocalSharedImportMap();
1146
+ return parsePromise.then(_ => generateLocalSharedImportMap());
741
1147
  }
742
1148
  }
743
1149
  }, {
@@ -746,21 +1152,6 @@ function proxySharedModule(options) {
746
1152
  config(config, {
747
1153
  command
748
1154
  }) {
749
- if (!config.build) config.build = {};
750
- if (!config.build.rollupOptions) config.build.rollupOptions = {};
751
- let {
752
- rollupOptions
753
- } = config.build;
754
- if (!rollupOptions.output) rollupOptions.output = {};
755
- wrapManualChunks(config.build.rollupOptions.output, id => {
756
- // https://github.com/module-federation/vite/issues/40#issuecomment-2311434503
757
- if (id.includes('/preload-helper.js')) {
758
- return "preload-helper";
759
- }
760
- if (id.includes("node_modules/@module-federation/runtime")) {
761
- return "@module-federation/runtime";
762
- }
763
- });
764
1155
  config.resolve.alias.push(...Object.keys(shared).map(key => {
765
1156
  const pattern = key.endsWith("/") ? `(^${key.replace(/\/$/, "")}(\/.+)?$)` : `(^${key}$)`;
766
1157
  return {
@@ -768,12 +1159,10 @@ function proxySharedModule(options) {
768
1159
  find: new RegExp(pattern),
769
1160
  replacement: "$1",
770
1161
  customResolver(source, importer) {
771
- var _config$optimizeDeps;
772
1162
  const loadSharePath = getLoadShareModulePath(source);
773
- config == null || (_config$optimizeDeps = config.optimizeDeps) == null || (_config$optimizeDeps = _config$optimizeDeps.needsInterop) == null || _config$optimizeDeps.push(loadSharePath);
774
1163
  writeLoadShareModule(source, shared[key], command);
775
1164
  writePreBuildLibPath(source);
776
- addShare(source);
1165
+ addUsedShares(source);
777
1166
  writeLocalSharedImportMap();
778
1167
  return this.resolve(loadSharePath);
779
1168
  }
@@ -782,18 +1171,16 @@ function proxySharedModule(options) {
782
1171
  const savePrebuild = new PromiseStore();
783
1172
  config.resolve.alias.push(...Object.keys(shared).map(key => {
784
1173
  return command === "build" ? {
785
- find: new RegExp(`(.*${PREBUILD_TAG}(.+))`),
1174
+ find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
786
1175
  replacement: function ($1) {
787
- $1 = $1.replace(/\.[^.]+$/, "");
788
- const pkgName = packageNameDecode($1.split(PREBUILD_TAG)[1]);
789
- return packageNameDecode(pkgName);
1176
+ const pkgName = VirtualModule.findModule(PREBUILD_TAG, $1).name;
1177
+ return pkgName;
790
1178
  }
791
1179
  } : {
792
- find: new RegExp(`(.*${PREBUILD_TAG}(.+))`),
1180
+ find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
793
1181
  replacement: "$1",
794
1182
  async customResolver(source, importer) {
795
- source = source.replace(/\.[^.]+$/, "");
796
- const pkgName = packageNameDecode(source.split(PREBUILD_TAG)[1]);
1183
+ const pkgName = VirtualModule.findModule(PREBUILD_TAG, source).name;
797
1184
  if (importer.includes(LOAD_SHARE_TAG)) {
798
1185
  // save pre-bunding module id
799
1186
  savePrebuild.set(pkgName, this.resolve(pkgName).then(item => item.id));
@@ -820,75 +1207,6 @@ function proxySharedModule(options) {
820
1207
  watch.ignored = [].concat(watch.ignored);
821
1208
  watch.ignored.push(`!**${getLocalSharedImportMapPath()}**`);
822
1209
  }
823
- }, {
824
- name: "prebuild-top-level-await",
825
- apply: "serve",
826
- transform(code, id) {
827
- if (!code.includes("/*mf top-level-await placeholder replacement mf*/")) {
828
- return null;
829
- }
830
- if (!filterFunction(id)) return null;
831
- let ast;
832
- try {
833
- ast = this.parse(code, {
834
- allowReturnOutsideFunction: true
835
- });
836
- } catch (e) {
837
- throw new Error(`${id}: ${e}`);
838
- }
839
- const magicString = new MagicString(code);
840
- walk(ast, {
841
- enter(node) {
842
- if (node.type === 'ExportNamedDeclaration' && node.specifiers) {
843
- const exportSpecifiers = node.specifiers.map(specifier => specifier.exported.name);
844
- const proxyStatements = exportSpecifiers.map(name => `
845
- const __mfproxy__await${name} = await ${name}();
846
- const __mfproxy__${name} = () => __mfproxy__await${name};
847
- `).join('\n');
848
- const exportStatements = exportSpecifiers.map(name => `__mfproxy__${name} as ${name}`).join(', ');
849
- const start = node.start;
850
- const end = node.end;
851
- const replacement = `${proxyStatements}\nexport { ${exportStatements} };`;
852
- magicString.overwrite(start, end, replacement);
853
- }
854
- if (node.type === 'ExportDefaultDeclaration') {
855
- const declaration = node.declaration;
856
- const start = node.start;
857
- const end = node.end;
858
- let proxyStatement;
859
- let exportStatement = 'default';
860
- if (declaration.type === 'Identifier') {
861
- // example: export default foo;
862
- proxyStatement = `
863
- const __mfproxy__awaitdefault = await ${declaration.name}();
864
- const __mfproxy__default = __mfproxy__awaitdefault;
865
- `;
866
- } else if (declaration.type === 'CallExpression' || declaration.type === 'FunctionDeclaration') {
867
- // example: export default someFunction();
868
- const declarationCode = code.slice(declaration.start, declaration.end);
869
- proxyStatement = `
870
- const __mfproxy__awaitdefault = await (${declarationCode});
871
- const __mfproxy__default = __mfproxy__awaitdefault;
872
- `;
873
- } else {
874
- // other
875
- proxyStatement = `
876
- const __mfproxy__awaitdefault = await (${code.slice(declaration.start, declaration.end)});
877
- const __mfproxy__default = __mfproxy__awaitdefault;
878
- `;
879
- }
880
- const replacement = `${proxyStatement}\nexport { __mfproxy__default as ${exportStatement} };`;
881
- magicString.overwrite(start, end, replacement);
882
- }
883
- }
884
- });
885
- return {
886
- code: magicString.toString(),
887
- map: magicString.generateMap({
888
- hires: true
889
- })
890
- };
891
- }
892
1210
  }];
893
1211
  }
894
1212
 
@@ -942,16 +1260,16 @@ function federation(mfUserOptions) {
942
1260
  if (!name) throw new Error("name is required");
943
1261
  return [aliasToArrayPlugin, normalizeOptimizeDepsPlugin, ...addEntry({
944
1262
  entryName: 'remoteEntry',
945
- entryPath: getWrapRemoteEntryPath(),
1263
+ entryPath: REMOTE_ENTRY_ID,
946
1264
  fileName: filename
947
1265
  }), ...addEntry({
948
1266
  entryName: 'hostInit',
949
1267
  entryPath: getHostAutoInitPath()
950
1268
  }), pluginProxyRemoteEntry(), pluginProxyRemotes(options), ...pluginModuleParseEnd(id => {
951
- return id.includes(getHostAutoInitImportId()) || id.includes(getWrapRemoteEntryImportId()) || id.includes(REMOTE_ENTRY_ID) || id.includes(getLocalSharedImportMapPath());
1269
+ return id.includes(getHostAutoInitImportId()) || id.includes(REMOTE_ENTRY_ID) || id.includes(getLocalSharedImportMapPath());
952
1270
  }), ...proxySharedModule({
953
1271
  shared
954
- }), {
1272
+ }), PluginDevProxyModuleTopLevelAwait(), {
955
1273
  name: 'module-federation-vite',
956
1274
  enforce: 'post',
957
1275
  config(config, {
@@ -963,11 +1281,8 @@ function federation(mfUserOptions) {
963
1281
  replacement: require.resolve('@module-federation/runtime')
964
1282
  });
965
1283
  (_config$optimizeDeps = config.optimizeDeps) == null || (_config$optimizeDeps = _config$optimizeDeps.include) == null || _config$optimizeDeps.push('@module-federation/runtime');
966
- // Object.keys(shared).forEach((key) => {
967
- // config.optimizeDeps?.include?.push(key);
968
- // });
969
1284
  }
970
- }];
1285
+ }, ...Manifest()];
971
1286
  }
972
1287
 
973
1288
  export { federation };