@squide/firefly-webpack-configs 4.2.1 → 4.2.3
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/CHANGELOG.md +12 -0
- package/dist/defineConfig.d.ts +59 -0
- package/dist/defineConfig.js +387 -0
- package/dist/defineConfig.js.map +1 -0
- package/dist/index.d.ts +2 -25
- package/dist/index.js +7 -45
- package/dist/index.js.map +1 -0
- package/dist/nonCacheableRemoteEntryPlugin.d.ts +3 -0
- package/dist/nonCacheableRemoteEntryPlugin.js +21 -0
- package/dist/nonCacheableRemoteEntryPlugin.js.map +1 -0
- package/dist/shared.d.ts +1 -0
- package/dist/shared.js +8 -0
- package/dist/shared.js.map +1 -0
- package/dist/sharedDependenciesResolutionPlugin.d.ts +9 -0
- package/dist/sharedDependenciesResolutionPlugin.js +137 -0
- package/dist/sharedDependenciesResolutionPlugin.js.map +1 -0
- package/package.json +30 -19
- package/src/defineConfig.ts +514 -0
- package/src/index.ts +3 -0
- package/src/nonCacheableRemoteEntryPlugin.ts +20 -0
- package/src/shared.ts +2 -0
- package/src/sharedDependenciesResolutionPlugin.ts +173 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This custom share dependency resolution strategy ensure that only the host app can ask for a new major version of a library.
|
|
3
|
+
Otherwise, any remote can request for an higher non-major version.
|
|
4
|
+
|
|
5
|
+
Examples:
|
|
6
|
+
|
|
7
|
+
host: 2.0
|
|
8
|
+
remote-1: 2.1 <-----
|
|
9
|
+
remote-2: 2.0
|
|
10
|
+
|
|
11
|
+
host: 2.0 <-----
|
|
12
|
+
remote-1: 3.1
|
|
13
|
+
remote-2: 2.0
|
|
14
|
+
|
|
15
|
+
host: 2.0
|
|
16
|
+
remote-1: 3.1
|
|
17
|
+
remote-2: 2.1 <-----
|
|
18
|
+
|
|
19
|
+
host: >2.0
|
|
20
|
+
remote-1: 3.1
|
|
21
|
+
remote-2: 2.1 <-----
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type { FederationHost, FederationRuntimePlugin } from "@module-federation/enhanced/runtime";
|
|
25
|
+
import { minVersion, parse, rcompare, type SemVer } from "semver";
|
|
26
|
+
import { HostApplicationName } from "./shared.ts";
|
|
27
|
+
|
|
28
|
+
type Shared = FederationHost["shareScopeMap"][string][string][string];
|
|
29
|
+
|
|
30
|
+
// Toggle to "true" to facilitate the debugging of this plugin.
|
|
31
|
+
const isDebug = false;
|
|
32
|
+
|
|
33
|
+
function log(...args: unknown[]) {
|
|
34
|
+
if (isDebug) {
|
|
35
|
+
console.log(...args);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function findHighestVersionForMajor(entries: Shared[], major: number) {
|
|
40
|
+
return entries.find(x => {
|
|
41
|
+
return parse(x.version)!.major === major;
|
|
42
|
+
}) as Shared;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface ResolveSharedDependencyResult {
|
|
46
|
+
resolvedEntry: Shared;
|
|
47
|
+
highestVersionEntry: Shared;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// The return type is required otherwise we get the following error: error TS2742: The inferred type of 'resolveSharedDependency' cannot be named without a reference to.
|
|
51
|
+
export function resolveSharedDependency(pkgName: string, entries: Shared[], logFct: (...rest: unknown[]) => void = () => {}): ResolveSharedDependencyResult {
|
|
52
|
+
const cleanedEntries = entries.map(x => ({
|
|
53
|
+
...x,
|
|
54
|
+
// Removing any special characters like >,>=,^,~ etc...
|
|
55
|
+
version: minVersion(x.version)!.version
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
// From higher to lower versions.
|
|
59
|
+
const sortedEntries = cleanedEntries.sort((x, y) => rcompare(x.version, y.version));
|
|
60
|
+
|
|
61
|
+
logFct("[squide] Sorted the entries by version from higher to lower", sortedEntries);
|
|
62
|
+
|
|
63
|
+
const highestVersionEntry = sortedEntries[0];
|
|
64
|
+
|
|
65
|
+
logFct(`[squide] ${pkgName} highest requested version is`, highestVersionEntry.version, highestVersionEntry);
|
|
66
|
+
|
|
67
|
+
// The host is always right!
|
|
68
|
+
if (highestVersionEntry.from === HostApplicationName) {
|
|
69
|
+
logFct("[squide] %cThis is the host version%c, great, resolving to:", "color: black; background-color: pink;", "", highestVersionEntry.version, highestVersionEntry);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
resolvedEntry: highestVersionEntry,
|
|
73
|
+
highestVersionEntry: highestVersionEntry
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
logFct(`[squide] ${pkgName} Highest requested version is not from the host.`);
|
|
78
|
+
|
|
79
|
+
const hostEntry = sortedEntries.find(x => x.from === HostApplicationName);
|
|
80
|
+
|
|
81
|
+
// Found nothing, that's odd but let's not break the app for this.
|
|
82
|
+
if (!hostEntry) {
|
|
83
|
+
logFct(`[squide] The host is not requesting any version of ${pkgName}, %caborting%c.`, "color: black; background-color: pink;", "");
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
resolvedEntry: highestVersionEntry,
|
|
87
|
+
highestVersionEntry: highestVersionEntry
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
logFct(`[squide] ${pkgName} version requested by the host is:`, hostEntry.version, hostEntry);
|
|
92
|
+
|
|
93
|
+
const parsedHighestVersion = parse(highestVersionEntry.version) as SemVer;
|
|
94
|
+
const parsedHostVersion = parse(hostEntry.version) as SemVer;
|
|
95
|
+
|
|
96
|
+
// Major versions should always be introduced by the host application.
|
|
97
|
+
if (parsedHighestVersion.major === parsedHostVersion.major) {
|
|
98
|
+
logFct(`[squide] Resolving to %c${parsedHighestVersion.major}%c.`, "color: black; background-color: pink;", "");
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
resolvedEntry: highestVersionEntry,
|
|
102
|
+
highestVersionEntry: highestVersionEntry
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
logFct("[squide] The major number of the highest requested version is higher than the major number of the version requested by the host, looking for another version to resolve to.");
|
|
107
|
+
|
|
108
|
+
// Start at the second entry since the first entry is the current higher version entry.
|
|
109
|
+
// The result could either be the actual host entry or any other entry that is higher than the version requested
|
|
110
|
+
// by the host, but match the host entry major version number.
|
|
111
|
+
const fallbackEntry = findHighestVersionForMajor(sortedEntries.splice(1), parsedHostVersion.major);
|
|
112
|
+
|
|
113
|
+
logFct(`[squide] The %chighest requested version%c for ${pkgName} that is in-range with the requested host major version number is:`, "color: black; background-color: pink;", "", fallbackEntry.version, fallbackEntry);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
resolvedEntry: fallbackEntry,
|
|
117
|
+
highestVersionEntry: highestVersionEntry
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const plugin: () => FederationRuntimePlugin = () => {
|
|
122
|
+
return {
|
|
123
|
+
name: "shared-dependencies-resolution-plugin",
|
|
124
|
+
resolveShare: function(args) {
|
|
125
|
+
const { shareScopeMap, scope, pkgName } = args;
|
|
126
|
+
|
|
127
|
+
log(`[squide] Resolving ${pkgName}:`, args);
|
|
128
|
+
|
|
129
|
+
// This custom strategy only applies to singleton shared dependencies.
|
|
130
|
+
const entries = Object.values(shareScopeMap[scope][pkgName]).filter(x => {
|
|
131
|
+
return (
|
|
132
|
+
// Temporary check until all the remotes on Webpack Module Federation has been updated to Module Federation 2.0.
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
134
|
+
// @ts-ignore
|
|
135
|
+
x.singleton ||
|
|
136
|
+
(x.shareConfig && x.shareConfig.singleton)
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Not a singleton dependency.
|
|
141
|
+
if (entries.length === 0) {
|
|
142
|
+
log(`[squide] ${pkgName} is not a singleton dependency, aborting.`);
|
|
143
|
+
|
|
144
|
+
return args;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// If there's only one version entry, then it means that everyone is requesting the same version
|
|
148
|
+
// of the dependency.
|
|
149
|
+
if (entries.length <= 1) {
|
|
150
|
+
log(`[squide] There's only one version requested for ${pkgName}, resolving to:`, entries[0].version, entries[0]);
|
|
151
|
+
|
|
152
|
+
return args;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
args.resolver = () => {
|
|
156
|
+
log(`[squide] There's %cmore than one requested version%c for ${pkgName}:`, "color: black; background-color: pink;", "", entries.length, shareScopeMap[scope][pkgName]);
|
|
157
|
+
|
|
158
|
+
const { resolvedEntry, highestVersionEntry } = resolveSharedDependency(pkgName, entries, log);
|
|
159
|
+
|
|
160
|
+
if (resolvedEntry.version !== highestVersionEntry.version) {
|
|
161
|
+
// eslint-disable-next-line max-len
|
|
162
|
+
console.log(`%c[squide] "${highestVersionEntry.from}" requested version "${highestVersionEntry.version}" of "${pkgName}". This version is higher than the major number of the version requested by the host for this dependency (${resolvedEntry.version}). The version for "${pkgName}" has been forced to "${resolvedEntry.version}".`, "color: white; background-color: red;");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return resolvedEntry;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
return args;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export default plugin;
|