@softarc/native-federation-orchestrator 4.5.2 → 4.5.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/README.md +2 -2
- package/fesm2022/@softarc/native-federation-orchestrator.mjs +315 -99
- package/fesm2022/@softarc/native-federation-orchestrator.mjs.map +4 -4
- package/fesm2022/module-federation.mjs +25 -20
- package/fesm2022/module-federation.mjs.map +2 -2
- package/fesm2022/node.mjs +315 -99
- package/fesm2022/node.mjs.map +3 -3
- package/fesm2022/options.mjs +5 -10
- package/fesm2022/options.mjs.map +2 -2
- package/package.json +2 -2
- package/quickstart.mjs +15 -15
- package/types/lib/core/1.domain/externals/basis.d.ts +7 -0
- package/types/lib/core/1.domain/remote-entry/remote-entry.contract.d.ts +1 -0
- package/types/lib/core/2.app/config/mode.contract.d.ts +1 -0
- package/types/lib/core/2.app/driving-ports/for-shared-externals-storage.port.d.ts +1 -1
- package/types/lib/core/2.app/steps/store-remote-entry.d.ts +15 -7
package/fesm2022/node.mjs
CHANGED
|
@@ -1490,16 +1490,21 @@ var createRemoteInfoRepository = (config) => {
|
|
|
1490
1490
|
const STORAGE = config.storage("remotes", {});
|
|
1491
1491
|
if (config.clearStorage) STORAGE.clear();
|
|
1492
1492
|
const _cache = STORAGE.get() ?? {};
|
|
1493
|
+
let _dirty = false;
|
|
1493
1494
|
return {
|
|
1494
1495
|
contains: function(remoteName) {
|
|
1495
1496
|
return !!_cache[remoteName];
|
|
1496
1497
|
},
|
|
1497
1498
|
remove: function(remoteName) {
|
|
1498
|
-
|
|
1499
|
+
if (remoteName in _cache) {
|
|
1500
|
+
delete _cache[remoteName];
|
|
1501
|
+
_dirty = true;
|
|
1502
|
+
}
|
|
1499
1503
|
return this;
|
|
1500
1504
|
},
|
|
1501
1505
|
addOrUpdate: function(remoteName, remote) {
|
|
1502
1506
|
_cache[remoteName] = remote;
|
|
1507
|
+
_dirty = true;
|
|
1503
1508
|
return this;
|
|
1504
1509
|
},
|
|
1505
1510
|
tryGet: function(remoteName) {
|
|
@@ -1514,7 +1519,9 @@ var createRemoteInfoRepository = (config) => {
|
|
|
1514
1519
|
return _cache;
|
|
1515
1520
|
},
|
|
1516
1521
|
commit: function() {
|
|
1522
|
+
if (!_dirty) return this;
|
|
1517
1523
|
STORAGE.set(_cache);
|
|
1524
|
+
_dirty = false;
|
|
1518
1525
|
return this;
|
|
1519
1526
|
}
|
|
1520
1527
|
};
|
|
@@ -1525,14 +1532,19 @@ var createScopedExternalsRepository = (config) => {
|
|
|
1525
1532
|
const STORAGE = config.storage("scoped-externals", {});
|
|
1526
1533
|
if (config.clearStorage) STORAGE.clear();
|
|
1527
1534
|
const _cache = STORAGE.get() ?? {};
|
|
1535
|
+
let _dirty = false;
|
|
1528
1536
|
return {
|
|
1529
1537
|
addExternal: function(remoteName, external, version) {
|
|
1530
1538
|
if (!_cache[remoteName]) _cache[remoteName] = {};
|
|
1531
1539
|
_cache[remoteName][external] = version;
|
|
1540
|
+
_dirty = true;
|
|
1532
1541
|
return this;
|
|
1533
1542
|
},
|
|
1534
1543
|
remove: function(remoteName) {
|
|
1535
|
-
|
|
1544
|
+
if (remoteName in _cache) {
|
|
1545
|
+
delete _cache[remoteName];
|
|
1546
|
+
_dirty = true;
|
|
1547
|
+
}
|
|
1536
1548
|
return this;
|
|
1537
1549
|
},
|
|
1538
1550
|
getAll: function() {
|
|
@@ -1542,7 +1554,9 @@ var createScopedExternalsRepository = (config) => {
|
|
|
1542
1554
|
return Optional.of(_cache[remoteName]);
|
|
1543
1555
|
},
|
|
1544
1556
|
commit: function() {
|
|
1557
|
+
if (!_dirty) return this;
|
|
1545
1558
|
STORAGE.set(_cache);
|
|
1559
|
+
_dirty = false;
|
|
1546
1560
|
return this;
|
|
1547
1561
|
}
|
|
1548
1562
|
};
|
|
@@ -1559,8 +1573,9 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1559
1573
|
{ [GLOBAL_SCOPE]: {} }
|
|
1560
1574
|
);
|
|
1561
1575
|
if (config.clearStorage) STORAGE.clear();
|
|
1562
|
-
const _cache = STORAGE.get();
|
|
1576
|
+
const _cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
1563
1577
|
let _sawPoolTag = false;
|
|
1578
|
+
let _dirty = false;
|
|
1564
1579
|
return {
|
|
1565
1580
|
markPoolTagPresent: function() {
|
|
1566
1581
|
_sawPoolTag = true;
|
|
@@ -1574,28 +1589,38 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1574
1589
|
addOrUpdate: function(externalName, external, shareScope) {
|
|
1575
1590
|
if (!_cache[shareScope ?? GLOBAL_SCOPE]) _cache[shareScope ?? GLOBAL_SCOPE] = {};
|
|
1576
1591
|
_cache[shareScope ?? GLOBAL_SCOPE][externalName] = external;
|
|
1592
|
+
_dirty = true;
|
|
1577
1593
|
return this;
|
|
1578
1594
|
},
|
|
1579
1595
|
getScopes: function(o = { includeGlobal: true }) {
|
|
1580
1596
|
if (o.includeGlobal) return Object.keys(_cache);
|
|
1581
1597
|
return Object.keys(_cache).filter((s) => s !== GLOBAL_SCOPE);
|
|
1582
1598
|
},
|
|
1583
|
-
|
|
1599
|
+
// Batched: one traversal of the graph per init instead of one per overridden remote.
|
|
1600
|
+
removeFromAllScopes: function(remoteNames) {
|
|
1601
|
+
if (remoteNames.size === 0) return;
|
|
1584
1602
|
Object.values(_cache).forEach((scope) => {
|
|
1585
1603
|
const removeExternals = [];
|
|
1586
1604
|
Object.entries(scope).forEach(([name, external]) => {
|
|
1587
|
-
|
|
1588
|
-
external.versions.
|
|
1589
|
-
const
|
|
1590
|
-
|
|
1591
|
-
|
|
1605
|
+
let removedVersion = false;
|
|
1606
|
+
for (let i = external.versions.length - 1; i >= 0; i--) {
|
|
1607
|
+
const remotes = external.versions[i].remotes;
|
|
1608
|
+
let keep = 0;
|
|
1609
|
+
for (let r = 0; r < remotes.length; r++) {
|
|
1610
|
+
if (remoteNames.has(remotes[r].name)) continue;
|
|
1611
|
+
remotes[keep++] = remotes[r];
|
|
1592
1612
|
}
|
|
1593
|
-
if (
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
for (let i = removeVersionIdx.length - 1; i >= 0; i--) {
|
|
1597
|
-
external.versions.splice(removeVersionIdx[i], 1);
|
|
1613
|
+
if (keep !== remotes.length) {
|
|
1614
|
+
remotes.length = keep;
|
|
1615
|
+
_dirty = true;
|
|
1598
1616
|
}
|
|
1617
|
+
if (remotes.length === 0) {
|
|
1618
|
+
external.versions.splice(i, 1);
|
|
1619
|
+
removedVersion = true;
|
|
1620
|
+
_dirty = true;
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
if (removedVersion) {
|
|
1599
1624
|
external.dirty = true;
|
|
1600
1625
|
if (external.versions.length === 0) removeExternals.push(name);
|
|
1601
1626
|
}
|
|
@@ -1619,7 +1644,9 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1619
1644
|
return Optional.of(_cache[shareScope ?? GLOBAL_SCOPE]?.[external]);
|
|
1620
1645
|
},
|
|
1621
1646
|
commit: function() {
|
|
1647
|
+
if (!_dirty) return this;
|
|
1622
1648
|
STORAGE.set(_cache);
|
|
1649
|
+
_dirty = false;
|
|
1623
1650
|
return this;
|
|
1624
1651
|
}
|
|
1625
1652
|
};
|
|
@@ -1630,17 +1657,21 @@ var createChunkRepository = (config) => {
|
|
|
1630
1657
|
const STORAGE = config.storage("shared-chunks", {});
|
|
1631
1658
|
if (config.clearStorage) STORAGE.clear();
|
|
1632
1659
|
const _cache = STORAGE.get() ?? {};
|
|
1660
|
+
let _dirty = false;
|
|
1633
1661
|
return {
|
|
1634
1662
|
addOrReplace: function(remoteName, bundleName, chunks) {
|
|
1635
1663
|
if (!_cache[remoteName]) _cache[remoteName] = {};
|
|
1636
1664
|
_cache[remoteName][bundleName] = chunks;
|
|
1665
|
+
_dirty = true;
|
|
1637
1666
|
return this;
|
|
1638
1667
|
},
|
|
1639
1668
|
tryGet: function(remoteName, bundleName) {
|
|
1640
1669
|
return Optional.of(_cache[remoteName]?.[bundleName]);
|
|
1641
1670
|
},
|
|
1642
1671
|
commit: function() {
|
|
1672
|
+
if (!_dirty) return this;
|
|
1643
1673
|
STORAGE.set(_cache);
|
|
1674
|
+
_dirty = false;
|
|
1644
1675
|
return this;
|
|
1645
1676
|
}
|
|
1646
1677
|
};
|
|
@@ -1830,10 +1861,9 @@ var globalThisStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
1830
1861
|
globalThis[namespace] = {};
|
|
1831
1862
|
}
|
|
1832
1863
|
const storage = globalThis[namespace];
|
|
1833
|
-
if (!storage[key]) storage[key] = initialValue;
|
|
1834
1864
|
const entry = {
|
|
1835
1865
|
get() {
|
|
1836
|
-
return cloneEntry(key, storage[key]);
|
|
1866
|
+
return cloneEntry(key, key in storage ? storage[key] : initialValue);
|
|
1837
1867
|
},
|
|
1838
1868
|
set(value) {
|
|
1839
1869
|
storage[key] = cloneEntry(key, value);
|
|
@@ -1857,6 +1887,7 @@ var createStorageConfig = (override) => ({
|
|
|
1857
1887
|
var defaultProfile = {
|
|
1858
1888
|
latestSharedExternal: false,
|
|
1859
1889
|
skipInvalidExternalVersions: false,
|
|
1890
|
+
scopeUncoveredEntrypoints: false,
|
|
1860
1891
|
overrideCachedRemotes: "init-only",
|
|
1861
1892
|
overrideCachedRemotesIfURLMatches: false
|
|
1862
1893
|
};
|
|
@@ -2022,19 +2053,71 @@ function createGetRemoteEntries(config, ports) {
|
|
|
2022
2053
|
}
|
|
2023
2054
|
}
|
|
2024
2055
|
|
|
2056
|
+
// src/lib/core/1.domain/externals/basis.ts
|
|
2057
|
+
var coverage = (remote) => Object.keys(remote.entries).length;
|
|
2058
|
+
function isBetterBasis(candidate, basis) {
|
|
2059
|
+
if (basis.cached !== candidate.cached) return candidate.cached;
|
|
2060
|
+
return coverage(candidate) > coverage(basis);
|
|
2061
|
+
}
|
|
2062
|
+
function addRemoteToVersion(version, remote, isHost = false) {
|
|
2063
|
+
if (isHost) {
|
|
2064
|
+
version.host = true;
|
|
2065
|
+
version.remotes.unshift(remote);
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
const basis = version.remotes[0];
|
|
2069
|
+
if (basis && !version.host && isBetterBasis(remote, basis)) {
|
|
2070
|
+
version.remotes.unshift(remote);
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
version.remotes.push(remote);
|
|
2074
|
+
}
|
|
2075
|
+
function versionDemands(version) {
|
|
2076
|
+
if (version.remotes.length < 2) return version.remotes;
|
|
2077
|
+
const distinct = /* @__PURE__ */ new Map();
|
|
2078
|
+
for (const remote of version.remotes) {
|
|
2079
|
+
const key = `${remote.requiredVersion}|${remote.strictVersion}|${remote.cached}`;
|
|
2080
|
+
if (!distinct.has(key)) distinct.set(key, remote);
|
|
2081
|
+
}
|
|
2082
|
+
return Array.from(distinct.values());
|
|
2083
|
+
}
|
|
2084
|
+
function findVersionForTag(versions, tag) {
|
|
2085
|
+
let scoped;
|
|
2086
|
+
for (const version of versions) {
|
|
2087
|
+
if (version.tag !== tag) continue;
|
|
2088
|
+
if (version.action !== "scope") return version;
|
|
2089
|
+
scoped ??= version;
|
|
2090
|
+
}
|
|
2091
|
+
return scoped;
|
|
2092
|
+
}
|
|
2093
|
+
function uncoveredEntrypoints(remote, basis) {
|
|
2094
|
+
return Object.keys(remote.entries).filter((entrypoint) => !(entrypoint in basis));
|
|
2095
|
+
}
|
|
2096
|
+
function countUncoveredEntrypoints(remote, basis) {
|
|
2097
|
+
let uncovered = 0;
|
|
2098
|
+
for (const entrypoint in remote.entries) {
|
|
2099
|
+
if (!(entrypoint in basis)) uncovered++;
|
|
2100
|
+
}
|
|
2101
|
+
return uncovered;
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2025
2104
|
// src/lib/core/2.app/steps/store-remote-entry.ts
|
|
2105
|
+
function createRemoveCachedRemoteEntries(ports) {
|
|
2106
|
+
return (remoteNames) => {
|
|
2107
|
+
if (remoteNames.size === 0) return;
|
|
2108
|
+
for (const remoteName of remoteNames) {
|
|
2109
|
+
ports.remoteInfoRepo.remove(remoteName);
|
|
2110
|
+
ports.scopedExternalsRepo.remove(remoteName);
|
|
2111
|
+
}
|
|
2112
|
+
ports.sharedExternalsRepo.removeFromAllScopes(remoteNames);
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2026
2115
|
function createStoreRemoteEntry(config, ports, logStep) {
|
|
2027
2116
|
return (remoteEntry, onSharedExternal) => {
|
|
2028
|
-
if (remoteEntry?.override) removeCachedRemoteEntry(remoteEntry);
|
|
2029
2117
|
addRemoteInfoToStorage(remoteEntry);
|
|
2030
2118
|
addExternalsToStorage(remoteEntry, onSharedExternal);
|
|
2031
2119
|
addSharedChunksToStorage(remoteEntry);
|
|
2032
2120
|
};
|
|
2033
|
-
function removeCachedRemoteEntry(remoteEntry) {
|
|
2034
|
-
ports.remoteInfoRepo.remove(remoteEntry.name);
|
|
2035
|
-
ports.scopedExternalsRepo.remove(remoteEntry.name);
|
|
2036
|
-
ports.sharedExternalsRepo.removeFromAllScopes(remoteEntry.name);
|
|
2037
|
-
}
|
|
2038
2121
|
function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
|
|
2039
2122
|
ports.remoteInfoRepo.addOrUpdate(name, {
|
|
2040
2123
|
scopeUrl: getScope(url),
|
|
@@ -2134,14 +2217,35 @@ function createStoreRemoteEntry(config, ports, logStep) {
|
|
|
2134
2217
|
// src/lib/core/2.app/steps/process-remote-entries.ts
|
|
2135
2218
|
function createProcessRemoteEntries(config, ports) {
|
|
2136
2219
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 2);
|
|
2220
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
2137
2221
|
return (remoteEntries) => {
|
|
2138
2222
|
try {
|
|
2139
|
-
|
|
2223
|
+
const evictPerEntry = evictOverriddenRemotes(remoteEntries);
|
|
2224
|
+
remoteEntries.forEach((remoteEntry) => {
|
|
2225
|
+
if (remoteEntry?.override && evictPerEntry.has(remoteEntry.name)) {
|
|
2226
|
+
removeCachedRemoteEntries(/* @__PURE__ */ new Set([remoteEntry.name]));
|
|
2227
|
+
}
|
|
2228
|
+
storeRemoteEntry(remoteEntry, addSharedExternal);
|
|
2229
|
+
});
|
|
2140
2230
|
return Promise.resolve(remoteEntries);
|
|
2141
2231
|
} catch (e) {
|
|
2142
2232
|
return Promise.reject(e);
|
|
2143
2233
|
}
|
|
2144
2234
|
};
|
|
2235
|
+
function evictOverriddenRemotes(remoteEntries) {
|
|
2236
|
+
const batched = /* @__PURE__ */ new Set();
|
|
2237
|
+
const repeated = /* @__PURE__ */ new Set();
|
|
2238
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2239
|
+
for (const remoteEntry of remoteEntries) {
|
|
2240
|
+
if (!remoteEntry) continue;
|
|
2241
|
+
if (seen.has(remoteEntry.name)) repeated.add(remoteEntry.name);
|
|
2242
|
+
seen.add(remoteEntry.name);
|
|
2243
|
+
if (remoteEntry.override) batched.add(remoteEntry.name);
|
|
2244
|
+
}
|
|
2245
|
+
for (const remoteName of repeated) batched.delete(remoteName);
|
|
2246
|
+
removeCachedRemoteEntries(batched);
|
|
2247
|
+
return repeated;
|
|
2248
|
+
}
|
|
2145
2249
|
function addSharedExternal(remoteEntry, _sharedInfo, {
|
|
2146
2250
|
tag,
|
|
2147
2251
|
remote,
|
|
@@ -2150,15 +2254,12 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
2150
2254
|
assertSameVersionCompatibility,
|
|
2151
2255
|
commit
|
|
2152
2256
|
}) {
|
|
2153
|
-
|
|
2257
|
+
if (scopeType !== "strict") cached2.dirty = true;
|
|
2258
|
+
const matchingVersion = findVersionForTag(cached2.versions, tag);
|
|
2154
2259
|
if (matchingVersion) {
|
|
2155
2260
|
assertSameVersionCompatibility(matchingVersion);
|
|
2156
|
-
|
|
2157
|
-
matchingVersion.host = true;
|
|
2158
|
-
matchingVersion.remotes.unshift(remote);
|
|
2159
|
-
} else matchingVersion.remotes.push(remote);
|
|
2261
|
+
addRemoteToVersion(matchingVersion, remote, !matchingVersion.host && !!remoteEntry?.host);
|
|
2160
2262
|
} else {
|
|
2161
|
-
if (scopeType !== "strict") cached2.dirty = true;
|
|
2162
2263
|
cached2.versions.push({
|
|
2163
2264
|
tag,
|
|
2164
2265
|
action: scopeType === "strict" ? "share" : "skip",
|
|
@@ -2173,13 +2274,23 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
2173
2274
|
// src/lib/core/2.app/steps/determine-shared-externals.ts
|
|
2174
2275
|
function createDetermineSharedExternals(config, ports) {
|
|
2175
2276
|
return () => {
|
|
2277
|
+
const memo = /* @__PURE__ */ new Map();
|
|
2278
|
+
const isCompatible = (tag, requiredVersion) => {
|
|
2279
|
+
const key = `${tag}|${requiredVersion}`;
|
|
2280
|
+
let hit = memo.get(key);
|
|
2281
|
+
if (hit === void 0) {
|
|
2282
|
+
hit = ports.versionCheck.isCompatible(tag, requiredVersion);
|
|
2283
|
+
memo.set(key, hit);
|
|
2284
|
+
}
|
|
2285
|
+
return hit;
|
|
2286
|
+
};
|
|
2176
2287
|
for (const shareScope of ports.sharedExternalsRepo.getScopes()) {
|
|
2177
2288
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
2178
2289
|
try {
|
|
2179
2290
|
Object.entries(sharedExternals).filter(([_, e]) => e.dirty).forEach(
|
|
2180
2291
|
([name, external]) => ports.sharedExternalsRepo.addOrUpdate(
|
|
2181
2292
|
name,
|
|
2182
|
-
setVersionActions(name, external),
|
|
2293
|
+
setVersionActions(name, external, isCompatible),
|
|
2183
2294
|
shareScope
|
|
2184
2295
|
)
|
|
2185
2296
|
);
|
|
@@ -2202,20 +2313,26 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2202
2313
|
}
|
|
2203
2314
|
return Promise.resolve();
|
|
2204
2315
|
};
|
|
2205
|
-
function uncoveredTears(external, winner) {
|
|
2316
|
+
function uncoveredTears(external, winner, accepts) {
|
|
2206
2317
|
const basis = winner.remotes[0].entries;
|
|
2207
2318
|
return external.versions.reduce((sum, v) => {
|
|
2208
2319
|
if (v === winner) return sum;
|
|
2209
|
-
if (!
|
|
2210
|
-
return sum + v.remotes.reduce((n, r) => n +
|
|
2320
|
+
if (!accepts(v, winner.tag)) return sum;
|
|
2321
|
+
return sum + v.remotes.reduce((n, r) => n + countUncoveredEntrypoints(r, basis), 0);
|
|
2211
2322
|
}, 0);
|
|
2212
2323
|
}
|
|
2213
|
-
function setVersionActions(externalName, external) {
|
|
2324
|
+
function setVersionActions(externalName, external, isCompatible) {
|
|
2214
2325
|
if (external.versions.length === 1) {
|
|
2215
2326
|
external.versions[0].action = "share";
|
|
2327
|
+
applyEntrypointCoveragePolicy(externalName, external);
|
|
2216
2328
|
external.dirty = false;
|
|
2217
2329
|
return external;
|
|
2218
2330
|
}
|
|
2331
|
+
const demands = new Map(
|
|
2332
|
+
external.versions.map((v) => [v, versionDemands(v)])
|
|
2333
|
+
);
|
|
2334
|
+
const accepts = (version, tag) => demands.get(version).every((d) => isCompatible(tag, d.requiredVersion));
|
|
2335
|
+
const objector = (version, tag) => demands.get(version).find((d) => d.strictVersion && !isCompatible(tag, d.requiredVersion));
|
|
2219
2336
|
let sharedVersion = external.versions.find((v) => v.host);
|
|
2220
2337
|
if (!sharedVersion && config.profile.latestSharedExternal) {
|
|
2221
2338
|
sharedVersion = external.versions[0];
|
|
@@ -2225,11 +2342,17 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2225
2342
|
let leastTears = Number.MAX_VALUE;
|
|
2226
2343
|
external.versions.forEach((vA) => {
|
|
2227
2344
|
const extraDownloads = external.versions.filter(
|
|
2228
|
-
(vB) =>
|
|
2345
|
+
(vB) => demands.get(vB).some((d) => !d.cached && d.strictVersion && !isCompatible(vA.tag, d.requiredVersion))
|
|
2229
2346
|
).length;
|
|
2230
|
-
|
|
2231
|
-
if (extraDownloads < leastExtraDownloads || extraDownloads === leastExtraDownloads && tears < leastTears) {
|
|
2347
|
+
if (extraDownloads < leastExtraDownloads) {
|
|
2232
2348
|
leastExtraDownloads = extraDownloads;
|
|
2349
|
+
leastTears = uncoveredTears(external, vA, accepts);
|
|
2350
|
+
sharedVersion = vA;
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
if (extraDownloads > leastExtraDownloads) return;
|
|
2354
|
+
const tears = uncoveredTears(external, vA, accepts);
|
|
2355
|
+
if (tears < leastTears) {
|
|
2233
2356
|
leastTears = tears;
|
|
2234
2357
|
sharedVersion = vA;
|
|
2235
2358
|
}
|
|
@@ -2239,39 +2362,81 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2239
2362
|
throw new NFError(`[${externalName}] Could not determine shared version!`);
|
|
2240
2363
|
}
|
|
2241
2364
|
external.versions.forEach((v) => {
|
|
2242
|
-
if (
|
|
2365
|
+
if (accepts(v, sharedVersion.tag)) {
|
|
2243
2366
|
v.action = "skip";
|
|
2244
2367
|
return;
|
|
2245
2368
|
}
|
|
2246
|
-
|
|
2369
|
+
const strict = objector(v, sharedVersion.tag);
|
|
2370
|
+
if (config.strict.strictExternalCompatibility && strict) {
|
|
2247
2371
|
config.log.error(
|
|
2248
2372
|
3,
|
|
2249
|
-
`[${
|
|
2373
|
+
`[${strict.name}][${externalName}@${v.tag}] Is not compatible with requiredRange '${strict.requiredVersion}' of shared ${externalName}@${sharedVersion.tag}.`
|
|
2250
2374
|
);
|
|
2251
2375
|
throw new NFError(`External ${externalName}@${v.tag} could not be shared.`);
|
|
2252
2376
|
}
|
|
2253
|
-
v.action =
|
|
2377
|
+
v.action = strict ? "scope" : "skip";
|
|
2254
2378
|
});
|
|
2255
2379
|
sharedVersion.action = "share";
|
|
2256
|
-
|
|
2257
|
-
const basis = sharedVersion.remotes[0].entries;
|
|
2258
|
-
external.versions.forEach((v) => {
|
|
2259
|
-
if (v.action !== "skip") return;
|
|
2260
|
-
const uncovered = v.remotes.some(
|
|
2261
|
-
(r) => Object.keys(r.entries).some((entrypoint) => !(entrypoint in basis))
|
|
2262
|
-
);
|
|
2263
|
-
if (uncovered) {
|
|
2264
|
-
v.action = "scope";
|
|
2265
|
-
config.log.debug(
|
|
2266
|
-
3,
|
|
2267
|
-
`[${externalName}@${v.tag}] Scoped: entrypoints not covered by shared ${externalName}@${sharedVersion.tag}.`
|
|
2268
|
-
);
|
|
2269
|
-
}
|
|
2270
|
-
});
|
|
2271
|
-
}
|
|
2380
|
+
applyEntrypointCoveragePolicy(externalName, external);
|
|
2272
2381
|
external.dirty = false;
|
|
2273
2382
|
return external;
|
|
2274
2383
|
}
|
|
2384
|
+
function applyEntrypointCoveragePolicy(externalName, external) {
|
|
2385
|
+
const { strictEntryPointCoverage } = config.strict;
|
|
2386
|
+
if (!strictEntryPointCoverage && !config.profile.scopeUncoveredEntrypoints) return;
|
|
2387
|
+
const tears = findTears(external);
|
|
2388
|
+
if (tears.length === 0) return;
|
|
2389
|
+
if (strictEntryPointCoverage) {
|
|
2390
|
+
const { version, remote, uncovered } = tears[0];
|
|
2391
|
+
config.log.error(
|
|
2392
|
+
3,
|
|
2393
|
+
`[${externalName}@${version.tag}][${remote.name}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
2394
|
+
);
|
|
2395
|
+
throw new NFError(
|
|
2396
|
+
`External ${externalName} could not be shared without tearing entrypoints.`
|
|
2397
|
+
);
|
|
2398
|
+
}
|
|
2399
|
+
scopeTornRemotes(externalName, external, tears);
|
|
2400
|
+
}
|
|
2401
|
+
function findTears(external) {
|
|
2402
|
+
const shared = external.versions.find((v) => v.action === "share");
|
|
2403
|
+
if (!shared) return [];
|
|
2404
|
+
const basis = shared.remotes[0].entries;
|
|
2405
|
+
const tears = [];
|
|
2406
|
+
for (const version of external.versions) {
|
|
2407
|
+
if (version.action === "scope") continue;
|
|
2408
|
+
version.remotes.forEach((remote, index) => {
|
|
2409
|
+
if (version === shared && index === 0) return;
|
|
2410
|
+
const uncovered = uncoveredEntrypoints(remote, basis);
|
|
2411
|
+
if (uncovered.length > 0) tears.push({ version, remote, uncovered });
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
return tears;
|
|
2415
|
+
}
|
|
2416
|
+
function scopeTornRemotes(externalName, external, tears) {
|
|
2417
|
+
const torn = new Set(tears.map((t) => t.remote));
|
|
2418
|
+
const demotedByTag = /* @__PURE__ */ new Map();
|
|
2419
|
+
for (const { version, remote, uncovered } of tears) {
|
|
2420
|
+
const group = demotedByTag.get(version.tag);
|
|
2421
|
+
if (group) group.push(remote);
|
|
2422
|
+
else demotedByTag.set(version.tag, [remote]);
|
|
2423
|
+
config.log.debug(
|
|
2424
|
+
3,
|
|
2425
|
+
`[${externalName}@${version.tag}][${remote.name}] Scoped: entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
2426
|
+
);
|
|
2427
|
+
}
|
|
2428
|
+
for (const version of external.versions) {
|
|
2429
|
+
if (version.remotes.some((r) => torn.has(r))) {
|
|
2430
|
+
version.remotes = version.remotes.filter((r) => !torn.has(r));
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
external.versions = external.versions.filter((v) => v.remotes.length > 0);
|
|
2434
|
+
for (const [tag, remotes] of demotedByTag) {
|
|
2435
|
+
const scoped = external.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
2436
|
+
if (scoped) scoped.remotes.push(...remotes);
|
|
2437
|
+
else external.versions.push({ tag, host: false, action: "scope", remotes });
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2275
2440
|
}
|
|
2276
2441
|
|
|
2277
2442
|
// src/lib/core/2.app/steps/pooling/pool-graph.ts
|
|
@@ -2566,6 +2731,7 @@ function createGenerateImportMap(config, ports) {
|
|
|
2566
2731
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2567
2732
|
let override = void 0;
|
|
2568
2733
|
let overrideScope = void 0;
|
|
2734
|
+
const cachedBefore = cachedFingerprint(external);
|
|
2569
2735
|
for (const version of external.versions) {
|
|
2570
2736
|
if (version.action === "scope") {
|
|
2571
2737
|
for (const remote of version.remotes) {
|
|
@@ -2611,7 +2777,7 @@ function createGenerateImportMap(config, ports) {
|
|
|
2611
2777
|
}
|
|
2612
2778
|
for (const [packageName, file] of Object.entries(r.entries)) {
|
|
2613
2779
|
if (packageName in source.entries) continue;
|
|
2614
|
-
if (config.strict.strictEntryPointCoverage) {
|
|
2780
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
2615
2781
|
warnUncoveredEntrypoint(shareScope, externalName, r.name, packageName);
|
|
2616
2782
|
continue;
|
|
2617
2783
|
}
|
|
@@ -2625,9 +2791,14 @@ function createGenerateImportMap(config, ports) {
|
|
|
2625
2791
|
addIntegrity(importMap, m.url, m.name, m.file);
|
|
2626
2792
|
}
|
|
2627
2793
|
}
|
|
2628
|
-
|
|
2794
|
+
if (cachedFingerprint(external) !== cachedBefore) {
|
|
2795
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external, shareScope);
|
|
2796
|
+
}
|
|
2629
2797
|
}
|
|
2630
2798
|
}
|
|
2799
|
+
function cachedFingerprint(external) {
|
|
2800
|
+
return external.versions.map((v) => v.remotes.map((r) => r.cached ? 1 : 0).join("")).join("|");
|
|
2801
|
+
}
|
|
2631
2802
|
function findOverride(external, shareScope, externalName) {
|
|
2632
2803
|
const sharedVersions = external.versions.filter((v) => v.action === "share");
|
|
2633
2804
|
const scopedExternalName = `${shareScope}.${externalName}`;
|
|
@@ -2659,6 +2830,7 @@ function createGenerateImportMap(config, ports) {
|
|
|
2659
2830
|
function addGlobalSharedExternals(importMap, chunkBundles) {
|
|
2660
2831
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope();
|
|
2661
2832
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2833
|
+
const cachedBefore = cachedFingerprint(external);
|
|
2662
2834
|
for (const version of external.versions) {
|
|
2663
2835
|
if (version.action === "skip") continue;
|
|
2664
2836
|
if (version.action === "scope") {
|
|
@@ -2686,31 +2858,39 @@ function createGenerateImportMap(config, ports) {
|
|
|
2686
2858
|
}
|
|
2687
2859
|
registerBundleChunks(chunkBundles, version.remotes[0].name, version.remotes[0].bundle);
|
|
2688
2860
|
version.remotes[0].cached = true;
|
|
2861
|
+
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes, 1);
|
|
2689
2862
|
}
|
|
2690
2863
|
for (const version of external.versions) {
|
|
2691
2864
|
if (version.action !== "skip") continue;
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
warnUncoveredEntrypoint(GLOBAL_SCOPE, externalName, remote.name, packageName);
|
|
2697
|
-
continue;
|
|
2698
|
-
}
|
|
2699
|
-
const scope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
2700
|
-
const url = join(scope, file);
|
|
2701
|
-
addToGlobal(importMap, { [packageName]: url });
|
|
2702
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
2703
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2704
|
-
remote.cached = true;
|
|
2705
|
-
}
|
|
2865
|
+
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes);
|
|
2866
|
+
}
|
|
2867
|
+
if (cachedFingerprint(external) !== cachedBefore) {
|
|
2868
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external);
|
|
2706
2869
|
}
|
|
2707
|
-
ports.sharedExternalsRepo.addOrUpdate(externalName, external);
|
|
2708
2870
|
}
|
|
2709
2871
|
return importMap;
|
|
2710
2872
|
}
|
|
2873
|
+
function selfFillUncovered(importMap, chunkBundles, externalName, remotes, from = 0) {
|
|
2874
|
+
for (let i = from; i < remotes.length; i++) {
|
|
2875
|
+
const remote = remotes[i];
|
|
2876
|
+
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
2877
|
+
if (importMap.imports[packageName]) continue;
|
|
2878
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
2879
|
+
warnUncoveredEntrypoint(GLOBAL_SCOPE, externalName, remote.name, packageName);
|
|
2880
|
+
continue;
|
|
2881
|
+
}
|
|
2882
|
+
const scope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
2883
|
+
const url = join(scope, file);
|
|
2884
|
+
addToGlobal(importMap, { [packageName]: url });
|
|
2885
|
+
addIntegrity(importMap, url, remote.name, file);
|
|
2886
|
+
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2887
|
+
remote.cached = true;
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2711
2891
|
function warnUncoveredEntrypoint(scope, externalName, remoteName, packageName) {
|
|
2712
2892
|
const msg = `[${scope}][${externalName}][${remoteName}] Entrypoint '${packageName}' is not covered by the shared version.`;
|
|
2713
|
-
if (config.strict.strictImportMap) {
|
|
2893
|
+
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
2714
2894
|
config.log.error(4, msg);
|
|
2715
2895
|
throw new NFError("Could not create ImportMap.");
|
|
2716
2896
|
}
|
|
@@ -2899,18 +3079,23 @@ function createGetRemoteEntry(config, ports) {
|
|
|
2899
3079
|
// src/lib/core/2.app/steps/update-cache.ts
|
|
2900
3080
|
function createUpdateCache(config, ports) {
|
|
2901
3081
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 8);
|
|
3082
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
2902
3083
|
return (remoteEntry) => {
|
|
2903
3084
|
try {
|
|
2904
3085
|
const actions = {};
|
|
3086
|
+
if (remoteEntry?.override) removeCachedRemoteEntries(/* @__PURE__ */ new Set([remoteEntry.name]));
|
|
2905
3087
|
storeRemoteEntry(remoteEntry, (entry, external, ctx) => {
|
|
2906
3088
|
const { action, sharedVersion } = resolveSharedExternal(entry, external, ctx);
|
|
2907
3089
|
actions[external.packageName] = { action };
|
|
2908
|
-
if (action === "skip" &&
|
|
2909
|
-
actions[external.packageName].
|
|
2910
|
-
|
|
2911
|
-
external
|
|
2912
|
-
|
|
2913
|
-
|
|
3090
|
+
if (action === "skip" && sharedVersion?.remotes[0]?.entries) {
|
|
3091
|
+
actions[external.packageName].covered = Object.keys(sharedVersion.remotes[0].entries);
|
|
3092
|
+
if (external.shareScope) {
|
|
3093
|
+
actions[external.packageName].override = resolveOverrideEntries(
|
|
3094
|
+
entry,
|
|
3095
|
+
external,
|
|
3096
|
+
sharedVersion
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
2914
3099
|
}
|
|
2915
3100
|
});
|
|
2916
3101
|
return Promise.resolve({ entry: remoteEntry, actions });
|
|
@@ -2938,13 +3123,29 @@ function createUpdateCache(config, ports) {
|
|
|
2938
3123
|
}
|
|
2939
3124
|
config.log.warn(8, errorMsg);
|
|
2940
3125
|
}
|
|
2941
|
-
if (action === "skip" &&
|
|
2942
|
-
|
|
3126
|
+
if (action === "skip" && sharedVersion) {
|
|
3127
|
+
const uncovered = uncoveredEntrypoints(remote, sharedVersion.remotes[0].entries);
|
|
3128
|
+
if (uncovered.length > 0) {
|
|
3129
|
+
const msg = `[${sharedInfo.shareScope ?? GLOBAL_SCOPE}][${remoteEntry.name}][${sharedInfo.packageName}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`;
|
|
3130
|
+
if (config.strict.strictEntryPointCoverage) {
|
|
3131
|
+
config.log.error(8, msg);
|
|
3132
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
3133
|
+
}
|
|
3134
|
+
if (config.profile.scopeUncoveredEntrypoints) {
|
|
3135
|
+
config.log.debug(8, msg);
|
|
3136
|
+
action = "scope";
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
2943
3139
|
}
|
|
2944
|
-
const matchingVersion = cached2.versions
|
|
2945
|
-
if (
|
|
3140
|
+
const matchingVersion = findVersionForTag(cached2.versions, tag);
|
|
3141
|
+
if (action === "scope") {
|
|
3142
|
+
remote.cached = true;
|
|
3143
|
+
const scoped = cached2.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
3144
|
+
if (scoped) scoped.remotes.push(remote);
|
|
3145
|
+
else cached2.versions.push({ tag, action, host: false, remotes: [remote] });
|
|
3146
|
+
} else if (matchingVersion) {
|
|
2946
3147
|
assertSameVersionCompatibility(matchingVersion);
|
|
2947
|
-
matchingVersion
|
|
3148
|
+
addRemoteToVersion(matchingVersion, remote);
|
|
2948
3149
|
} else {
|
|
2949
3150
|
if (!sharedVersion) action = "share";
|
|
2950
3151
|
remote.cached = action !== "skip";
|
|
@@ -3047,22 +3248,24 @@ function createConvertToImportMap(config, ports) {
|
|
|
3047
3248
|
return;
|
|
3048
3249
|
}
|
|
3049
3250
|
if (actions[external.packageName].action === "skip") {
|
|
3050
|
-
const override = actions[external.packageName]
|
|
3051
|
-
if (!external.shareScope)
|
|
3251
|
+
const { override, covered } = actions[external.packageName];
|
|
3252
|
+
if (!external.shareScope) {
|
|
3253
|
+
if (covered) {
|
|
3254
|
+
serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap);
|
|
3255
|
+
}
|
|
3256
|
+
return;
|
|
3257
|
+
}
|
|
3052
3258
|
if (override) {
|
|
3053
3259
|
Object.entries(override).forEach(([packageName, url]) => {
|
|
3054
3260
|
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
3055
3261
|
});
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
3064
|
-
addIntegrity(importMap, url, integrityMap, fileName);
|
|
3065
|
-
});
|
|
3262
|
+
serveUncovered(
|
|
3263
|
+
remoteEntry,
|
|
3264
|
+
external,
|
|
3265
|
+
covered ?? Object.keys(override),
|
|
3266
|
+
remoteEntryScope,
|
|
3267
|
+
importMap
|
|
3268
|
+
);
|
|
3066
3269
|
return;
|
|
3067
3270
|
}
|
|
3068
3271
|
log.error(
|
|
@@ -3129,9 +3332,22 @@ function createConvertToImportMap(config, ports) {
|
|
|
3129
3332
|
});
|
|
3130
3333
|
return importMap;
|
|
3131
3334
|
}
|
|
3335
|
+
function serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap) {
|
|
3336
|
+
const provided = new Set(covered);
|
|
3337
|
+
Object.entries(external.entries).forEach(([packageName, fileName]) => {
|
|
3338
|
+
if (provided.has(packageName)) return;
|
|
3339
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
3340
|
+
warnUncoveredEntrypoint(remoteEntry.name, external.packageName, packageName);
|
|
3341
|
+
return;
|
|
3342
|
+
}
|
|
3343
|
+
const url = join(remoteEntryScope, fileName);
|
|
3344
|
+
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
3345
|
+
addIntegrity(importMap, url, remoteEntry.integrity, fileName);
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3132
3348
|
function warnUncoveredEntrypoint(remoteName, externalName, packageName) {
|
|
3133
3349
|
const msg = `[${remoteName}][${externalName}] Entrypoint '${packageName}' is not covered by the override.`;
|
|
3134
|
-
if (config.strict.strictImportMap) {
|
|
3350
|
+
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
3135
3351
|
log.error(9, msg);
|
|
3136
3352
|
throw new NFError("Could not create ImportMap.");
|
|
3137
3353
|
}
|