@softarc/native-federation 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -39
- package/dist/config.d.ts +3 -1
- package/dist/config.js +4 -6
- package/dist/internal.d.ts +2 -1
- package/dist/internal.js +2 -0
- package/dist/lib/config/project-paths.d.ts +5 -0
- package/dist/lib/config/project-paths.js +49 -0
- package/dist/lib/config/secondaries.d.ts +5 -0
- package/dist/lib/config/secondaries.js +186 -0
- package/dist/lib/config/share-utils.d.ts +13 -10
- package/dist/lib/config/share-utils.js +58 -254
- package/dist/lib/config/version-lookup.d.ts +4 -0
- package/dist/lib/config/version-lookup.js +37 -0
- package/dist/lib/config/with-native-federation.js +8 -5
- package/dist/lib/core/build/build-for-federation.js +4 -9
- package/dist/lib/core/build/bundle-shared.js +4 -11
- package/dist/lib/core/output/densify-externals.d.ts +8 -0
- package/dist/lib/core/output/densify-externals.js +49 -0
- package/dist/lib/domain/config/external-config.contract.d.ts +13 -9
- package/dist/lib/domain/config/federation-config.contract.d.ts +2 -0
- package/dist/lib/domain/config/index.d.ts +1 -1
- package/dist/lib/domain/core/federation-info.contract.d.ts +5 -1
- package/dist/lib/domain/core/index.d.ts +1 -1
- package/dist/lib/utils/normalize.d.ts +1 -0
- package/dist/lib/utils/normalize.js +8 -0
- package/package.json +2 -2
|
@@ -1,240 +1,48 @@
|
|
|
1
1
|
import * as path from "path";
|
|
2
|
-
import { cwd } from "process";
|
|
3
2
|
import { DEFAULT_SKIP_LIST, isInSkipList, prepareSkipList } from "./default-skip-list.js";
|
|
4
3
|
import {
|
|
5
4
|
sharedPackageJsonRepository,
|
|
6
5
|
findDepPackageJson,
|
|
7
6
|
getVersionMaps
|
|
8
7
|
} from "../utils/package/package-info.js";
|
|
9
|
-
import { getConfigContext } from "./configuration-context.js";
|
|
10
8
|
import { logger } from "../utils/logger.js";
|
|
11
9
|
import { nodeIo } from "../utils/io/node-io-adapter.js";
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const filePath = path.join(folder, "package.json");
|
|
34
|
-
if (io.exists(filePath)) {
|
|
35
|
-
return filePath;
|
|
36
|
-
}
|
|
37
|
-
throw new Error(
|
|
38
|
-
"no package.json found. Searched the following folder and all parents: " + folder
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
function lookupVersion(key, workspaceRoot, repo) {
|
|
42
|
-
const versionMaps = getVersionMaps(workspaceRoot, workspaceRoot, repo);
|
|
43
|
-
for (const versionMap of versionMaps) {
|
|
44
|
-
const version = lookupVersionInMap(key, versionMap);
|
|
45
|
-
if (version) {
|
|
46
|
-
return version;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
throw new Error(
|
|
50
|
-
`Shared Dependency ${key} has requiredVersion:'auto'. However, this dependency is not found in your package.json`
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
function lookupVersionInMap(key, versions) {
|
|
54
|
-
const parts = key.split("/");
|
|
55
|
-
if (parts.length >= 2 && parts[0].startsWith("@")) {
|
|
56
|
-
key = parts[0] + "/" + parts[1];
|
|
57
|
-
} else {
|
|
58
|
-
key = parts[0];
|
|
59
|
-
}
|
|
60
|
-
if (!versions[key]) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
return versions[key];
|
|
64
|
-
}
|
|
65
|
-
function _findSecondaries(io, libPath, excludes, shareObject, acc, preparedSkipList) {
|
|
66
|
-
const files = io.readDir(libPath);
|
|
67
|
-
const secondaries = files.map((f) => path.join(libPath, f)).filter((f) => io.isDirectory(f) && !f.endsWith("node_modules"));
|
|
68
|
-
for (const s of secondaries) {
|
|
69
|
-
if (io.exists(path.join(s, "package.json"))) {
|
|
70
|
-
const secondaryLibName = s.replace(/\\/g, "/").replace(/^.*node_modules[/]/, "");
|
|
71
|
-
const inCustomSkipList = excludes.some(
|
|
72
|
-
(e) => e === secondaryLibName || e.endsWith("*") && secondaryLibName.startsWith(e.slice(0, -1))
|
|
73
|
-
);
|
|
74
|
-
if (inCustomSkipList) continue;
|
|
75
|
-
if (isInSkipList(secondaryLibName, preparedSkipList)) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
acc[secondaryLibName] = { ...shareObject };
|
|
79
|
-
}
|
|
80
|
-
_findSecondaries(io, s, excludes, shareObject, acc, preparedSkipList);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function findSecondaries(io, libPath, excludes, shareObject, preparedSkipList) {
|
|
84
|
-
const acc = {};
|
|
85
|
-
_findSecondaries(io, libPath, excludes, shareObject, acc, preparedSkipList);
|
|
86
|
-
return acc;
|
|
87
|
-
}
|
|
88
|
-
function getSecondaries(io, includeSecondaries, libPath, key, shareObject, preparedSkipList) {
|
|
89
|
-
let exclude = [];
|
|
90
|
-
let resolveGlob = false;
|
|
91
|
-
if (typeof includeSecondaries === "object") {
|
|
92
|
-
if (includeSecondaries.skip) {
|
|
93
|
-
if (Array.isArray(includeSecondaries.skip)) {
|
|
94
|
-
exclude = includeSecondaries.skip;
|
|
95
|
-
} else if (typeof includeSecondaries.skip === "string") {
|
|
96
|
-
exclude = [includeSecondaries.skip];
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
resolveGlob = !!includeSecondaries.resolveGlob;
|
|
100
|
-
}
|
|
101
|
-
if (!io.exists(libPath)) {
|
|
102
|
-
return {};
|
|
103
|
-
}
|
|
104
|
-
const configured = readConfiguredSecondaries(
|
|
105
|
-
io,
|
|
106
|
-
key,
|
|
107
|
-
libPath,
|
|
108
|
-
exclude,
|
|
109
|
-
shareObject,
|
|
110
|
-
preparedSkipList,
|
|
111
|
-
resolveGlob
|
|
112
|
-
);
|
|
113
|
-
if (configured) {
|
|
114
|
-
return configured;
|
|
115
|
-
}
|
|
116
|
-
const secondaries = findSecondaries(io, libPath, exclude, shareObject, preparedSkipList);
|
|
117
|
-
return secondaries;
|
|
118
|
-
}
|
|
119
|
-
function readConfiguredSecondaries(io, parent, libPath, exclude, shareObject, preparedSkipList, resolveGlob) {
|
|
120
|
-
const libPackageJson = path.join(libPath, "package.json");
|
|
121
|
-
if (!io.exists(libPackageJson)) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
const packageJson = JSON.parse(io.readText(libPackageJson));
|
|
125
|
-
const version = packageJson["version"];
|
|
126
|
-
const esm = packageJson["type"] === "module";
|
|
127
|
-
const exports = packageJson["exports"];
|
|
128
|
-
if (!exports) {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
const keys = Object.keys(exports).filter(
|
|
132
|
-
(key) => key !== "." && key !== "./package.json" && key.startsWith("./") && (exports[key]?.["default"] || exports[key]?.["import"] || typeof exports[key] === "string")
|
|
133
|
-
);
|
|
134
|
-
const result = {};
|
|
135
|
-
const discoveredFiles = /* @__PURE__ */ new Set();
|
|
136
|
-
for (const key of keys) {
|
|
137
|
-
const secondaryName = path.join(parent, key).replace(/\\/g, "/");
|
|
138
|
-
const inCustomSkipList = exclude.some(
|
|
139
|
-
(e) => e === secondaryName || e.endsWith("*") && secondaryName.startsWith(e.slice(0, -1))
|
|
140
|
-
);
|
|
141
|
-
if (inCustomSkipList) continue;
|
|
142
|
-
if (isInSkipList(secondaryName, preparedSkipList)) {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
const entry = getDefaultEntry(exports, key);
|
|
146
|
-
if (typeof entry !== "string") {
|
|
147
|
-
console.log("No entry point found for " + secondaryName);
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
if (!key.includes("*") && !isJsFile(entry)) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
const items = resolveGlobSecondaries(
|
|
154
|
-
io,
|
|
155
|
-
key,
|
|
156
|
-
libPath,
|
|
157
|
-
parent,
|
|
158
|
-
secondaryName,
|
|
159
|
-
entry,
|
|
160
|
-
{ discovered: discoveredFiles, skip: exclude },
|
|
161
|
-
resolveGlob
|
|
162
|
-
);
|
|
163
|
-
items.forEach((e) => discoveredFiles.add(typeof e === "string" ? e : e.value));
|
|
164
|
-
for (const item of items) {
|
|
165
|
-
if (typeof item === "object") {
|
|
166
|
-
result[item.key] = {
|
|
167
|
-
...shareObject,
|
|
168
|
-
packageInfo: {
|
|
169
|
-
entryPoint: item.value,
|
|
170
|
-
version: shareObject.version ?? version,
|
|
171
|
-
esm
|
|
172
|
-
}
|
|
10
|
+
import { findPackageJson, inferProjectPath } from "./project-paths.js";
|
|
11
|
+
import { isInferVersion, lookupVersion } from "./version-lookup.js";
|
|
12
|
+
import { addSecondaries, getSecondaries } from "./secondaries.js";
|
|
13
|
+
const fromPackageJson = (baseCfg, projectPath) => {
|
|
14
|
+
const skipList = [...DEFAULT_SKIP_LIST];
|
|
15
|
+
let overrides = {};
|
|
16
|
+
const patchList = {};
|
|
17
|
+
const builder = {
|
|
18
|
+
skip(externals) {
|
|
19
|
+
skipList.push(...externals);
|
|
20
|
+
return builder;
|
|
21
|
+
},
|
|
22
|
+
override(externals) {
|
|
23
|
+
overrides = { ...overrides, ...externals };
|
|
24
|
+
return builder;
|
|
25
|
+
},
|
|
26
|
+
patch(externals, cfg) {
|
|
27
|
+
externals.forEach((external) => {
|
|
28
|
+
patchList[external] = {
|
|
29
|
+
...patchList[external] ?? {},
|
|
30
|
+
...cfg
|
|
173
31
|
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
let items = [];
|
|
185
|
-
if (key.includes("*")) {
|
|
186
|
-
if (!resolveGlob) return items;
|
|
187
|
-
const expanded = resolvePackageJsonExportsWildcardCore(io, key, entry, libPath);
|
|
188
|
-
items = expanded.map((e) => ({
|
|
189
|
-
key: path.join(parent, e.key),
|
|
190
|
-
value: path.join(libPath, e.value)
|
|
191
|
-
})).filter((i) => {
|
|
192
|
-
if (!isJsFile(i.value)) {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
if (excludes.skip.some(
|
|
196
|
-
(e) => e.endsWith("*") ? i.key.startsWith(e.slice(0, -1)) : e === i.key
|
|
197
|
-
)) {
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
if (excludes.discovered.has(i.value)) {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
return true;
|
|
204
|
-
});
|
|
205
|
-
} else {
|
|
206
|
-
items = [secondaryName];
|
|
207
|
-
}
|
|
208
|
-
return items;
|
|
209
|
-
}
|
|
210
|
-
function isJsFile(file) {
|
|
211
|
-
return file.endsWith(".js") || file.endsWith(".mjs") || file.endsWith(".cjs");
|
|
212
|
-
}
|
|
213
|
-
function getDefaultEntry(exports, key) {
|
|
214
|
-
let entry = "";
|
|
215
|
-
if (typeof exports[key] === "string") {
|
|
216
|
-
entry = exports[key];
|
|
217
|
-
}
|
|
218
|
-
if (!entry) {
|
|
219
|
-
entry = exports[key]?.["default"];
|
|
220
|
-
if (typeof entry === "object") {
|
|
221
|
-
entry = entry["default"];
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
if (!entry) {
|
|
225
|
-
entry = exports[key]?.["import"];
|
|
226
|
-
if (typeof entry === "object") {
|
|
227
|
-
entry = entry["import"] ?? entry["default"];
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
if (!entry) {
|
|
231
|
-
entry = exports[key]?.["require"];
|
|
232
|
-
if (typeof entry === "object") {
|
|
233
|
-
entry = entry["require"] ?? entry["default"];
|
|
32
|
+
});
|
|
33
|
+
return builder;
|
|
34
|
+
},
|
|
35
|
+
get() {
|
|
36
|
+
return shareAllCore(nodeIo, baseCfg, {
|
|
37
|
+
skipList,
|
|
38
|
+
projectPath,
|
|
39
|
+
overrides,
|
|
40
|
+
patchList
|
|
41
|
+
});
|
|
234
42
|
}
|
|
235
|
-
}
|
|
236
|
-
return
|
|
237
|
-
}
|
|
43
|
+
};
|
|
44
|
+
return builder;
|
|
45
|
+
};
|
|
238
46
|
function shareAll(config, opts = {}) {
|
|
239
47
|
return shareAllCore(nodeIo, config, opts);
|
|
240
48
|
}
|
|
@@ -251,32 +59,35 @@ function shareAllCore(io, config, opts = {}, repo = sharedPackageJsonRepository)
|
|
|
251
59
|
if (!!opts.overrides && Object.keys(opts.overrides).some((o) => key.startsWith(o))) {
|
|
252
60
|
continue;
|
|
253
61
|
}
|
|
254
|
-
const
|
|
255
|
-
const requiredVersion =
|
|
62
|
+
const inferVersion = !config.requiredVersion || config.requiredVersion === "auto";
|
|
63
|
+
const requiredVersion = inferVersion ? versions[key] : config.requiredVersion;
|
|
256
64
|
if (!sharedExternals[key]) {
|
|
257
65
|
sharedExternals[key] = { ...config, requiredVersion };
|
|
258
66
|
}
|
|
259
67
|
}
|
|
260
68
|
}
|
|
69
|
+
const finalExternalList = applyPatchList(sharedExternals, opts.patchList, opts.overrides);
|
|
261
70
|
return {
|
|
262
|
-
...shareCore(io,
|
|
71
|
+
...shareCore(io, finalExternalList, opts.projectPath, skipList, repo),
|
|
263
72
|
...!opts.overrides ? {} : shareCore(io, opts.overrides, opts.projectPath, skipList, repo)
|
|
264
73
|
};
|
|
265
74
|
}
|
|
266
|
-
function
|
|
267
|
-
if (!
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
if (!projectPath && getConfigContext().workspaceRoot) {
|
|
271
|
-
projectPath = getConfigContext().workspaceRoot || "";
|
|
75
|
+
function applyPatchList(sharedExternals, patchList, overrides) {
|
|
76
|
+
if (!patchList) {
|
|
77
|
+
return sharedExternals;
|
|
272
78
|
}
|
|
273
|
-
|
|
274
|
-
|
|
79
|
+
const result = { ...sharedExternals };
|
|
80
|
+
for (const [external, cfg] of Object.entries(patchList)) {
|
|
81
|
+
if (!result[external]) {
|
|
82
|
+
const shadowedByOverride = !!overrides && Object.keys(overrides).some((o) => external.startsWith(o));
|
|
83
|
+
logger.warn(
|
|
84
|
+
shadowedByOverride ? `Ignoring patch for '${external}': it is already configured via 'overrides' ('patch' and 'overrides' are mutually exclusive per external).` : `Ignoring patch for '${external}': it is not a shared external (unknown dependency or skipped).`
|
|
85
|
+
);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
result[external] = { ...result[external], ...cfg };
|
|
275
89
|
}
|
|
276
|
-
return
|
|
277
|
-
}
|
|
278
|
-
function setInferVersion(infer) {
|
|
279
|
-
inferVersion = infer;
|
|
90
|
+
return result;
|
|
280
91
|
}
|
|
281
92
|
function share(configuredShareObjects, projectPath = "", skipList = DEFAULT_SKIP_LIST) {
|
|
282
93
|
return shareCore(nodeIo, configuredShareObjects, projectPath, skipList);
|
|
@@ -287,11 +98,10 @@ function shareCore(io, configuredShareObjects, projectPath = "", skipList = DEFA
|
|
|
287
98
|
const preparedSkipList = prepareSkipList(skipList);
|
|
288
99
|
const shareObjects = { ...configuredShareObjects };
|
|
289
100
|
const result = {};
|
|
290
|
-
let includeSecondaries;
|
|
291
101
|
for (const key in shareObjects) {
|
|
292
|
-
includeSecondaries = false;
|
|
102
|
+
let includeSecondaries = false;
|
|
293
103
|
const shareObject = shareObjects[key];
|
|
294
|
-
if (shareObject.requiredVersion === "auto" ||
|
|
104
|
+
if (shareObject.requiredVersion === "auto" || isInferVersion() && typeof shareObject.requiredVersion === "undefined" || (shareObject.requiredVersion?.length ?? 1) < 1) {
|
|
295
105
|
const version = lookupVersion(key, projectPath, repo);
|
|
296
106
|
shareObject.requiredVersion = version;
|
|
297
107
|
shareObject.version = version.replace(/^\D*/, "");
|
|
@@ -302,7 +112,9 @@ function shareCore(io, configuredShareObjects, projectPath = "", skipList = DEFA
|
|
|
302
112
|
if (shareObject.includeSecondaries) {
|
|
303
113
|
includeSecondaries = shareObject.includeSecondaries;
|
|
304
114
|
delete shareObject.includeSecondaries;
|
|
305
|
-
if (includeSecondaries
|
|
115
|
+
if (typeof includeSecondaries === "object" && includeSecondaries.keepAll) {
|
|
116
|
+
shareObject.includeSecondaries = true;
|
|
117
|
+
}
|
|
306
118
|
}
|
|
307
119
|
result[key] = shareObject;
|
|
308
120
|
if (includeSecondaries) {
|
|
@@ -327,16 +139,8 @@ function shareCore(io, configuredShareObjects, projectPath = "", skipList = DEFA
|
|
|
327
139
|
}
|
|
328
140
|
return result;
|
|
329
141
|
}
|
|
330
|
-
function addSecondaries(secondaries, result) {
|
|
331
|
-
for (const key in secondaries) {
|
|
332
|
-
result[key] = secondaries[key];
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
142
|
export {
|
|
336
|
-
|
|
337
|
-
findRootTsConfigJsonCore,
|
|
338
|
-
getSecondaries,
|
|
339
|
-
setInferVersion,
|
|
143
|
+
fromPackageJson,
|
|
340
144
|
share,
|
|
341
145
|
shareAll,
|
|
342
146
|
shareAllCore,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PackageJsonRepository } from '../domain/utils/package-json.contract.js';
|
|
2
|
+
export declare function setInferVersion(infer: boolean): void;
|
|
3
|
+
export declare function isInferVersion(): boolean;
|
|
4
|
+
export declare function lookupVersion(key: string, workspaceRoot: string, repo: PackageJsonRepository): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { getVersionMaps } from "../utils/package/package-info.js";
|
|
2
|
+
let inferVersion = false;
|
|
3
|
+
function setInferVersion(infer) {
|
|
4
|
+
inferVersion = infer;
|
|
5
|
+
}
|
|
6
|
+
function isInferVersion() {
|
|
7
|
+
return inferVersion;
|
|
8
|
+
}
|
|
9
|
+
function lookupVersion(key, workspaceRoot, repo) {
|
|
10
|
+
const versionMaps = getVersionMaps(workspaceRoot, workspaceRoot, repo);
|
|
11
|
+
for (const versionMap of versionMaps) {
|
|
12
|
+
const version = lookupVersionInMap(key, versionMap);
|
|
13
|
+
if (version) {
|
|
14
|
+
return version;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
throw new Error(
|
|
18
|
+
`Shared Dependency ${key} has requiredVersion:'auto'. However, this dependency is not found in your package.json`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function lookupVersionInMap(key, versions) {
|
|
22
|
+
const parts = key.split("/");
|
|
23
|
+
if (parts.length >= 2 && parts[0].startsWith("@")) {
|
|
24
|
+
key = parts[0] + "/" + parts[1];
|
|
25
|
+
} else {
|
|
26
|
+
key = parts[0];
|
|
27
|
+
}
|
|
28
|
+
if (!versions[key]) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return versions[key];
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
isInferVersion,
|
|
35
|
+
lookupVersion,
|
|
36
|
+
setInferVersion
|
|
37
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getRawMappedPaths } from "./mapped-paths.js";
|
|
2
|
-
import {
|
|
2
|
+
import { fromPackageJson } from "./share-utils.js";
|
|
3
|
+
import { findRootTsConfigJson } from "./project-paths.js";
|
|
3
4
|
import { isInSkipList, prepareSkipList } from "./default-skip-list.js";
|
|
4
5
|
import { logger } from "../utils/logger.js";
|
|
5
6
|
function withNativeFederation(config) {
|
|
@@ -18,6 +19,7 @@ function withNativeFederation(config) {
|
|
|
18
19
|
mappingVersion: config.features?.mappingVersion ?? true,
|
|
19
20
|
ignoreUnusedDeps: config.features?.ignoreUnusedDeps ?? true,
|
|
20
21
|
denseChunking: config.features?.denseChunking ?? false,
|
|
22
|
+
denseExternals: config.features?.denseExternals ?? false,
|
|
21
23
|
integrityHashes: config.features?.integrityHashes ?? false
|
|
22
24
|
},
|
|
23
25
|
...config.shareScope && { shareScope: config.shareScope }
|
|
@@ -35,12 +37,12 @@ function normalizeExposes(exposes) {
|
|
|
35
37
|
}
|
|
36
38
|
function normalizeShared(config, skip, chunks) {
|
|
37
39
|
let result = {};
|
|
38
|
-
const shared = config.shared ??
|
|
40
|
+
const shared = config.shared ?? fromPackageJson({
|
|
39
41
|
singleton: true,
|
|
40
42
|
strictVersion: true,
|
|
41
43
|
requiredVersion: "auto",
|
|
42
44
|
platform: "browser"
|
|
43
|
-
});
|
|
45
|
+
}).get();
|
|
44
46
|
result = Object.keys(shared).reduce((acc, cur) => {
|
|
45
47
|
const key = cur.replace(/\\/g, "/");
|
|
46
48
|
const sharedConfig = shared[cur];
|
|
@@ -56,11 +58,12 @@ function normalizeShared(config, skip, chunks) {
|
|
|
56
58
|
strictVersion: sharedConfig.strictVersion ?? false,
|
|
57
59
|
version: sharedConfig.version,
|
|
58
60
|
chunks: sharedConfig.chunks ?? chunks,
|
|
59
|
-
includeSecondaries: sharedConfig.includeSecondaries,
|
|
61
|
+
includeSecondaries: typeof sharedConfig.includeSecondaries === "object" ? !!sharedConfig.includeSecondaries.keepAll : sharedConfig.includeSecondaries,
|
|
60
62
|
packageInfo: sharedConfig.packageInfo,
|
|
61
63
|
platform: sharedConfig.platform ?? config.platform ?? "browser",
|
|
62
64
|
build: sharedConfig.build ?? "default",
|
|
63
|
-
...sharedConfig.shareScope && { shareScope: sharedConfig.shareScope }
|
|
65
|
+
...sharedConfig.shareScope && { shareScope: sharedConfig.shareScope },
|
|
66
|
+
...sharedConfig.pool && { pool: sharedConfig.pool }
|
|
64
67
|
};
|
|
65
68
|
return {
|
|
66
69
|
...acc,
|
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
describeSharedMappings
|
|
5
5
|
} from "./bundle-exposed-and-mappings.js";
|
|
6
6
|
import { bundleShared } from "./bundle-shared.js";
|
|
7
|
+
import { densifyExternals } from "../output/densify-externals.js";
|
|
7
8
|
import { writeFederationInfo } from "../output/write-federation-info.js";
|
|
8
9
|
import { writeImportMap } from "../output/write-import-map.js";
|
|
9
10
|
import { logger } from "../../utils/logger.js";
|
|
10
|
-
import { normalizePackageName } from "../../utils/normalize.js";
|
|
11
|
+
import { inferPackageFromSecondary, normalizePackageName } from "../../utils/normalize.js";
|
|
11
12
|
import { AbortedError } from "../../utils/errors.js";
|
|
12
13
|
import { addExternalsToCache } from "../cache/federation-cache.js";
|
|
13
14
|
import path from "path";
|
|
@@ -97,10 +98,11 @@ async function buildForFederation(config, fedOptions, externals, signal) {
|
|
|
97
98
|
if (!external.shareScope) external.shareScope = config.shareScope;
|
|
98
99
|
});
|
|
99
100
|
}
|
|
101
|
+
const shared = config.features.denseExternals ? densifyExternals(sharedExternals) : sharedExternals;
|
|
100
102
|
const buildNotificationsEndpoint = fedOptions.buildNotifications?.enable && fedOptions.dev ? fedOptions.buildNotifications?.endpoint : void 0;
|
|
101
103
|
const federationInfo = {
|
|
102
104
|
name: config.name,
|
|
103
|
-
shared
|
|
105
|
+
shared,
|
|
104
106
|
exposes: exposedInfo,
|
|
105
107
|
buildNotificationsEndpoint
|
|
106
108
|
};
|
|
@@ -120,13 +122,6 @@ async function buildForFederation(config, fedOptions, externals, signal) {
|
|
|
120
122
|
writeImportMap(fedOptions.federationCache, fedOptions, federationInfo.integrity);
|
|
121
123
|
return federationInfo;
|
|
122
124
|
}
|
|
123
|
-
function inferPackageFromSecondary(secondary) {
|
|
124
|
-
const parts = secondary.split("/");
|
|
125
|
-
if (secondary.startsWith("@") && parts.length >= 2) {
|
|
126
|
-
return parts[0] + "/" + parts[1];
|
|
127
|
-
}
|
|
128
|
-
return parts[0];
|
|
129
|
-
}
|
|
130
125
|
async function bundleSeparatePackages(separateBrowser, externals, config, fedOptions, buildOptions) {
|
|
131
126
|
const groupedByPackage = {};
|
|
132
127
|
for (const [key, shared] of Object.entries(separateBrowser)) {
|
|
@@ -193,13 +193,8 @@ function buildResult(packageInfos, sharedBundles, outFileNames) {
|
|
|
193
193
|
singleton: shared?.singleton,
|
|
194
194
|
strictVersion: shared?.strictVersion,
|
|
195
195
|
version: pi.version,
|
|
196
|
-
...shared?.shareScope && { shareScope: shared.shareScope }
|
|
197
|
-
|
|
198
|
-
// dev: !fedOptions.dev
|
|
199
|
-
// ? undefined
|
|
200
|
-
// : {
|
|
201
|
-
// entryPoint: normalize(pi.entryPoint),
|
|
202
|
-
// },
|
|
196
|
+
...shared?.shareScope && { shareScope: shared.shareScope },
|
|
197
|
+
...shared?.pool && { pool: shared.pool }
|
|
203
198
|
};
|
|
204
199
|
});
|
|
205
200
|
}
|
|
@@ -212,14 +207,12 @@ function addChunksToResult(chunks, result) {
|
|
|
212
207
|
result.push({
|
|
213
208
|
singleton: false,
|
|
214
209
|
strictVersion: false,
|
|
215
|
-
// Here, the version
|
|
210
|
+
// Here, the version, singleton and strictversion
|
|
211
|
+
// do not matter because
|
|
216
212
|
// a) a chunk split off by the bundler does
|
|
217
213
|
// not have a version and b) it gets a hash
|
|
218
214
|
// code as part of the file name to be unique
|
|
219
215
|
// when requested via a _versioned_ package.
|
|
220
|
-
//
|
|
221
|
-
// For the same reason, we don't need to
|
|
222
|
-
// take care of singleton and strictVersion.
|
|
223
216
|
version: "0.0.0",
|
|
224
217
|
requiredVersion: "0.0.0",
|
|
225
218
|
packageName: toChunkImport(fileName),
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SharedInfo, DenseSharedInfo } from '../../domain/core/federation-info.contract.js';
|
|
2
|
+
/**
|
|
3
|
+
* Groups a flat `shared` array into {@link DenseSharedInfo} objects: one per shared external,
|
|
4
|
+
* with an `entries` map from each import name to its output file. Entries sharing a parent
|
|
5
|
+
* package but with differing metadata split into separate groups. Bundler chunks and
|
|
6
|
+
* already-dense entries pass through unchanged.
|
|
7
|
+
*/
|
|
8
|
+
export declare function densifyExternals(shared: Array<SharedInfo | DenseSharedInfo>): Array<SharedInfo | DenseSharedInfo>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { CHUNK_PREFIX } from "../../domain/core/chunk.js";
|
|
2
|
+
import { inferPackageFromSecondary } from "../../utils/normalize.js";
|
|
3
|
+
function isDense(entry) {
|
|
4
|
+
return "entries" in entry;
|
|
5
|
+
}
|
|
6
|
+
function isChunk(entry) {
|
|
7
|
+
return entry.packageName.startsWith(CHUNK_PREFIX + "/");
|
|
8
|
+
}
|
|
9
|
+
function densifyExternals(shared) {
|
|
10
|
+
const result = [];
|
|
11
|
+
const groupIndex = /* @__PURE__ */ new Map();
|
|
12
|
+
for (const entry of shared) {
|
|
13
|
+
if (isDense(entry) || isChunk(entry)) {
|
|
14
|
+
result.push(entry);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const parent = inferPackageFromSecondary(entry.packageName);
|
|
18
|
+
const sig = JSON.stringify({
|
|
19
|
+
singleton: entry.singleton,
|
|
20
|
+
strictVersion: entry.strictVersion,
|
|
21
|
+
requiredVersion: entry.requiredVersion,
|
|
22
|
+
version: entry.version,
|
|
23
|
+
shareScope: entry.shareScope
|
|
24
|
+
});
|
|
25
|
+
const key = parent + " " + sig;
|
|
26
|
+
const existing = groupIndex.get(key);
|
|
27
|
+
if (existing === void 0) {
|
|
28
|
+
const dense = {
|
|
29
|
+
singleton: entry.singleton,
|
|
30
|
+
strictVersion: entry.strictVersion,
|
|
31
|
+
requiredVersion: entry.requiredVersion,
|
|
32
|
+
packageName: parent,
|
|
33
|
+
entries: { [entry.packageName]: entry.outFileName }
|
|
34
|
+
};
|
|
35
|
+
if (entry.version !== void 0) dense.version = entry.version;
|
|
36
|
+
if (entry.shareScope !== void 0) dense.shareScope = entry.shareScope;
|
|
37
|
+
if (entry.bundle !== void 0) dense.bundle = entry.bundle;
|
|
38
|
+
if (entry.dev !== void 0) dense.dev = entry.dev;
|
|
39
|
+
groupIndex.set(key, result.length);
|
|
40
|
+
result.push(dense);
|
|
41
|
+
} else {
|
|
42
|
+
result[existing].entries[entry.packageName] = entry.outFileName;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
densifyExternals
|
|
49
|
+
};
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
export type IncludeSecondariesOptions = {
|
|
2
|
+
skip?: string | string[];
|
|
3
|
+
resolveGlob?: boolean;
|
|
4
|
+
keepAll?: boolean;
|
|
5
|
+
} | boolean;
|
|
1
6
|
export interface ExternalConfig {
|
|
2
7
|
singleton?: boolean;
|
|
3
8
|
strictVersion?: boolean;
|
|
4
9
|
requiredVersion?: string;
|
|
5
10
|
version?: string;
|
|
6
|
-
includeSecondaries?:
|
|
11
|
+
includeSecondaries?: IncludeSecondariesOptions;
|
|
7
12
|
platform?: 'browser' | 'node';
|
|
8
13
|
build?: 'separate' | 'package';
|
|
14
|
+
pool?: string;
|
|
9
15
|
chunks?: boolean;
|
|
10
16
|
shareScope?: string;
|
|
11
17
|
packageInfo?: {
|
|
@@ -21,6 +27,7 @@ export interface NormalizedExternalConfig {
|
|
|
21
27
|
version?: string;
|
|
22
28
|
includeSecondaries?: boolean;
|
|
23
29
|
shareScope?: string;
|
|
30
|
+
pool?: string;
|
|
24
31
|
chunks: boolean;
|
|
25
32
|
platform: 'browser' | 'node';
|
|
26
33
|
build: 'default' | 'separate' | 'package';
|
|
@@ -30,14 +37,11 @@ export interface NormalizedExternalConfig {
|
|
|
30
37
|
esm: boolean;
|
|
31
38
|
};
|
|
32
39
|
}
|
|
33
|
-
export type IncludeSecondariesOptions = {
|
|
34
|
-
skip?: string | string[];
|
|
35
|
-
resolveGlob?: boolean;
|
|
36
|
-
keepAll?: boolean;
|
|
37
|
-
} | boolean;
|
|
38
40
|
export type SharedExternalsConfig = Record<string, ExternalConfig>;
|
|
39
41
|
export type NormalizedSharedExternalsConfig = Record<string, NormalizedExternalConfig>;
|
|
40
|
-
export type ShareAllExternalsOptions =
|
|
41
|
-
|
|
42
|
+
export type ShareAllExternalsOptions = ExternalConfig;
|
|
43
|
+
export type ShareExternalsOptions = SharedExternalsConfig;
|
|
44
|
+
export type ResolvedExternalConfig = Omit<ExternalConfig, 'includeSecondaries'> & {
|
|
45
|
+
includeSecondaries?: boolean;
|
|
42
46
|
};
|
|
43
|
-
export type
|
|
47
|
+
export type ResolvedSharedExternalsConfig = Record<string, ResolvedExternalConfig>;
|
|
@@ -19,6 +19,7 @@ export interface FederationConfig {
|
|
|
19
19
|
mappingVersion?: boolean;
|
|
20
20
|
ignoreUnusedDeps?: boolean;
|
|
21
21
|
denseChunking?: boolean;
|
|
22
|
+
denseExternals?: boolean;
|
|
22
23
|
integrityHashes?: boolean;
|
|
23
24
|
};
|
|
24
25
|
}
|
|
@@ -36,6 +37,7 @@ export interface NormalizedFederationConfig {
|
|
|
36
37
|
mappingVersion: boolean;
|
|
37
38
|
ignoreUnusedDeps: boolean;
|
|
38
39
|
denseChunking: boolean;
|
|
40
|
+
denseExternals: boolean;
|
|
39
41
|
integrityHashes: boolean;
|
|
40
42
|
};
|
|
41
43
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { ExternalConfig, IncludeSecondariesOptions, SharedExternalsConfig, ShareAllExternalsOptions, ShareExternalsOptions, } from './external-config.contract.js';
|
|
1
|
+
export type { ExternalConfig, IncludeSecondariesOptions, ResolvedExternalConfig, ResolvedSharedExternalsConfig, SharedExternalsConfig, ShareAllExternalsOptions, ShareExternalsOptions, } from './external-config.contract.js';
|
|
2
2
|
export type { FederationConfig } from './federation-config.contract.js';
|
|
3
3
|
export type { PreparedSkipList, SkipFn, SkipList, SkipListEntry } from './skip-list.contract.js';
|