@softarc/native-federation-orchestrator 4.5.1 → 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 +405 -159
- 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 +401 -156
- 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 -13
- 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 +2 -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/pooling/pool.types.d.ts +1 -20
- package/types/lib/core/2.app/steps/pooling/pool.util.d.ts +1 -2
- package/types/lib/core/2.app/steps/store-remote-entry.d.ts +15 -7
|
@@ -1426,19 +1426,71 @@ function createGetRemoteEntries(config, ports) {
|
|
|
1426
1426
|
}
|
|
1427
1427
|
}
|
|
1428
1428
|
|
|
1429
|
+
// src/lib/core/1.domain/externals/basis.ts
|
|
1430
|
+
var coverage = (remote) => Object.keys(remote.entries).length;
|
|
1431
|
+
function isBetterBasis(candidate, basis) {
|
|
1432
|
+
if (basis.cached !== candidate.cached) return candidate.cached;
|
|
1433
|
+
return coverage(candidate) > coverage(basis);
|
|
1434
|
+
}
|
|
1435
|
+
function addRemoteToVersion(version, remote, isHost = false) {
|
|
1436
|
+
if (isHost) {
|
|
1437
|
+
version.host = true;
|
|
1438
|
+
version.remotes.unshift(remote);
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
const basis = version.remotes[0];
|
|
1442
|
+
if (basis && !version.host && isBetterBasis(remote, basis)) {
|
|
1443
|
+
version.remotes.unshift(remote);
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
version.remotes.push(remote);
|
|
1447
|
+
}
|
|
1448
|
+
function versionDemands(version) {
|
|
1449
|
+
if (version.remotes.length < 2) return version.remotes;
|
|
1450
|
+
const distinct = /* @__PURE__ */ new Map();
|
|
1451
|
+
for (const remote of version.remotes) {
|
|
1452
|
+
const key = `${remote.requiredVersion}|${remote.strictVersion}|${remote.cached}`;
|
|
1453
|
+
if (!distinct.has(key)) distinct.set(key, remote);
|
|
1454
|
+
}
|
|
1455
|
+
return Array.from(distinct.values());
|
|
1456
|
+
}
|
|
1457
|
+
function findVersionForTag(versions, tag) {
|
|
1458
|
+
let scoped;
|
|
1459
|
+
for (const version of versions) {
|
|
1460
|
+
if (version.tag !== tag) continue;
|
|
1461
|
+
if (version.action !== "scope") return version;
|
|
1462
|
+
scoped ??= version;
|
|
1463
|
+
}
|
|
1464
|
+
return scoped;
|
|
1465
|
+
}
|
|
1466
|
+
function uncoveredEntrypoints(remote, basis) {
|
|
1467
|
+
return Object.keys(remote.entries).filter((entrypoint) => !(entrypoint in basis));
|
|
1468
|
+
}
|
|
1469
|
+
function countUncoveredEntrypoints(remote, basis) {
|
|
1470
|
+
let uncovered = 0;
|
|
1471
|
+
for (const entrypoint in remote.entries) {
|
|
1472
|
+
if (!(entrypoint in basis)) uncovered++;
|
|
1473
|
+
}
|
|
1474
|
+
return uncovered;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1429
1477
|
// src/lib/core/2.app/steps/store-remote-entry.ts
|
|
1478
|
+
function createRemoveCachedRemoteEntries(ports) {
|
|
1479
|
+
return (remoteNames) => {
|
|
1480
|
+
if (remoteNames.size === 0) return;
|
|
1481
|
+
for (const remoteName of remoteNames) {
|
|
1482
|
+
ports.remoteInfoRepo.remove(remoteName);
|
|
1483
|
+
ports.scopedExternalsRepo.remove(remoteName);
|
|
1484
|
+
}
|
|
1485
|
+
ports.sharedExternalsRepo.removeFromAllScopes(remoteNames);
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1430
1488
|
function createStoreRemoteEntry(config, ports, logStep) {
|
|
1431
1489
|
return (remoteEntry, onSharedExternal) => {
|
|
1432
|
-
if (remoteEntry?.override) removeCachedRemoteEntry(remoteEntry);
|
|
1433
1490
|
addRemoteInfoToStorage(remoteEntry);
|
|
1434
1491
|
addExternalsToStorage(remoteEntry, onSharedExternal);
|
|
1435
1492
|
addSharedChunksToStorage(remoteEntry);
|
|
1436
1493
|
};
|
|
1437
|
-
function removeCachedRemoteEntry(remoteEntry) {
|
|
1438
|
-
ports.remoteInfoRepo.remove(remoteEntry.name);
|
|
1439
|
-
ports.scopedExternalsRepo.remove(remoteEntry.name);
|
|
1440
|
-
ports.sharedExternalsRepo.removeFromAllScopes(remoteEntry.name);
|
|
1441
|
-
}
|
|
1442
1494
|
function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
|
|
1443
1495
|
ports.remoteInfoRepo.addOrUpdate(name, {
|
|
1444
1496
|
scopeUrl: getScope(url),
|
|
@@ -1538,14 +1590,35 @@ function createStoreRemoteEntry(config, ports, logStep) {
|
|
|
1538
1590
|
// src/lib/core/2.app/steps/process-remote-entries.ts
|
|
1539
1591
|
function createProcessRemoteEntries(config, ports) {
|
|
1540
1592
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 2);
|
|
1593
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
1541
1594
|
return (remoteEntries) => {
|
|
1542
1595
|
try {
|
|
1543
|
-
|
|
1596
|
+
const evictPerEntry = evictOverriddenRemotes(remoteEntries);
|
|
1597
|
+
remoteEntries.forEach((remoteEntry) => {
|
|
1598
|
+
if (remoteEntry?.override && evictPerEntry.has(remoteEntry.name)) {
|
|
1599
|
+
removeCachedRemoteEntries(/* @__PURE__ */ new Set([remoteEntry.name]));
|
|
1600
|
+
}
|
|
1601
|
+
storeRemoteEntry(remoteEntry, addSharedExternal);
|
|
1602
|
+
});
|
|
1544
1603
|
return Promise.resolve(remoteEntries);
|
|
1545
1604
|
} catch (e) {
|
|
1546
1605
|
return Promise.reject(e);
|
|
1547
1606
|
}
|
|
1548
1607
|
};
|
|
1608
|
+
function evictOverriddenRemotes(remoteEntries) {
|
|
1609
|
+
const batched = /* @__PURE__ */ new Set();
|
|
1610
|
+
const repeated = /* @__PURE__ */ new Set();
|
|
1611
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1612
|
+
for (const remoteEntry of remoteEntries) {
|
|
1613
|
+
if (!remoteEntry) continue;
|
|
1614
|
+
if (seen.has(remoteEntry.name)) repeated.add(remoteEntry.name);
|
|
1615
|
+
seen.add(remoteEntry.name);
|
|
1616
|
+
if (remoteEntry.override) batched.add(remoteEntry.name);
|
|
1617
|
+
}
|
|
1618
|
+
for (const remoteName of repeated) batched.delete(remoteName);
|
|
1619
|
+
removeCachedRemoteEntries(batched);
|
|
1620
|
+
return repeated;
|
|
1621
|
+
}
|
|
1549
1622
|
function addSharedExternal(remoteEntry, _sharedInfo, {
|
|
1550
1623
|
tag,
|
|
1551
1624
|
remote,
|
|
@@ -1554,15 +1627,12 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
1554
1627
|
assertSameVersionCompatibility,
|
|
1555
1628
|
commit
|
|
1556
1629
|
}) {
|
|
1557
|
-
|
|
1630
|
+
if (scopeType !== "strict") cached.dirty = true;
|
|
1631
|
+
const matchingVersion = findVersionForTag(cached.versions, tag);
|
|
1558
1632
|
if (matchingVersion) {
|
|
1559
1633
|
assertSameVersionCompatibility(matchingVersion);
|
|
1560
|
-
|
|
1561
|
-
matchingVersion.host = true;
|
|
1562
|
-
matchingVersion.remotes.unshift(remote);
|
|
1563
|
-
} else matchingVersion.remotes.push(remote);
|
|
1634
|
+
addRemoteToVersion(matchingVersion, remote, !matchingVersion.host && !!remoteEntry?.host);
|
|
1564
1635
|
} else {
|
|
1565
|
-
if (scopeType !== "strict") cached.dirty = true;
|
|
1566
1636
|
cached.versions.push({
|
|
1567
1637
|
tag,
|
|
1568
1638
|
action: scopeType === "strict" ? "share" : "skip",
|
|
@@ -1581,13 +1651,23 @@ var STRICT_SCOPE = "strict";
|
|
|
1581
1651
|
// src/lib/core/2.app/steps/determine-shared-externals.ts
|
|
1582
1652
|
function createDetermineSharedExternals(config, ports) {
|
|
1583
1653
|
return () => {
|
|
1654
|
+
const memo = /* @__PURE__ */ new Map();
|
|
1655
|
+
const isCompatible = (tag, requiredVersion) => {
|
|
1656
|
+
const key = `${tag}|${requiredVersion}`;
|
|
1657
|
+
let hit = memo.get(key);
|
|
1658
|
+
if (hit === void 0) {
|
|
1659
|
+
hit = ports.versionCheck.isCompatible(tag, requiredVersion);
|
|
1660
|
+
memo.set(key, hit);
|
|
1661
|
+
}
|
|
1662
|
+
return hit;
|
|
1663
|
+
};
|
|
1584
1664
|
for (const shareScope of ports.sharedExternalsRepo.getScopes()) {
|
|
1585
1665
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
1586
1666
|
try {
|
|
1587
1667
|
Object.entries(sharedExternals).filter(([_, e]) => e.dirty).forEach(
|
|
1588
1668
|
([name, external]) => ports.sharedExternalsRepo.addOrUpdate(
|
|
1589
1669
|
name,
|
|
1590
|
-
setVersionActions(name, external),
|
|
1670
|
+
setVersionActions(name, external, isCompatible),
|
|
1591
1671
|
shareScope
|
|
1592
1672
|
)
|
|
1593
1673
|
);
|
|
@@ -1610,24 +1690,47 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1610
1690
|
}
|
|
1611
1691
|
return Promise.resolve();
|
|
1612
1692
|
};
|
|
1613
|
-
function
|
|
1693
|
+
function uncoveredTears(external, winner, accepts) {
|
|
1694
|
+
const basis = winner.remotes[0].entries;
|
|
1695
|
+
return external.versions.reduce((sum, v) => {
|
|
1696
|
+
if (v === winner) return sum;
|
|
1697
|
+
if (!accepts(v, winner.tag)) return sum;
|
|
1698
|
+
return sum + v.remotes.reduce((n, r) => n + countUncoveredEntrypoints(r, basis), 0);
|
|
1699
|
+
}, 0);
|
|
1700
|
+
}
|
|
1701
|
+
function setVersionActions(externalName, external, isCompatible) {
|
|
1614
1702
|
if (external.versions.length === 1) {
|
|
1615
1703
|
external.versions[0].action = "share";
|
|
1704
|
+
applyEntrypointCoveragePolicy(externalName, external);
|
|
1616
1705
|
external.dirty = false;
|
|
1617
1706
|
return external;
|
|
1618
1707
|
}
|
|
1708
|
+
const demands = new Map(
|
|
1709
|
+
external.versions.map((v) => [v, versionDemands(v)])
|
|
1710
|
+
);
|
|
1711
|
+
const accepts = (version, tag) => demands.get(version).every((d) => isCompatible(tag, d.requiredVersion));
|
|
1712
|
+
const objector = (version, tag) => demands.get(version).find((d) => d.strictVersion && !isCompatible(tag, d.requiredVersion));
|
|
1619
1713
|
let sharedVersion = external.versions.find((v) => v.host);
|
|
1620
1714
|
if (!sharedVersion && config.profile.latestSharedExternal) {
|
|
1621
1715
|
sharedVersion = external.versions[0];
|
|
1622
1716
|
}
|
|
1623
1717
|
if (!sharedVersion) {
|
|
1624
1718
|
let leastExtraDownloads = Number.MAX_VALUE;
|
|
1719
|
+
let leastTears = Number.MAX_VALUE;
|
|
1625
1720
|
external.versions.forEach((vA) => {
|
|
1626
1721
|
const extraDownloads = external.versions.filter(
|
|
1627
|
-
(vB) =>
|
|
1722
|
+
(vB) => demands.get(vB).some((d) => !d.cached && d.strictVersion && !isCompatible(vA.tag, d.requiredVersion))
|
|
1628
1723
|
).length;
|
|
1629
1724
|
if (extraDownloads < leastExtraDownloads) {
|
|
1630
1725
|
leastExtraDownloads = extraDownloads;
|
|
1726
|
+
leastTears = uncoveredTears(external, vA, accepts);
|
|
1727
|
+
sharedVersion = vA;
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
if (extraDownloads > leastExtraDownloads) return;
|
|
1731
|
+
const tears = uncoveredTears(external, vA, accepts);
|
|
1732
|
+
if (tears < leastTears) {
|
|
1733
|
+
leastTears = tears;
|
|
1631
1734
|
sharedVersion = vA;
|
|
1632
1735
|
}
|
|
1633
1736
|
});
|
|
@@ -1636,23 +1739,81 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1636
1739
|
throw new NFError(`[${externalName}] Could not determine shared version!`);
|
|
1637
1740
|
}
|
|
1638
1741
|
external.versions.forEach((v) => {
|
|
1639
|
-
if (
|
|
1742
|
+
if (accepts(v, sharedVersion.tag)) {
|
|
1640
1743
|
v.action = "skip";
|
|
1641
1744
|
return;
|
|
1642
1745
|
}
|
|
1643
|
-
|
|
1746
|
+
const strict = objector(v, sharedVersion.tag);
|
|
1747
|
+
if (config.strict.strictExternalCompatibility && strict) {
|
|
1644
1748
|
config.log.error(
|
|
1645
1749
|
3,
|
|
1646
|
-
`[${
|
|
1750
|
+
`[${strict.name}][${externalName}@${v.tag}] Is not compatible with requiredRange '${strict.requiredVersion}' of shared ${externalName}@${sharedVersion.tag}.`
|
|
1647
1751
|
);
|
|
1648
1752
|
throw new NFError(`External ${externalName}@${v.tag} could not be shared.`);
|
|
1649
1753
|
}
|
|
1650
|
-
v.action =
|
|
1754
|
+
v.action = strict ? "scope" : "skip";
|
|
1651
1755
|
});
|
|
1652
1756
|
sharedVersion.action = "share";
|
|
1757
|
+
applyEntrypointCoveragePolicy(externalName, external);
|
|
1653
1758
|
external.dirty = false;
|
|
1654
1759
|
return external;
|
|
1655
1760
|
}
|
|
1761
|
+
function applyEntrypointCoveragePolicy(externalName, external) {
|
|
1762
|
+
const { strictEntryPointCoverage } = config.strict;
|
|
1763
|
+
if (!strictEntryPointCoverage && !config.profile.scopeUncoveredEntrypoints) return;
|
|
1764
|
+
const tears = findTears(external);
|
|
1765
|
+
if (tears.length === 0) return;
|
|
1766
|
+
if (strictEntryPointCoverage) {
|
|
1767
|
+
const { version, remote, uncovered } = tears[0];
|
|
1768
|
+
config.log.error(
|
|
1769
|
+
3,
|
|
1770
|
+
`[${externalName}@${version.tag}][${remote.name}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
1771
|
+
);
|
|
1772
|
+
throw new NFError(
|
|
1773
|
+
`External ${externalName} could not be shared without tearing entrypoints.`
|
|
1774
|
+
);
|
|
1775
|
+
}
|
|
1776
|
+
scopeTornRemotes(externalName, external, tears);
|
|
1777
|
+
}
|
|
1778
|
+
function findTears(external) {
|
|
1779
|
+
const shared = external.versions.find((v) => v.action === "share");
|
|
1780
|
+
if (!shared) return [];
|
|
1781
|
+
const basis = shared.remotes[0].entries;
|
|
1782
|
+
const tears = [];
|
|
1783
|
+
for (const version of external.versions) {
|
|
1784
|
+
if (version.action === "scope") continue;
|
|
1785
|
+
version.remotes.forEach((remote, index) => {
|
|
1786
|
+
if (version === shared && index === 0) return;
|
|
1787
|
+
const uncovered = uncoveredEntrypoints(remote, basis);
|
|
1788
|
+
if (uncovered.length > 0) tears.push({ version, remote, uncovered });
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
return tears;
|
|
1792
|
+
}
|
|
1793
|
+
function scopeTornRemotes(externalName, external, tears) {
|
|
1794
|
+
const torn = new Set(tears.map((t) => t.remote));
|
|
1795
|
+
const demotedByTag = /* @__PURE__ */ new Map();
|
|
1796
|
+
for (const { version, remote, uncovered } of tears) {
|
|
1797
|
+
const group = demotedByTag.get(version.tag);
|
|
1798
|
+
if (group) group.push(remote);
|
|
1799
|
+
else demotedByTag.set(version.tag, [remote]);
|
|
1800
|
+
config.log.debug(
|
|
1801
|
+
3,
|
|
1802
|
+
`[${externalName}@${version.tag}][${remote.name}] Scoped: entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
for (const version of external.versions) {
|
|
1806
|
+
if (version.remotes.some((r) => torn.has(r))) {
|
|
1807
|
+
version.remotes = version.remotes.filter((r) => !torn.has(r));
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
external.versions = external.versions.filter((v) => v.remotes.length > 0);
|
|
1811
|
+
for (const [tag, remotes] of demotedByTag) {
|
|
1812
|
+
const scoped = external.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
1813
|
+
if (scoped) scoped.remotes.push(...remotes);
|
|
1814
|
+
else external.versions.push({ tag, host: false, action: "scope", remotes });
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1656
1817
|
}
|
|
1657
1818
|
|
|
1658
1819
|
// src/lib/core/2.app/steps/pooling/pool-graph.ts
|
|
@@ -1757,9 +1918,6 @@ function buildPools(sharedExternals, useAutoExternalPooling, log) {
|
|
|
1757
1918
|
}
|
|
1758
1919
|
|
|
1759
1920
|
// src/lib/core/2.app/steps/pooling/pool.util.ts
|
|
1760
|
-
function versionForRemote(member, remote) {
|
|
1761
|
-
return member.external.versions.find((v) => v.remotes.some((r) => r.name === remote));
|
|
1762
|
-
}
|
|
1763
1921
|
function remotesInPool(members) {
|
|
1764
1922
|
return [
|
|
1765
1923
|
...new Set(members.flatMap((m) => m.external.versions.flatMap((v) => v.remotes.map((r) => r.name))))
|
|
@@ -1767,57 +1925,12 @@ function remotesInPool(members) {
|
|
|
1767
1925
|
}
|
|
1768
1926
|
|
|
1769
1927
|
// src/lib/core/2.app/steps/pooling/pool-shared-externals.ts
|
|
1770
|
-
function
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
providers: new Set((share?.remotes ?? []).map((r) => r.name))
|
|
1777
|
-
};
|
|
1778
|
-
});
|
|
1779
|
-
}
|
|
1780
|
-
function selectCoverageAnchor(winners) {
|
|
1781
|
-
const coverage = /* @__PURE__ */ new Map();
|
|
1782
|
-
for (const winner of winners)
|
|
1783
|
-
for (const remote of winner.providers) coverage.set(remote, (coverage.get(remote) ?? 0) + 1);
|
|
1784
|
-
if (coverage.size === 0) return void 0;
|
|
1785
|
-
const anchorRemote = [...coverage.keys()].sort(
|
|
1786
|
-
(a, b) => coverage.get(b) - coverage.get(a) || a.localeCompare(b)
|
|
1787
|
-
)[0];
|
|
1788
|
-
return {
|
|
1789
|
-
anchorRemote,
|
|
1790
|
-
tagPerMember: Object.fromEntries(
|
|
1791
|
-
winners.filter((w) => w.providers.has(anchorRemote)).map((w) => [w.member.name, w.tag])
|
|
1792
|
-
)
|
|
1793
|
-
};
|
|
1794
|
-
}
|
|
1795
|
-
function classifyPoolConservative(members, anchor) {
|
|
1796
|
-
const classification = /* @__PURE__ */ new Map();
|
|
1797
|
-
for (const remote of remotesInPool(members)) {
|
|
1798
|
-
let coverageForced = false;
|
|
1799
|
-
let verdict = "follow";
|
|
1800
|
-
for (const member of members) {
|
|
1801
|
-
const version = versionForRemote(member, remote);
|
|
1802
|
-
if (!version) continue;
|
|
1803
|
-
const anchorTag = anchor.tagPerMember[member.name];
|
|
1804
|
-
if (!anchorTag) {
|
|
1805
|
-
coverageForced = true;
|
|
1806
|
-
continue;
|
|
1807
|
-
}
|
|
1808
|
-
if (version.tag === anchorTag) continue;
|
|
1809
|
-
if (version.action === "scope") {
|
|
1810
|
-
verdict = "scope-incompat";
|
|
1811
|
-
break;
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
classification.set(
|
|
1815
|
-
remote,
|
|
1816
|
-
verdict === "scope-incompat" ? "scope-incompat" : coverageForced ? "scope-coverage" : "follow"
|
|
1817
|
-
);
|
|
1818
|
-
}
|
|
1819
|
-
classification.set(anchor.anchorRemote, "follow");
|
|
1820
|
-
return classification;
|
|
1928
|
+
function islandedRemotes(members) {
|
|
1929
|
+
const islanded = /* @__PURE__ */ new Set();
|
|
1930
|
+
for (const member of members)
|
|
1931
|
+
for (const version of member.external.versions)
|
|
1932
|
+
if (version.action === "scope") for (const remote of version.remotes) islanded.add(remote.name);
|
|
1933
|
+
return islanded;
|
|
1821
1934
|
}
|
|
1822
1935
|
function createPoolSharedExternals(config, ports) {
|
|
1823
1936
|
return () => {
|
|
@@ -1853,73 +1966,57 @@ function createPoolSharedExternals(config, ports) {
|
|
|
1853
1966
|
if (members.length < 2) return;
|
|
1854
1967
|
const allRemotes = remotesInPool(members);
|
|
1855
1968
|
if (allRemotes.length < 2) return;
|
|
1856
|
-
const
|
|
1857
|
-
if (!anchor) return;
|
|
1858
|
-
const classification = classifyPoolConservative(members, anchor);
|
|
1969
|
+
const islanded = islandedRemotes(members);
|
|
1859
1970
|
config.log.debug(
|
|
1860
1971
|
3,
|
|
1861
|
-
`[${scope}][pool:${poolName}]
|
|
1972
|
+
`[${scope}][pool:${poolName}] ${members.length} members across ${allRemotes.length} remotes, islanded={${[...islanded].join(", ") || "\u2205"}}
|
|
1973
|
+
` + members.map((m) => ` - ${m.name}`).join("\n")
|
|
1862
1974
|
);
|
|
1863
|
-
|
|
1864
|
-
if (incompatForced && config.strict.strictExternalCompatibility) {
|
|
1975
|
+
if (islanded.size > 0 && config.strict.strictExternalCompatibility) {
|
|
1865
1976
|
config.log.error(
|
|
1866
1977
|
3,
|
|
1867
|
-
`[${scope}][pool:${poolName}]
|
|
1978
|
+
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${[...islanded].join(", ")}}.`
|
|
1868
1979
|
);
|
|
1869
1980
|
throw new NFError(`Could not pool '${poolName}' in scope ${scope}.`);
|
|
1870
1981
|
}
|
|
1871
1982
|
for (const member of members) {
|
|
1872
|
-
const rebuilt = rebuildMember(member,
|
|
1983
|
+
const rebuilt = rebuildMember(member, islanded);
|
|
1873
1984
|
warnIfScopedOnly(poolName, member.name, rebuilt, scope);
|
|
1874
1985
|
ports.sharedExternalsRepo.addOrUpdate(member.name, rebuilt, scope);
|
|
1875
1986
|
}
|
|
1876
1987
|
}
|
|
1877
1988
|
function warnIfScopedOnly(poolName, memberName, rebuilt, scope) {
|
|
1878
1989
|
if (rebuilt.versions.some((v) => v.action === "share")) return;
|
|
1879
|
-
const
|
|
1990
|
+
const consumers = new Set(rebuilt.versions.flatMap((v) => v.remotes.map((r) => r.name))).size;
|
|
1991
|
+
if (consumers < 2) return;
|
|
1880
1992
|
config.log.warn(
|
|
1881
1993
|
3,
|
|
1882
|
-
`[${scope}][pool:${poolName}] '${memberName}' is scoped-only \u2014 no coherent shared build provides it; ${
|
|
1994
|
+
`[${scope}][pool:${poolName}] '${memberName}' is scoped-only \u2014 no coherent shared build provides it; ${consumers} remotes download their own copy.`
|
|
1883
1995
|
);
|
|
1884
1996
|
}
|
|
1885
|
-
function rebuildMember(member,
|
|
1886
|
-
const anchorTag = anchor.tagPerMember[member.name];
|
|
1997
|
+
function rebuildMember(member, islanded) {
|
|
1887
1998
|
const entries = member.external.versions.flatMap(
|
|
1888
|
-
(v) => v.remotes.map((meta) => ({ remote: meta.name, tag: v.tag, host: v.host, meta }))
|
|
1999
|
+
(v) => v.remotes.map((meta) => ({ remote: meta.name, tag: v.tag, host: v.host, action: v.action, meta }))
|
|
1889
2000
|
);
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
const anchorHost = member.external.versions.find((v) => v.tag === anchorTag)?.host ?? false;
|
|
1907
|
-
const scopes = (e) => {
|
|
1908
|
-
const cls = classification.get(e.remote);
|
|
1909
|
-
return cls === "scope-incompat" || cls === "scope-coverage" && e.tag !== anchorTag;
|
|
1910
|
-
};
|
|
1911
|
-
const shareOnAnchor = entries.filter(
|
|
1912
|
-
(e) => e.remote !== anchor.anchorRemote && e.tag === anchorTag && !scopes(e)
|
|
1913
|
-
);
|
|
1914
|
-
const shareVersion = {
|
|
1915
|
-
tag: anchorTag,
|
|
1916
|
-
host: anchorHost,
|
|
1917
|
-
action: "share",
|
|
1918
|
-
remotes: [anchorMeta, ...shareOnAnchor.map((e) => e.meta)]
|
|
1919
|
-
};
|
|
2001
|
+
const isScoped = (e) => islanded.has(e.remote) || e.action === "scope";
|
|
2002
|
+
let scoped = entries.filter(isScoped);
|
|
2003
|
+
let clean = entries.filter((e) => !isScoped(e));
|
|
2004
|
+
if (!clean.some((e) => e.action === "share")) {
|
|
2005
|
+
scoped = [...scoped, ...clean];
|
|
2006
|
+
clean = [];
|
|
2007
|
+
}
|
|
2008
|
+
const shareEntries = clean.filter((e) => e.action === "share");
|
|
2009
|
+
const shareVersion = shareEntries.length > 0 ? [
|
|
2010
|
+
{
|
|
2011
|
+
tag: shareEntries[0].tag,
|
|
2012
|
+
host: shareEntries[0].host,
|
|
2013
|
+
action: "share",
|
|
2014
|
+
remotes: shareEntries.map((e) => e.meta)
|
|
2015
|
+
}
|
|
2016
|
+
] : [];
|
|
1920
2017
|
const skipByTag = /* @__PURE__ */ new Map();
|
|
1921
|
-
for (const e of
|
|
1922
|
-
if (e.
|
|
2018
|
+
for (const e of clean) {
|
|
2019
|
+
if (e.action !== "skip") continue;
|
|
1923
2020
|
const version = skipByTag.get(e.tag) ?? {
|
|
1924
2021
|
tag: e.tag,
|
|
1925
2022
|
host: e.host,
|
|
@@ -1929,16 +2026,25 @@ function createPoolSharedExternals(config, ports) {
|
|
|
1929
2026
|
version.remotes.push(e.meta);
|
|
1930
2027
|
skipByTag.set(e.tag, version);
|
|
1931
2028
|
}
|
|
1932
|
-
const
|
|
1933
|
-
const
|
|
2029
|
+
const scopeByTag = /* @__PURE__ */ new Map();
|
|
2030
|
+
for (const e of scoped) {
|
|
2031
|
+
const version = scopeByTag.get(e.tag) ?? {
|
|
2032
|
+
tag: e.tag,
|
|
2033
|
+
host: false,
|
|
2034
|
+
action: "scope",
|
|
2035
|
+
remotes: []
|
|
2036
|
+
};
|
|
2037
|
+
version.remotes.push(e.meta);
|
|
2038
|
+
scopeByTag.set(e.tag, version);
|
|
2039
|
+
}
|
|
1934
2040
|
return {
|
|
1935
2041
|
dirty: false,
|
|
1936
|
-
versions: [shareVersion, ...skipByTag.values(), ...
|
|
2042
|
+
versions: [...shareVersion, ...skipByTag.values(), ...scopeByTag.values()]
|
|
1937
2043
|
};
|
|
1938
2044
|
}
|
|
1939
2045
|
}
|
|
1940
2046
|
|
|
1941
|
-
// node_modules/.pnpm/@softarc+native-federation@4.3.
|
|
2047
|
+
// node_modules/.pnpm/@softarc+native-federation@4.3.2_typescript@6.0.3/node_modules/@softarc/native-federation/dist/lib/domain/core/build-notification-options.contract.js
|
|
1942
2048
|
var BuildNotificationType = /* @__PURE__ */ ((BuildNotificationType2) => {
|
|
1943
2049
|
BuildNotificationType2["COMPLETED"] = "federation-rebuild-complete";
|
|
1944
2050
|
BuildNotificationType2["ERROR"] = "federation-rebuild-error";
|
|
@@ -1946,7 +2052,7 @@ var BuildNotificationType = /* @__PURE__ */ ((BuildNotificationType2) => {
|
|
|
1946
2052
|
return BuildNotificationType2;
|
|
1947
2053
|
})(BuildNotificationType || {});
|
|
1948
2054
|
|
|
1949
|
-
// node_modules/.pnpm/@softarc+native-federation@4.3.
|
|
2055
|
+
// node_modules/.pnpm/@softarc+native-federation@4.3.2_typescript@6.0.3/node_modules/@softarc/native-federation/dist/lib/domain/core/chunk.js
|
|
1950
2056
|
var CHUNK_PREFIX = "@nf-internal";
|
|
1951
2057
|
function toChunkImport(fileName) {
|
|
1952
2058
|
if (fileName.startsWith("./")) {
|
|
@@ -2010,6 +2116,7 @@ function createGenerateImportMap(config, ports) {
|
|
|
2010
2116
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2011
2117
|
let override = void 0;
|
|
2012
2118
|
let overrideScope = void 0;
|
|
2119
|
+
const cachedBefore = cachedFingerprint(external);
|
|
2013
2120
|
for (const version of external.versions) {
|
|
2014
2121
|
if (version.action === "scope") {
|
|
2015
2122
|
for (const remote of version.remotes) {
|
|
@@ -2053,14 +2160,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
2053
2160
|
for (const m of mappings) {
|
|
2054
2161
|
addToScope(importMap, rScope, { [m.packageName]: m.url });
|
|
2055
2162
|
}
|
|
2163
|
+
for (const [packageName, file] of Object.entries(r.entries)) {
|
|
2164
|
+
if (packageName in source.entries) continue;
|
|
2165
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
2166
|
+
warnUncoveredEntrypoint(shareScope, externalName, r.name, packageName);
|
|
2167
|
+
continue;
|
|
2168
|
+
}
|
|
2169
|
+
const url = join(rScope, file);
|
|
2170
|
+
addToScope(importMap, rScope, { [packageName]: url });
|
|
2171
|
+
addIntegrity(importMap, url, r.name, file);
|
|
2172
|
+
r.cached = true;
|
|
2173
|
+
}
|
|
2056
2174
|
});
|
|
2057
2175
|
for (const m of mappings) {
|
|
2058
2176
|
addIntegrity(importMap, m.url, m.name, m.file);
|
|
2059
2177
|
}
|
|
2060
2178
|
}
|
|
2061
|
-
|
|
2179
|
+
if (cachedFingerprint(external) !== cachedBefore) {
|
|
2180
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external, shareScope);
|
|
2181
|
+
}
|
|
2062
2182
|
}
|
|
2063
2183
|
}
|
|
2184
|
+
function cachedFingerprint(external) {
|
|
2185
|
+
return external.versions.map((v) => v.remotes.map((r) => r.cached ? 1 : 0).join("")).join("|");
|
|
2186
|
+
}
|
|
2064
2187
|
function findOverride(external, shareScope, externalName) {
|
|
2065
2188
|
const sharedVersions = external.versions.filter((v) => v.action === "share");
|
|
2066
2189
|
const scopedExternalName = `${shareScope}.${externalName}`;
|
|
@@ -2092,6 +2215,7 @@ function createGenerateImportMap(config, ports) {
|
|
|
2092
2215
|
function addGlobalSharedExternals(importMap, chunkBundles) {
|
|
2093
2216
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope();
|
|
2094
2217
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2218
|
+
const cachedBefore = cachedFingerprint(external);
|
|
2095
2219
|
for (const version of external.versions) {
|
|
2096
2220
|
if (version.action === "skip") continue;
|
|
2097
2221
|
if (version.action === "scope") {
|
|
@@ -2119,11 +2243,44 @@ function createGenerateImportMap(config, ports) {
|
|
|
2119
2243
|
}
|
|
2120
2244
|
registerBundleChunks(chunkBundles, version.remotes[0].name, version.remotes[0].bundle);
|
|
2121
2245
|
version.remotes[0].cached = true;
|
|
2246
|
+
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes, 1);
|
|
2247
|
+
}
|
|
2248
|
+
for (const version of external.versions) {
|
|
2249
|
+
if (version.action !== "skip") continue;
|
|
2250
|
+
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes);
|
|
2251
|
+
}
|
|
2252
|
+
if (cachedFingerprint(external) !== cachedBefore) {
|
|
2253
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external);
|
|
2122
2254
|
}
|
|
2123
|
-
ports.sharedExternalsRepo.addOrUpdate(externalName, external);
|
|
2124
2255
|
}
|
|
2125
2256
|
return importMap;
|
|
2126
2257
|
}
|
|
2258
|
+
function selfFillUncovered(importMap, chunkBundles, externalName, remotes, from = 0) {
|
|
2259
|
+
for (let i = from; i < remotes.length; i++) {
|
|
2260
|
+
const remote = remotes[i];
|
|
2261
|
+
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
2262
|
+
if (importMap.imports[packageName]) continue;
|
|
2263
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
2264
|
+
warnUncoveredEntrypoint(GLOBAL_SCOPE, externalName, remote.name, packageName);
|
|
2265
|
+
continue;
|
|
2266
|
+
}
|
|
2267
|
+
const scope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
2268
|
+
const url = join(scope, file);
|
|
2269
|
+
addToGlobal(importMap, { [packageName]: url });
|
|
2270
|
+
addIntegrity(importMap, url, remote.name, file);
|
|
2271
|
+
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2272
|
+
remote.cached = true;
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
function warnUncoveredEntrypoint(scope, externalName, remoteName, packageName) {
|
|
2277
|
+
const msg = `[${scope}][${externalName}][${remoteName}] Entrypoint '${packageName}' is not covered by the shared version.`;
|
|
2278
|
+
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
2279
|
+
config.log.error(4, msg);
|
|
2280
|
+
throw new NFError("Could not create ImportMap.");
|
|
2281
|
+
}
|
|
2282
|
+
config.log.warn(4, msg);
|
|
2283
|
+
}
|
|
2127
2284
|
function notifyDuplicateGlobalExternal(externalName) {
|
|
2128
2285
|
if (config.strict.strictImportMap) {
|
|
2129
2286
|
config.log.error(4, `[${externalName}] Shared external has multiple shared versions.`);
|
|
@@ -2346,18 +2503,23 @@ function createGetRemoteEntry(config, ports) {
|
|
|
2346
2503
|
// src/lib/core/2.app/steps/update-cache.ts
|
|
2347
2504
|
function createUpdateCache(config, ports) {
|
|
2348
2505
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 8);
|
|
2506
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
2349
2507
|
return (remoteEntry) => {
|
|
2350
2508
|
try {
|
|
2351
2509
|
const actions = {};
|
|
2510
|
+
if (remoteEntry?.override) removeCachedRemoteEntries(/* @__PURE__ */ new Set([remoteEntry.name]));
|
|
2352
2511
|
storeRemoteEntry(remoteEntry, (entry, external, ctx) => {
|
|
2353
2512
|
const { action, sharedVersion } = resolveSharedExternal(entry, external, ctx);
|
|
2354
2513
|
actions[external.packageName] = { action };
|
|
2355
|
-
if (action === "skip" &&
|
|
2356
|
-
actions[external.packageName].
|
|
2357
|
-
|
|
2358
|
-
external
|
|
2359
|
-
|
|
2360
|
-
|
|
2514
|
+
if (action === "skip" && sharedVersion?.remotes[0]?.entries) {
|
|
2515
|
+
actions[external.packageName].covered = Object.keys(sharedVersion.remotes[0].entries);
|
|
2516
|
+
if (external.shareScope) {
|
|
2517
|
+
actions[external.packageName].override = resolveOverrideEntries(
|
|
2518
|
+
entry,
|
|
2519
|
+
external,
|
|
2520
|
+
sharedVersion
|
|
2521
|
+
);
|
|
2522
|
+
}
|
|
2361
2523
|
}
|
|
2362
2524
|
});
|
|
2363
2525
|
return Promise.resolve({ entry: remoteEntry, actions });
|
|
@@ -2385,10 +2547,29 @@ function createUpdateCache(config, ports) {
|
|
|
2385
2547
|
}
|
|
2386
2548
|
config.log.warn(8, errorMsg);
|
|
2387
2549
|
}
|
|
2388
|
-
|
|
2389
|
-
|
|
2550
|
+
if (action === "skip" && sharedVersion) {
|
|
2551
|
+
const uncovered = uncoveredEntrypoints(remote, sharedVersion.remotes[0].entries);
|
|
2552
|
+
if (uncovered.length > 0) {
|
|
2553
|
+
const msg = `[${sharedInfo.shareScope ?? GLOBAL_SCOPE}][${remoteEntry.name}][${sharedInfo.packageName}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`;
|
|
2554
|
+
if (config.strict.strictEntryPointCoverage) {
|
|
2555
|
+
config.log.error(8, msg);
|
|
2556
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
2557
|
+
}
|
|
2558
|
+
if (config.profile.scopeUncoveredEntrypoints) {
|
|
2559
|
+
config.log.debug(8, msg);
|
|
2560
|
+
action = "scope";
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
const matchingVersion = findVersionForTag(cached.versions, tag);
|
|
2565
|
+
if (action === "scope") {
|
|
2566
|
+
remote.cached = true;
|
|
2567
|
+
const scoped = cached.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
2568
|
+
if (scoped) scoped.remotes.push(remote);
|
|
2569
|
+
else cached.versions.push({ tag, action, host: false, remotes: [remote] });
|
|
2570
|
+
} else if (matchingVersion) {
|
|
2390
2571
|
assertSameVersionCompatibility(matchingVersion);
|
|
2391
|
-
matchingVersion
|
|
2572
|
+
addRemoteToVersion(matchingVersion, remote);
|
|
2392
2573
|
} else {
|
|
2393
2574
|
if (!sharedVersion) action = "share";
|
|
2394
2575
|
remote.cached = action !== "skip";
|
|
@@ -2449,8 +2630,6 @@ function createPoolDynamicExternals(config) {
|
|
|
2449
2630
|
const memberActions = members.map((name) => actions[name].action);
|
|
2450
2631
|
if (memberActions.includes("scope")) {
|
|
2451
2632
|
members.forEach(scope);
|
|
2452
|
-
} else if (memberActions.includes("share") && memberActions.includes("skip")) {
|
|
2453
|
-
members.filter((name) => actions[name].action === "share").forEach(scope);
|
|
2454
2633
|
}
|
|
2455
2634
|
}
|
|
2456
2635
|
}
|
|
@@ -2493,12 +2672,24 @@ function createConvertToImportMap(config, ports) {
|
|
|
2493
2672
|
return;
|
|
2494
2673
|
}
|
|
2495
2674
|
if (actions[external.packageName].action === "skip") {
|
|
2496
|
-
const override = actions[external.packageName]
|
|
2497
|
-
if (!external.shareScope)
|
|
2675
|
+
const { override, covered } = actions[external.packageName];
|
|
2676
|
+
if (!external.shareScope) {
|
|
2677
|
+
if (covered) {
|
|
2678
|
+
serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap);
|
|
2679
|
+
}
|
|
2680
|
+
return;
|
|
2681
|
+
}
|
|
2498
2682
|
if (override) {
|
|
2499
2683
|
Object.entries(override).forEach(([packageName, url]) => {
|
|
2500
2684
|
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
2501
2685
|
});
|
|
2686
|
+
serveUncovered(
|
|
2687
|
+
remoteEntry,
|
|
2688
|
+
external,
|
|
2689
|
+
covered ?? Object.keys(override),
|
|
2690
|
+
remoteEntryScope,
|
|
2691
|
+
importMap
|
|
2692
|
+
);
|
|
2502
2693
|
return;
|
|
2503
2694
|
}
|
|
2504
2695
|
log.error(
|
|
@@ -2565,6 +2756,27 @@ function createConvertToImportMap(config, ports) {
|
|
|
2565
2756
|
});
|
|
2566
2757
|
return importMap;
|
|
2567
2758
|
}
|
|
2759
|
+
function serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap) {
|
|
2760
|
+
const provided = new Set(covered);
|
|
2761
|
+
Object.entries(external.entries).forEach(([packageName, fileName]) => {
|
|
2762
|
+
if (provided.has(packageName)) return;
|
|
2763
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
2764
|
+
warnUncoveredEntrypoint(remoteEntry.name, external.packageName, packageName);
|
|
2765
|
+
return;
|
|
2766
|
+
}
|
|
2767
|
+
const url = join(remoteEntryScope, fileName);
|
|
2768
|
+
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
2769
|
+
addIntegrity(importMap, url, remoteEntry.integrity, fileName);
|
|
2770
|
+
});
|
|
2771
|
+
}
|
|
2772
|
+
function warnUncoveredEntrypoint(remoteName, externalName, packageName) {
|
|
2773
|
+
const msg = `[${remoteName}][${externalName}] Entrypoint '${packageName}' is not covered by the override.`;
|
|
2774
|
+
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
2775
|
+
log.error(9, msg);
|
|
2776
|
+
throw new NFError("Could not create ImportMap.");
|
|
2777
|
+
}
|
|
2778
|
+
log.warn(9, msg);
|
|
2779
|
+
}
|
|
2568
2780
|
function addIntegrity(importMap, url, integrityMap, file) {
|
|
2569
2781
|
const hash = integrityMap?.[file];
|
|
2570
2782
|
if (!hash) return;
|
|
@@ -2698,7 +2910,7 @@ var createManifestProvider = () => {
|
|
|
2698
2910
|
};
|
|
2699
2911
|
};
|
|
2700
2912
|
|
|
2701
|
-
// node_modules/.pnpm/@softarc+native-federation@4.3.
|
|
2913
|
+
// node_modules/.pnpm/@softarc+native-federation@4.3.2_typescript@6.0.3/node_modules/@softarc/native-federation/dist/lib/utils/normalize.js
|
|
2702
2914
|
function inferPackageFromSecondary(secondary) {
|
|
2703
2915
|
const parts = secondary.split("/");
|
|
2704
2916
|
if (secondary.startsWith("@") && parts.length >= 2) {
|
|
@@ -2707,7 +2919,7 @@ function inferPackageFromSecondary(secondary) {
|
|
|
2707
2919
|
return parts[0];
|
|
2708
2920
|
}
|
|
2709
2921
|
|
|
2710
|
-
// node_modules/.pnpm/@softarc+native-federation@4.3.
|
|
2922
|
+
// node_modules/.pnpm/@softarc+native-federation@4.3.2_typescript@6.0.3/node_modules/@softarc/native-federation/dist/lib/core/output/densify-externals.js
|
|
2711
2923
|
function isDense(entry) {
|
|
2712
2924
|
return "entries" in entry;
|
|
2713
2925
|
}
|
|
@@ -2748,6 +2960,7 @@ function densifyExternals(shared) {
|
|
|
2748
2960
|
if (entry.version !== void 0) dense.version = entry.version;
|
|
2749
2961
|
if (entry.shareScope !== void 0) dense.shareScope = entry.shareScope;
|
|
2750
2962
|
if (entry.bundle !== void 0) dense.bundle = entry.bundle;
|
|
2963
|
+
if (entry.pool !== void 0) dense.pool = entry.pool;
|
|
2751
2964
|
if (entry.dev !== void 0) dense.dev = entry.dev;
|
|
2752
2965
|
groupIndex.set(key, result.length);
|
|
2753
2966
|
result.push(dense);
|
|
@@ -2807,16 +3020,21 @@ var createRemoteInfoRepository = (config) => {
|
|
|
2807
3020
|
const STORAGE = config.storage("remotes", {});
|
|
2808
3021
|
if (config.clearStorage) STORAGE.clear();
|
|
2809
3022
|
const _cache = STORAGE.get() ?? {};
|
|
3023
|
+
let _dirty = false;
|
|
2810
3024
|
return {
|
|
2811
3025
|
contains: function(remoteName) {
|
|
2812
3026
|
return !!_cache[remoteName];
|
|
2813
3027
|
},
|
|
2814
3028
|
remove: function(remoteName) {
|
|
2815
|
-
|
|
3029
|
+
if (remoteName in _cache) {
|
|
3030
|
+
delete _cache[remoteName];
|
|
3031
|
+
_dirty = true;
|
|
3032
|
+
}
|
|
2816
3033
|
return this;
|
|
2817
3034
|
},
|
|
2818
3035
|
addOrUpdate: function(remoteName, remote) {
|
|
2819
3036
|
_cache[remoteName] = remote;
|
|
3037
|
+
_dirty = true;
|
|
2820
3038
|
return this;
|
|
2821
3039
|
},
|
|
2822
3040
|
tryGet: function(remoteName) {
|
|
@@ -2831,7 +3049,9 @@ var createRemoteInfoRepository = (config) => {
|
|
|
2831
3049
|
return _cache;
|
|
2832
3050
|
},
|
|
2833
3051
|
commit: function() {
|
|
3052
|
+
if (!_dirty) return this;
|
|
2834
3053
|
STORAGE.set(_cache);
|
|
3054
|
+
_dirty = false;
|
|
2835
3055
|
return this;
|
|
2836
3056
|
}
|
|
2837
3057
|
};
|
|
@@ -2842,14 +3062,19 @@ var createScopedExternalsRepository = (config) => {
|
|
|
2842
3062
|
const STORAGE = config.storage("scoped-externals", {});
|
|
2843
3063
|
if (config.clearStorage) STORAGE.clear();
|
|
2844
3064
|
const _cache = STORAGE.get() ?? {};
|
|
3065
|
+
let _dirty = false;
|
|
2845
3066
|
return {
|
|
2846
3067
|
addExternal: function(remoteName, external, version) {
|
|
2847
3068
|
if (!_cache[remoteName]) _cache[remoteName] = {};
|
|
2848
3069
|
_cache[remoteName][external] = version;
|
|
3070
|
+
_dirty = true;
|
|
2849
3071
|
return this;
|
|
2850
3072
|
},
|
|
2851
3073
|
remove: function(remoteName) {
|
|
2852
|
-
|
|
3074
|
+
if (remoteName in _cache) {
|
|
3075
|
+
delete _cache[remoteName];
|
|
3076
|
+
_dirty = true;
|
|
3077
|
+
}
|
|
2853
3078
|
return this;
|
|
2854
3079
|
},
|
|
2855
3080
|
getAll: function() {
|
|
@@ -2859,7 +3084,9 @@ var createScopedExternalsRepository = (config) => {
|
|
|
2859
3084
|
return Optional.of(_cache[remoteName]);
|
|
2860
3085
|
},
|
|
2861
3086
|
commit: function() {
|
|
3087
|
+
if (!_dirty) return this;
|
|
2862
3088
|
STORAGE.set(_cache);
|
|
3089
|
+
_dirty = false;
|
|
2863
3090
|
return this;
|
|
2864
3091
|
}
|
|
2865
3092
|
};
|
|
@@ -2872,8 +3099,9 @@ var createSharedExternalsRepository = (config) => {
|
|
|
2872
3099
|
{ [GLOBAL_SCOPE]: {} }
|
|
2873
3100
|
);
|
|
2874
3101
|
if (config.clearStorage) STORAGE.clear();
|
|
2875
|
-
const _cache = STORAGE.get();
|
|
3102
|
+
const _cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
2876
3103
|
let _sawPoolTag = false;
|
|
3104
|
+
let _dirty = false;
|
|
2877
3105
|
return {
|
|
2878
3106
|
markPoolTagPresent: function() {
|
|
2879
3107
|
_sawPoolTag = true;
|
|
@@ -2887,28 +3115,38 @@ var createSharedExternalsRepository = (config) => {
|
|
|
2887
3115
|
addOrUpdate: function(externalName, external, shareScope) {
|
|
2888
3116
|
if (!_cache[shareScope ?? GLOBAL_SCOPE]) _cache[shareScope ?? GLOBAL_SCOPE] = {};
|
|
2889
3117
|
_cache[shareScope ?? GLOBAL_SCOPE][externalName] = external;
|
|
3118
|
+
_dirty = true;
|
|
2890
3119
|
return this;
|
|
2891
3120
|
},
|
|
2892
3121
|
getScopes: function(o = { includeGlobal: true }) {
|
|
2893
3122
|
if (o.includeGlobal) return Object.keys(_cache);
|
|
2894
3123
|
return Object.keys(_cache).filter((s) => s !== GLOBAL_SCOPE);
|
|
2895
3124
|
},
|
|
2896
|
-
|
|
3125
|
+
// Batched: one traversal of the graph per init instead of one per overridden remote.
|
|
3126
|
+
removeFromAllScopes: function(remoteNames) {
|
|
3127
|
+
if (remoteNames.size === 0) return;
|
|
2897
3128
|
Object.values(_cache).forEach((scope) => {
|
|
2898
3129
|
const removeExternals = [];
|
|
2899
3130
|
Object.entries(scope).forEach(([name, external]) => {
|
|
2900
|
-
|
|
2901
|
-
external.versions.
|
|
2902
|
-
const
|
|
2903
|
-
|
|
2904
|
-
|
|
3131
|
+
let removedVersion = false;
|
|
3132
|
+
for (let i = external.versions.length - 1; i >= 0; i--) {
|
|
3133
|
+
const remotes = external.versions[i].remotes;
|
|
3134
|
+
let keep = 0;
|
|
3135
|
+
for (let r = 0; r < remotes.length; r++) {
|
|
3136
|
+
if (remoteNames.has(remotes[r].name)) continue;
|
|
3137
|
+
remotes[keep++] = remotes[r];
|
|
2905
3138
|
}
|
|
2906
|
-
if (
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
3139
|
+
if (keep !== remotes.length) {
|
|
3140
|
+
remotes.length = keep;
|
|
3141
|
+
_dirty = true;
|
|
3142
|
+
}
|
|
3143
|
+
if (remotes.length === 0) {
|
|
3144
|
+
external.versions.splice(i, 1);
|
|
3145
|
+
removedVersion = true;
|
|
3146
|
+
_dirty = true;
|
|
2911
3147
|
}
|
|
3148
|
+
}
|
|
3149
|
+
if (removedVersion) {
|
|
2912
3150
|
external.dirty = true;
|
|
2913
3151
|
if (external.versions.length === 0) removeExternals.push(name);
|
|
2914
3152
|
}
|
|
@@ -2932,7 +3170,9 @@ var createSharedExternalsRepository = (config) => {
|
|
|
2932
3170
|
return Optional.of(_cache[shareScope ?? GLOBAL_SCOPE]?.[external]);
|
|
2933
3171
|
},
|
|
2934
3172
|
commit: function() {
|
|
3173
|
+
if (!_dirty) return this;
|
|
2935
3174
|
STORAGE.set(_cache);
|
|
3175
|
+
_dirty = false;
|
|
2936
3176
|
return this;
|
|
2937
3177
|
}
|
|
2938
3178
|
};
|
|
@@ -2969,17 +3209,21 @@ var createChunkRepository = (config) => {
|
|
|
2969
3209
|
const STORAGE = config.storage("shared-chunks", {});
|
|
2970
3210
|
if (config.clearStorage) STORAGE.clear();
|
|
2971
3211
|
const _cache = STORAGE.get() ?? {};
|
|
3212
|
+
let _dirty = false;
|
|
2972
3213
|
return {
|
|
2973
3214
|
addOrReplace: function(remoteName, bundleName, chunks) {
|
|
2974
3215
|
if (!_cache[remoteName]) _cache[remoteName] = {};
|
|
2975
3216
|
_cache[remoteName][bundleName] = chunks;
|
|
3217
|
+
_dirty = true;
|
|
2976
3218
|
return this;
|
|
2977
3219
|
},
|
|
2978
3220
|
tryGet: function(remoteName, bundleName) {
|
|
2979
3221
|
return Optional.of(_cache[remoteName]?.[bundleName]);
|
|
2980
3222
|
},
|
|
2981
3223
|
commit: function() {
|
|
3224
|
+
if (!_dirty) return this;
|
|
2982
3225
|
STORAGE.set(_cache);
|
|
3226
|
+
_dirty = false;
|
|
2983
3227
|
return this;
|
|
2984
3228
|
}
|
|
2985
3229
|
};
|
|
@@ -3185,10 +3429,9 @@ var globalThisStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
3185
3429
|
globalThis[namespace] = {};
|
|
3186
3430
|
}
|
|
3187
3431
|
const storage = globalThis[namespace];
|
|
3188
|
-
if (!storage[key]) storage[key] = initialValue;
|
|
3189
3432
|
const entry = {
|
|
3190
3433
|
get() {
|
|
3191
|
-
return cloneEntry(key, storage[key]);
|
|
3434
|
+
return cloneEntry(key, key in storage ? storage[key] : initialValue);
|
|
3192
3435
|
},
|
|
3193
3436
|
set(value) {
|
|
3194
3437
|
storage[key] = cloneEntry(key, value);
|
|
@@ -3212,6 +3455,7 @@ var createStorageConfig = (override) => ({
|
|
|
3212
3455
|
var defaultProfile = {
|
|
3213
3456
|
latestSharedExternal: false,
|
|
3214
3457
|
skipInvalidExternalVersions: false,
|
|
3458
|
+
scopeUncoveredEntrypoints: false,
|
|
3215
3459
|
overrideCachedRemotes: "init-only",
|
|
3216
3460
|
overrideCachedRemotesIfURLMatches: false
|
|
3217
3461
|
};
|
|
@@ -3223,13 +3467,15 @@ var createModeConfig = (override) => {
|
|
|
3223
3467
|
strictExternalCompatibility: override.strict,
|
|
3224
3468
|
strictExternalSameVersionCompatibility: override.strict,
|
|
3225
3469
|
strictExternalVersion: override.strict,
|
|
3226
|
-
strictImportMap: override.strict
|
|
3470
|
+
strictImportMap: override.strict,
|
|
3471
|
+
strictEntryPointCoverage: override.strict
|
|
3227
3472
|
} : {
|
|
3228
3473
|
strictRemoteEntry: override.strict?.strictRemoteEntry ?? false,
|
|
3229
3474
|
strictExternalCompatibility: override.strict?.strictExternalCompatibility ?? false,
|
|
3230
3475
|
strictExternalSameVersionCompatibility: override.strict?.strictExternalSameVersionCompatibility ?? false,
|
|
3231
3476
|
strictExternalVersion: override.strict?.strictExternalVersion ?? false,
|
|
3232
|
-
strictImportMap: override.strict?.strictImportMap ?? false
|
|
3477
|
+
strictImportMap: override.strict?.strictImportMap ?? false,
|
|
3478
|
+
strictEntryPointCoverage: override.strict?.strictEntryPointCoverage ?? false
|
|
3233
3479
|
};
|
|
3234
3480
|
return {
|
|
3235
3481
|
strict: strictnessConfig,
|