@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
|
@@ -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,20 +1690,26 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1610
1690
|
}
|
|
1611
1691
|
return Promise.resolve();
|
|
1612
1692
|
};
|
|
1613
|
-
function uncoveredTears(external, winner) {
|
|
1693
|
+
function uncoveredTears(external, winner, accepts) {
|
|
1614
1694
|
const basis = winner.remotes[0].entries;
|
|
1615
1695
|
return external.versions.reduce((sum, v) => {
|
|
1616
1696
|
if (v === winner) return sum;
|
|
1617
|
-
if (!
|
|
1618
|
-
return sum + v.remotes.reduce((n, r) => n +
|
|
1697
|
+
if (!accepts(v, winner.tag)) return sum;
|
|
1698
|
+
return sum + v.remotes.reduce((n, r) => n + countUncoveredEntrypoints(r, basis), 0);
|
|
1619
1699
|
}, 0);
|
|
1620
1700
|
}
|
|
1621
|
-
function setVersionActions(externalName, external) {
|
|
1701
|
+
function setVersionActions(externalName, external, isCompatible) {
|
|
1622
1702
|
if (external.versions.length === 1) {
|
|
1623
1703
|
external.versions[0].action = "share";
|
|
1704
|
+
applyEntrypointCoveragePolicy(externalName, external);
|
|
1624
1705
|
external.dirty = false;
|
|
1625
1706
|
return external;
|
|
1626
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));
|
|
1627
1713
|
let sharedVersion = external.versions.find((v) => v.host);
|
|
1628
1714
|
if (!sharedVersion && config.profile.latestSharedExternal) {
|
|
1629
1715
|
sharedVersion = external.versions[0];
|
|
@@ -1633,11 +1719,17 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1633
1719
|
let leastTears = Number.MAX_VALUE;
|
|
1634
1720
|
external.versions.forEach((vA) => {
|
|
1635
1721
|
const extraDownloads = external.versions.filter(
|
|
1636
|
-
(vB) =>
|
|
1722
|
+
(vB) => demands.get(vB).some((d) => !d.cached && d.strictVersion && !isCompatible(vA.tag, d.requiredVersion))
|
|
1637
1723
|
).length;
|
|
1638
|
-
|
|
1639
|
-
if (extraDownloads < leastExtraDownloads || extraDownloads === leastExtraDownloads && tears < leastTears) {
|
|
1724
|
+
if (extraDownloads < leastExtraDownloads) {
|
|
1640
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) {
|
|
1641
1733
|
leastTears = tears;
|
|
1642
1734
|
sharedVersion = vA;
|
|
1643
1735
|
}
|
|
@@ -1647,39 +1739,81 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1647
1739
|
throw new NFError(`[${externalName}] Could not determine shared version!`);
|
|
1648
1740
|
}
|
|
1649
1741
|
external.versions.forEach((v) => {
|
|
1650
|
-
if (
|
|
1742
|
+
if (accepts(v, sharedVersion.tag)) {
|
|
1651
1743
|
v.action = "skip";
|
|
1652
1744
|
return;
|
|
1653
1745
|
}
|
|
1654
|
-
|
|
1746
|
+
const strict = objector(v, sharedVersion.tag);
|
|
1747
|
+
if (config.strict.strictExternalCompatibility && strict) {
|
|
1655
1748
|
config.log.error(
|
|
1656
1749
|
3,
|
|
1657
|
-
`[${
|
|
1750
|
+
`[${strict.name}][${externalName}@${v.tag}] Is not compatible with requiredRange '${strict.requiredVersion}' of shared ${externalName}@${sharedVersion.tag}.`
|
|
1658
1751
|
);
|
|
1659
1752
|
throw new NFError(`External ${externalName}@${v.tag} could not be shared.`);
|
|
1660
1753
|
}
|
|
1661
|
-
v.action =
|
|
1754
|
+
v.action = strict ? "scope" : "skip";
|
|
1662
1755
|
});
|
|
1663
1756
|
sharedVersion.action = "share";
|
|
1664
|
-
|
|
1665
|
-
const basis = sharedVersion.remotes[0].entries;
|
|
1666
|
-
external.versions.forEach((v) => {
|
|
1667
|
-
if (v.action !== "skip") return;
|
|
1668
|
-
const uncovered = v.remotes.some(
|
|
1669
|
-
(r) => Object.keys(r.entries).some((entrypoint) => !(entrypoint in basis))
|
|
1670
|
-
);
|
|
1671
|
-
if (uncovered) {
|
|
1672
|
-
v.action = "scope";
|
|
1673
|
-
config.log.debug(
|
|
1674
|
-
3,
|
|
1675
|
-
`[${externalName}@${v.tag}] Scoped: entrypoints not covered by shared ${externalName}@${sharedVersion.tag}.`
|
|
1676
|
-
);
|
|
1677
|
-
}
|
|
1678
|
-
});
|
|
1679
|
-
}
|
|
1757
|
+
applyEntrypointCoveragePolicy(externalName, external);
|
|
1680
1758
|
external.dirty = false;
|
|
1681
1759
|
return external;
|
|
1682
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
|
+
}
|
|
1683
1817
|
}
|
|
1684
1818
|
|
|
1685
1819
|
// src/lib/core/2.app/steps/pooling/pool-graph.ts
|
|
@@ -1982,6 +2116,7 @@ function createGenerateImportMap(config, ports) {
|
|
|
1982
2116
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
1983
2117
|
let override = void 0;
|
|
1984
2118
|
let overrideScope = void 0;
|
|
2119
|
+
const cachedBefore = cachedFingerprint(external);
|
|
1985
2120
|
for (const version of external.versions) {
|
|
1986
2121
|
if (version.action === "scope") {
|
|
1987
2122
|
for (const remote of version.remotes) {
|
|
@@ -2027,7 +2162,7 @@ function createGenerateImportMap(config, ports) {
|
|
|
2027
2162
|
}
|
|
2028
2163
|
for (const [packageName, file] of Object.entries(r.entries)) {
|
|
2029
2164
|
if (packageName in source.entries) continue;
|
|
2030
|
-
if (config.strict.strictEntryPointCoverage) {
|
|
2165
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
2031
2166
|
warnUncoveredEntrypoint(shareScope, externalName, r.name, packageName);
|
|
2032
2167
|
continue;
|
|
2033
2168
|
}
|
|
@@ -2041,9 +2176,14 @@ function createGenerateImportMap(config, ports) {
|
|
|
2041
2176
|
addIntegrity(importMap, m.url, m.name, m.file);
|
|
2042
2177
|
}
|
|
2043
2178
|
}
|
|
2044
|
-
|
|
2179
|
+
if (cachedFingerprint(external) !== cachedBefore) {
|
|
2180
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external, shareScope);
|
|
2181
|
+
}
|
|
2045
2182
|
}
|
|
2046
2183
|
}
|
|
2184
|
+
function cachedFingerprint(external) {
|
|
2185
|
+
return external.versions.map((v) => v.remotes.map((r) => r.cached ? 1 : 0).join("")).join("|");
|
|
2186
|
+
}
|
|
2047
2187
|
function findOverride(external, shareScope, externalName) {
|
|
2048
2188
|
const sharedVersions = external.versions.filter((v) => v.action === "share");
|
|
2049
2189
|
const scopedExternalName = `${shareScope}.${externalName}`;
|
|
@@ -2075,6 +2215,7 @@ function createGenerateImportMap(config, ports) {
|
|
|
2075
2215
|
function addGlobalSharedExternals(importMap, chunkBundles) {
|
|
2076
2216
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope();
|
|
2077
2217
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2218
|
+
const cachedBefore = cachedFingerprint(external);
|
|
2078
2219
|
for (const version of external.versions) {
|
|
2079
2220
|
if (version.action === "skip") continue;
|
|
2080
2221
|
if (version.action === "scope") {
|
|
@@ -2102,31 +2243,39 @@ function createGenerateImportMap(config, ports) {
|
|
|
2102
2243
|
}
|
|
2103
2244
|
registerBundleChunks(chunkBundles, version.remotes[0].name, version.remotes[0].bundle);
|
|
2104
2245
|
version.remotes[0].cached = true;
|
|
2246
|
+
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes, 1);
|
|
2105
2247
|
}
|
|
2106
2248
|
for (const version of external.versions) {
|
|
2107
2249
|
if (version.action !== "skip") continue;
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
warnUncoveredEntrypoint(GLOBAL_SCOPE, externalName, remote.name, packageName);
|
|
2113
|
-
continue;
|
|
2114
|
-
}
|
|
2115
|
-
const scope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
2116
|
-
const url = join(scope, file);
|
|
2117
|
-
addToGlobal(importMap, { [packageName]: url });
|
|
2118
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
2119
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2120
|
-
remote.cached = true;
|
|
2121
|
-
}
|
|
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
|
+
}
|
|
2127
2276
|
function warnUncoveredEntrypoint(scope, externalName, remoteName, packageName) {
|
|
2128
2277
|
const msg = `[${scope}][${externalName}][${remoteName}] Entrypoint '${packageName}' is not covered by the shared version.`;
|
|
2129
|
-
if (config.strict.strictImportMap) {
|
|
2278
|
+
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
2130
2279
|
config.log.error(4, msg);
|
|
2131
2280
|
throw new NFError("Could not create ImportMap.");
|
|
2132
2281
|
}
|
|
@@ -2354,18 +2503,23 @@ function createGetRemoteEntry(config, ports) {
|
|
|
2354
2503
|
// src/lib/core/2.app/steps/update-cache.ts
|
|
2355
2504
|
function createUpdateCache(config, ports) {
|
|
2356
2505
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 8);
|
|
2506
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
2357
2507
|
return (remoteEntry) => {
|
|
2358
2508
|
try {
|
|
2359
2509
|
const actions = {};
|
|
2510
|
+
if (remoteEntry?.override) removeCachedRemoteEntries(/* @__PURE__ */ new Set([remoteEntry.name]));
|
|
2360
2511
|
storeRemoteEntry(remoteEntry, (entry, external, ctx) => {
|
|
2361
2512
|
const { action, sharedVersion } = resolveSharedExternal(entry, external, ctx);
|
|
2362
2513
|
actions[external.packageName] = { action };
|
|
2363
|
-
if (action === "skip" &&
|
|
2364
|
-
actions[external.packageName].
|
|
2365
|
-
|
|
2366
|
-
external
|
|
2367
|
-
|
|
2368
|
-
|
|
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
|
+
}
|
|
2369
2523
|
}
|
|
2370
2524
|
});
|
|
2371
2525
|
return Promise.resolve({ entry: remoteEntry, actions });
|
|
@@ -2393,13 +2547,29 @@ function createUpdateCache(config, ports) {
|
|
|
2393
2547
|
}
|
|
2394
2548
|
config.log.warn(8, errorMsg);
|
|
2395
2549
|
}
|
|
2396
|
-
if (action === "skip" &&
|
|
2397
|
-
|
|
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
|
+
}
|
|
2398
2563
|
}
|
|
2399
|
-
const matchingVersion = cached.versions
|
|
2400
|
-
if (
|
|
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) {
|
|
2401
2571
|
assertSameVersionCompatibility(matchingVersion);
|
|
2402
|
-
matchingVersion
|
|
2572
|
+
addRemoteToVersion(matchingVersion, remote);
|
|
2403
2573
|
} else {
|
|
2404
2574
|
if (!sharedVersion) action = "share";
|
|
2405
2575
|
remote.cached = action !== "skip";
|
|
@@ -2502,22 +2672,24 @@ function createConvertToImportMap(config, ports) {
|
|
|
2502
2672
|
return;
|
|
2503
2673
|
}
|
|
2504
2674
|
if (actions[external.packageName].action === "skip") {
|
|
2505
|
-
const override = actions[external.packageName]
|
|
2506
|
-
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
|
+
}
|
|
2507
2682
|
if (override) {
|
|
2508
2683
|
Object.entries(override).forEach(([packageName, url]) => {
|
|
2509
2684
|
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
2510
2685
|
});
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
2519
|
-
addIntegrity(importMap, url, integrityMap, fileName);
|
|
2520
|
-
});
|
|
2686
|
+
serveUncovered(
|
|
2687
|
+
remoteEntry,
|
|
2688
|
+
external,
|
|
2689
|
+
covered ?? Object.keys(override),
|
|
2690
|
+
remoteEntryScope,
|
|
2691
|
+
importMap
|
|
2692
|
+
);
|
|
2521
2693
|
return;
|
|
2522
2694
|
}
|
|
2523
2695
|
log.error(
|
|
@@ -2584,9 +2756,22 @@ function createConvertToImportMap(config, ports) {
|
|
|
2584
2756
|
});
|
|
2585
2757
|
return importMap;
|
|
2586
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
|
+
}
|
|
2587
2772
|
function warnUncoveredEntrypoint(remoteName, externalName, packageName) {
|
|
2588
2773
|
const msg = `[${remoteName}][${externalName}] Entrypoint '${packageName}' is not covered by the override.`;
|
|
2589
|
-
if (config.strict.strictImportMap) {
|
|
2774
|
+
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
2590
2775
|
log.error(9, msg);
|
|
2591
2776
|
throw new NFError("Could not create ImportMap.");
|
|
2592
2777
|
}
|
|
@@ -2835,16 +3020,21 @@ var createRemoteInfoRepository = (config) => {
|
|
|
2835
3020
|
const STORAGE = config.storage("remotes", {});
|
|
2836
3021
|
if (config.clearStorage) STORAGE.clear();
|
|
2837
3022
|
const _cache = STORAGE.get() ?? {};
|
|
3023
|
+
let _dirty = false;
|
|
2838
3024
|
return {
|
|
2839
3025
|
contains: function(remoteName) {
|
|
2840
3026
|
return !!_cache[remoteName];
|
|
2841
3027
|
},
|
|
2842
3028
|
remove: function(remoteName) {
|
|
2843
|
-
|
|
3029
|
+
if (remoteName in _cache) {
|
|
3030
|
+
delete _cache[remoteName];
|
|
3031
|
+
_dirty = true;
|
|
3032
|
+
}
|
|
2844
3033
|
return this;
|
|
2845
3034
|
},
|
|
2846
3035
|
addOrUpdate: function(remoteName, remote) {
|
|
2847
3036
|
_cache[remoteName] = remote;
|
|
3037
|
+
_dirty = true;
|
|
2848
3038
|
return this;
|
|
2849
3039
|
},
|
|
2850
3040
|
tryGet: function(remoteName) {
|
|
@@ -2859,7 +3049,9 @@ var createRemoteInfoRepository = (config) => {
|
|
|
2859
3049
|
return _cache;
|
|
2860
3050
|
},
|
|
2861
3051
|
commit: function() {
|
|
3052
|
+
if (!_dirty) return this;
|
|
2862
3053
|
STORAGE.set(_cache);
|
|
3054
|
+
_dirty = false;
|
|
2863
3055
|
return this;
|
|
2864
3056
|
}
|
|
2865
3057
|
};
|
|
@@ -2870,14 +3062,19 @@ var createScopedExternalsRepository = (config) => {
|
|
|
2870
3062
|
const STORAGE = config.storage("scoped-externals", {});
|
|
2871
3063
|
if (config.clearStorage) STORAGE.clear();
|
|
2872
3064
|
const _cache = STORAGE.get() ?? {};
|
|
3065
|
+
let _dirty = false;
|
|
2873
3066
|
return {
|
|
2874
3067
|
addExternal: function(remoteName, external, version) {
|
|
2875
3068
|
if (!_cache[remoteName]) _cache[remoteName] = {};
|
|
2876
3069
|
_cache[remoteName][external] = version;
|
|
3070
|
+
_dirty = true;
|
|
2877
3071
|
return this;
|
|
2878
3072
|
},
|
|
2879
3073
|
remove: function(remoteName) {
|
|
2880
|
-
|
|
3074
|
+
if (remoteName in _cache) {
|
|
3075
|
+
delete _cache[remoteName];
|
|
3076
|
+
_dirty = true;
|
|
3077
|
+
}
|
|
2881
3078
|
return this;
|
|
2882
3079
|
},
|
|
2883
3080
|
getAll: function() {
|
|
@@ -2887,7 +3084,9 @@ var createScopedExternalsRepository = (config) => {
|
|
|
2887
3084
|
return Optional.of(_cache[remoteName]);
|
|
2888
3085
|
},
|
|
2889
3086
|
commit: function() {
|
|
3087
|
+
if (!_dirty) return this;
|
|
2890
3088
|
STORAGE.set(_cache);
|
|
3089
|
+
_dirty = false;
|
|
2891
3090
|
return this;
|
|
2892
3091
|
}
|
|
2893
3092
|
};
|
|
@@ -2900,8 +3099,9 @@ var createSharedExternalsRepository = (config) => {
|
|
|
2900
3099
|
{ [GLOBAL_SCOPE]: {} }
|
|
2901
3100
|
);
|
|
2902
3101
|
if (config.clearStorage) STORAGE.clear();
|
|
2903
|
-
const _cache = STORAGE.get();
|
|
3102
|
+
const _cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
2904
3103
|
let _sawPoolTag = false;
|
|
3104
|
+
let _dirty = false;
|
|
2905
3105
|
return {
|
|
2906
3106
|
markPoolTagPresent: function() {
|
|
2907
3107
|
_sawPoolTag = true;
|
|
@@ -2915,28 +3115,38 @@ var createSharedExternalsRepository = (config) => {
|
|
|
2915
3115
|
addOrUpdate: function(externalName, external, shareScope) {
|
|
2916
3116
|
if (!_cache[shareScope ?? GLOBAL_SCOPE]) _cache[shareScope ?? GLOBAL_SCOPE] = {};
|
|
2917
3117
|
_cache[shareScope ?? GLOBAL_SCOPE][externalName] = external;
|
|
3118
|
+
_dirty = true;
|
|
2918
3119
|
return this;
|
|
2919
3120
|
},
|
|
2920
3121
|
getScopes: function(o = { includeGlobal: true }) {
|
|
2921
3122
|
if (o.includeGlobal) return Object.keys(_cache);
|
|
2922
3123
|
return Object.keys(_cache).filter((s) => s !== GLOBAL_SCOPE);
|
|
2923
3124
|
},
|
|
2924
|
-
|
|
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;
|
|
2925
3128
|
Object.values(_cache).forEach((scope) => {
|
|
2926
3129
|
const removeExternals = [];
|
|
2927
3130
|
Object.entries(scope).forEach(([name, external]) => {
|
|
2928
|
-
|
|
2929
|
-
external.versions.
|
|
2930
|
-
const
|
|
2931
|
-
|
|
2932
|
-
|
|
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];
|
|
2933
3138
|
}
|
|
2934
|
-
if (
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
for (let i = removeVersionIdx.length - 1; i >= 0; i--) {
|
|
2938
|
-
external.versions.splice(removeVersionIdx[i], 1);
|
|
3139
|
+
if (keep !== remotes.length) {
|
|
3140
|
+
remotes.length = keep;
|
|
3141
|
+
_dirty = true;
|
|
2939
3142
|
}
|
|
3143
|
+
if (remotes.length === 0) {
|
|
3144
|
+
external.versions.splice(i, 1);
|
|
3145
|
+
removedVersion = true;
|
|
3146
|
+
_dirty = true;
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
if (removedVersion) {
|
|
2940
3150
|
external.dirty = true;
|
|
2941
3151
|
if (external.versions.length === 0) removeExternals.push(name);
|
|
2942
3152
|
}
|
|
@@ -2960,7 +3170,9 @@ var createSharedExternalsRepository = (config) => {
|
|
|
2960
3170
|
return Optional.of(_cache[shareScope ?? GLOBAL_SCOPE]?.[external]);
|
|
2961
3171
|
},
|
|
2962
3172
|
commit: function() {
|
|
3173
|
+
if (!_dirty) return this;
|
|
2963
3174
|
STORAGE.set(_cache);
|
|
3175
|
+
_dirty = false;
|
|
2964
3176
|
return this;
|
|
2965
3177
|
}
|
|
2966
3178
|
};
|
|
@@ -2997,17 +3209,21 @@ var createChunkRepository = (config) => {
|
|
|
2997
3209
|
const STORAGE = config.storage("shared-chunks", {});
|
|
2998
3210
|
if (config.clearStorage) STORAGE.clear();
|
|
2999
3211
|
const _cache = STORAGE.get() ?? {};
|
|
3212
|
+
let _dirty = false;
|
|
3000
3213
|
return {
|
|
3001
3214
|
addOrReplace: function(remoteName, bundleName, chunks) {
|
|
3002
3215
|
if (!_cache[remoteName]) _cache[remoteName] = {};
|
|
3003
3216
|
_cache[remoteName][bundleName] = chunks;
|
|
3217
|
+
_dirty = true;
|
|
3004
3218
|
return this;
|
|
3005
3219
|
},
|
|
3006
3220
|
tryGet: function(remoteName, bundleName) {
|
|
3007
3221
|
return Optional.of(_cache[remoteName]?.[bundleName]);
|
|
3008
3222
|
},
|
|
3009
3223
|
commit: function() {
|
|
3224
|
+
if (!_dirty) return this;
|
|
3010
3225
|
STORAGE.set(_cache);
|
|
3226
|
+
_dirty = false;
|
|
3011
3227
|
return this;
|
|
3012
3228
|
}
|
|
3013
3229
|
};
|
|
@@ -3213,10 +3429,9 @@ var globalThisStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
3213
3429
|
globalThis[namespace] = {};
|
|
3214
3430
|
}
|
|
3215
3431
|
const storage = globalThis[namespace];
|
|
3216
|
-
if (!storage[key]) storage[key] = initialValue;
|
|
3217
3432
|
const entry = {
|
|
3218
3433
|
get() {
|
|
3219
|
-
return cloneEntry(key, storage[key]);
|
|
3434
|
+
return cloneEntry(key, key in storage ? storage[key] : initialValue);
|
|
3220
3435
|
},
|
|
3221
3436
|
set(value) {
|
|
3222
3437
|
storage[key] = cloneEntry(key, value);
|
|
@@ -3240,6 +3455,7 @@ var createStorageConfig = (override) => ({
|
|
|
3240
3455
|
var defaultProfile = {
|
|
3241
3456
|
latestSharedExternal: false,
|
|
3242
3457
|
skipInvalidExternalVersions: false,
|
|
3458
|
+
scopeUncoveredEntrypoints: false,
|
|
3243
3459
|
overrideCachedRemotes: "init-only",
|
|
3244
3460
|
overrideCachedRemotesIfURLMatches: false
|
|
3245
3461
|
};
|