@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.
- package/README.md +16 -5
- package/lib/index.cjs +674 -333
- package/lib/index.esm.js +676 -335
- package/lib/index.modern.js +651 -336
- package/lib/index.umd.js +677 -336
- package/lib/plugins/pluginDevProxyModuleTopLevelAwait.d.ts +2 -0
- package/lib/plugins/pluginMFManifest.d.ts +3 -0
- package/lib/utils/VirtualModule.d.ts +5 -3
- package/lib/utils/normalizeModuleFederationOptions.d.ts +8 -2
- package/lib/utils/packageNameUtils.d.ts +7 -3
- package/lib/virtualModules/index.d.ts +4 -3
- package/lib/virtualModules/virtualRemoteEntry.d.ts +6 -4
- package/lib/virtualModules/virtualRemotes.d.ts +6 -8
- package/lib/virtualModules/virtualRuntimeInitStatus.d.ts +3 -0
- package/lib/virtualModules/virtualShared_preBuild.d.ts +0 -6
- package/package.json +2 -2
package/lib/index.modern.js
CHANGED
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
-
import {
|
|
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}`, `${
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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(
|
|
336
|
+
return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
|
|
278
337
|
}
|
|
279
338
|
/**
|
|
280
|
-
*
|
|
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(
|
|
283
|
-
if (typeof
|
|
284
|
-
return
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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
|
-
|
|
327
|
-
|
|
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.
|
|
330
|
-
this.
|
|
331
|
-
this.
|
|
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
|
|
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
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
-
|
|
364
|
-
|
|
365
|
-
|
|
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
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
|
405
|
-
|
|
406
|
-
const sharedCount =
|
|
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
|
-
|
|
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
|
-
|
|
416
|
-
await parsePromise;
|
|
551
|
+
function generateLocalSharedImportMap() {
|
|
417
552
|
const options = getNormalizeModuleFederationOptions();
|
|
418
553
|
return `
|
|
419
|
-
const
|
|
420
|
-
${Array.from(
|
|
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
|
|
428
|
-
${Array.from(
|
|
429
|
-
const shareItem =
|
|
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
|
-
|
|
439
|
-
const {${JSON.stringify(key)}: pkgDynamicImport} =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
516
|
-
|
|
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
|
-
|
|
682
|
+
writeRuntimeInitStatus();
|
|
603
683
|
}
|
|
604
684
|
|
|
605
|
-
const
|
|
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
|
|
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
|
-
|
|
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(
|
|
646
|
-
replacement:
|
|
1083
|
+
find: new RegExp(`^(${remote.name}(\/.*|$))`),
|
|
1084
|
+
replacement: "$1",
|
|
647
1085
|
customResolver(source) {
|
|
648
|
-
const
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
|
|
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
|
-
|
|
788
|
-
|
|
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
|
-
|
|
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:
|
|
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(
|
|
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 };
|