@atlaspack/bundler-default 2.14.5-canary.3 → 2.14.5-canary.300
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +564 -0
- package/dist/DefaultBundler.js +84 -0
- package/dist/MonolithicBundler.js +68 -0
- package/dist/bundleMerge.js +137 -0
- package/dist/bundlerConfig.js +223 -0
- package/dist/decorateLegacyGraph.js +189 -0
- package/dist/idealGraph.js +1471 -0
- package/dist/memoize.js +31 -0
- package/dist/stats.js +69 -0
- package/lib/DefaultBundler.js +6 -1
- package/lib/MonolithicBundler.js +11 -3
- package/lib/bundleMerge.js +160 -0
- package/lib/bundlerConfig.js +76 -9
- package/lib/decorateLegacyGraph.js +24 -3
- package/lib/idealGraph.js +453 -36
- package/lib/memoize.js +39 -0
- package/lib/stats.js +85 -0
- package/lib/types/DefaultBundler.d.ts +18 -0
- package/lib/types/MonolithicBundler.d.ts +2 -0
- package/lib/types/bundleMerge.d.ts +9 -0
- package/lib/types/bundlerConfig.d.ts +36 -0
- package/lib/types/decorateLegacyGraph.d.ts +3 -0
- package/lib/types/idealGraph.d.ts +40 -0
- package/lib/types/memoize.d.ts +2 -0
- package/lib/types/stats.d.ts +16 -0
- package/package.json +20 -12
- package/src/{DefaultBundler.js → DefaultBundler.ts} +21 -6
- package/src/{MonolithicBundler.js → MonolithicBundler.ts} +17 -5
- package/src/bundleMerge.ts +250 -0
- package/src/{bundlerConfig.js → bundlerConfig.ts} +124 -44
- package/src/{decorateLegacyGraph.js → decorateLegacyGraph.ts} +26 -7
- package/src/{idealGraph.js → idealGraph.ts} +802 -116
- package/src/memoize.ts +32 -0
- package/src/stats.ts +97 -0
- package/tsconfig.json +30 -0
- package/tsconfig.tsbuildinfo +1 -0
package/lib/idealGraph.js
CHANGED
|
@@ -12,6 +12,13 @@ function _path() {
|
|
|
12
12
|
};
|
|
13
13
|
return data;
|
|
14
14
|
}
|
|
15
|
+
function _sortedArrayFunctions() {
|
|
16
|
+
const data = _interopRequireDefault(require("sorted-array-functions"));
|
|
17
|
+
_sortedArrayFunctions = function () {
|
|
18
|
+
return data;
|
|
19
|
+
};
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
15
22
|
function _featureFlags() {
|
|
16
23
|
const data = require("@atlaspack/feature-flags");
|
|
17
24
|
_featureFlags = function () {
|
|
@@ -47,8 +54,11 @@ function _nullthrows() {
|
|
|
47
54
|
};
|
|
48
55
|
return data;
|
|
49
56
|
}
|
|
57
|
+
var _bundleMerge = require("./bundleMerge");
|
|
58
|
+
var _stats = require("./stats");
|
|
50
59
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
51
60
|
/* BundleRoot - An asset that is the main entry of a Bundle. */
|
|
61
|
+
|
|
52
62
|
const dependencyPriorityEdges = {
|
|
53
63
|
sync: 1,
|
|
54
64
|
parallel: 2,
|
|
@@ -64,12 +74,19 @@ const idealBundleGraphEdges = exports.idealBundleGraphEdges = Object.freeze({
|
|
|
64
74
|
// which mutates the assetGraph into the bundleGraph we would
|
|
65
75
|
// expect from default bundler
|
|
66
76
|
|
|
77
|
+
function isNonRootBundle(bundle, message) {
|
|
78
|
+
let existingBundle = (0, _nullthrows().default)(bundle, message);
|
|
79
|
+
(0, _assert().default)(existingBundle !== 'root', "Bundle cannot be 'root'");
|
|
80
|
+
return existingBundle;
|
|
81
|
+
}
|
|
67
82
|
function createIdealGraph(assetGraph, config, entries, logger) {
|
|
83
|
+
var _config$sharedBundleM;
|
|
68
84
|
// Asset to the bundle and group it's an entry of
|
|
69
85
|
let bundleRoots = new Map();
|
|
70
86
|
let bundles = new Map();
|
|
71
87
|
let dependencyBundleGraph = new (_graph().ContentGraph)();
|
|
72
88
|
let assetReference = new (_utils().DefaultMap)(() => []);
|
|
89
|
+
let stats = new _stats.Stats(config.projectRoot);
|
|
73
90
|
|
|
74
91
|
// A Graph of Bundles and a root node (dummy string), which models only Bundles, and connections to their
|
|
75
92
|
// referencing Bundle. There are no actual BundleGroup nodes, just bundles that take on that role.
|
|
@@ -107,15 +124,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
107
124
|
}
|
|
108
125
|
let assets = [];
|
|
109
126
|
let assetToIndex = new Map();
|
|
110
|
-
|
|
111
|
-
let manualSharedMap = new Map();
|
|
112
|
-
// May need a map to be able to look up NON- bundle root assets which need special case instructions
|
|
113
|
-
// Use this when placing assets into bundles, to avoid duplication
|
|
114
|
-
let manualAssetToBundle = new Map();
|
|
115
|
-
let {
|
|
116
|
-
manualAssetToConfig,
|
|
117
|
-
constantModuleToMSB
|
|
118
|
-
} = function makeManualAssetToConfigLookup() {
|
|
127
|
+
function makeManualAssetToConfigLookup() {
|
|
119
128
|
let manualAssetToConfig = new Map();
|
|
120
129
|
let constantModuleToMSB = new (_utils().DefaultMap)(() => []);
|
|
121
130
|
if (config.manualSharedBundles.length === 0) {
|
|
@@ -159,17 +168,15 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
159
168
|
assetGraph.traverse((node, _, actions) => {
|
|
160
169
|
if (node.type === 'asset' && (!Array.isArray(c.types) || c.types.includes(node.value.type))) {
|
|
161
170
|
let projectRelativePath = _path().default.relative(config.projectRoot, node.value.filePath);
|
|
162
|
-
if (!assetRegexes.some(regex => regex.test(projectRelativePath))) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
171
|
|
|
166
172
|
// We track all matching MSB's for constant modules as they are never duplicated
|
|
167
173
|
// and need to be assigned to all matching bundles
|
|
168
174
|
if (node.value.meta.isConstantModule === true) {
|
|
169
175
|
constantModuleToMSB.get(node.value).push(c);
|
|
170
176
|
}
|
|
171
|
-
|
|
172
|
-
|
|
177
|
+
if (assetRegexes.some(regex => regex.test(projectRelativePath))) {
|
|
178
|
+
manualAssetToConfig.set(node.value, c);
|
|
179
|
+
}
|
|
173
180
|
}
|
|
174
181
|
if (node.type === 'dependency' && (node.value.priority === 'lazy' || (0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && node.value.priority === 'conditional') && parentAsset) {
|
|
175
182
|
// Don't walk past the bundle group assets
|
|
@@ -181,8 +188,23 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
181
188
|
manualAssetToConfig,
|
|
182
189
|
constantModuleToMSB
|
|
183
190
|
};
|
|
184
|
-
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//Manual is a map of the user-given name to the bundle node Id that corresponds to ALL the assets that match any glob in that user-specified array
|
|
194
|
+
let manualSharedMap = new Map();
|
|
195
|
+
// May need a map to be able to look up NON- bundle root assets which need special case instructions
|
|
196
|
+
// Use this when placing assets into bundles, to avoid duplication
|
|
197
|
+
let manualAssetToBundle = new Map();
|
|
198
|
+
let {
|
|
199
|
+
manualAssetToConfig,
|
|
200
|
+
constantModuleToMSB
|
|
201
|
+
} = makeManualAssetToConfigLookup();
|
|
185
202
|
let manualBundleToInternalizedAsset = new (_utils().DefaultMap)(() => []);
|
|
203
|
+
let mergeSourceBundleLookup = new Map();
|
|
204
|
+
let mergeSourceBundleAssets = new Set((_config$sharedBundleM = config.sharedBundleMerge) === null || _config$sharedBundleM === void 0 ? void 0 : _config$sharedBundleM.flatMap(c => {
|
|
205
|
+
var _c$sourceBundles;
|
|
206
|
+
return ((_c$sourceBundles = c.sourceBundles) === null || _c$sourceBundles === void 0 ? void 0 : _c$sourceBundles.map(assetMatch => _path().default.join(config.projectRoot, assetMatch))) ?? [];
|
|
207
|
+
}));
|
|
186
208
|
|
|
187
209
|
/**
|
|
188
210
|
* Step Create Bundles: Traverse the assetGraph (aka MutableBundleGraph) and create bundles
|
|
@@ -233,15 +255,16 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
233
255
|
manualSharedBundleKey != null && manualSharedMap.has(manualSharedBundleKey)) {
|
|
234
256
|
bundleId = (0, _nullthrows().default)(manualSharedMap.get(manualSharedBundleKey));
|
|
235
257
|
}
|
|
236
|
-
if (dependency.priority === 'lazy' || (0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && node.value.priority === 'conditional' || childAsset.bundleBehavior === 'isolated'
|
|
237
|
-
|
|
258
|
+
if (dependency.priority === 'lazy' || (0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && node.value.priority === 'conditional' || childAsset.bundleBehavior === 'isolated' ||
|
|
259
|
+
// An isolated Dependency, or Bundle must contain all assets it needs to load.
|
|
260
|
+
childAsset.bundleBehavior === 'inlineIsolated') {
|
|
238
261
|
if (bundleId == null) {
|
|
239
262
|
let firstBundleGroup = (0, _nullthrows().default)(bundleGraph.getNode(stack[0][1]));
|
|
240
263
|
(0, _assert().default)(firstBundleGroup !== 'root');
|
|
241
264
|
bundle = createBundle({
|
|
242
265
|
asset: childAsset,
|
|
243
266
|
bundleBehavior: dependency.bundleBehavior ?? childAsset.bundleBehavior,
|
|
244
|
-
needsStableName: dependency.bundleBehavior === 'inline' || childAsset.bundleBehavior === 'inline' ? false : dependency.isEntry || dependency.needsStableName,
|
|
267
|
+
needsStableName: dependency.bundleBehavior === 'inline' || childAsset.bundleBehavior === 'inline' || dependency.bundleBehavior === 'inlineIsolated' || childAsset.bundleBehavior === 'inlineIsolated' ? false : dependency.isEntry || dependency.needsStableName,
|
|
245
268
|
target: firstBundleGroup.target
|
|
246
269
|
});
|
|
247
270
|
bundleId = bundleGraph.addNode(bundle);
|
|
@@ -249,6 +272,11 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
249
272
|
bundleRoots.set(childAsset, [bundleId, bundleId]);
|
|
250
273
|
bundleGroupBundleIds.add(bundleId);
|
|
251
274
|
bundleGraph.addEdge(bundleGraphRootNodeId, bundleId);
|
|
275
|
+
// If this asset is relevant for merging then track it's source
|
|
276
|
+
// bundle id for later
|
|
277
|
+
if (mergeSourceBundleAssets.has(childAsset.filePath)) {
|
|
278
|
+
mergeSourceBundleLookup.set(_path().default.relative(config.projectRoot, childAsset.filePath), bundleId);
|
|
279
|
+
}
|
|
252
280
|
if (manualSharedObject) {
|
|
253
281
|
// MSB Step 4: If this was the first instance of a match, mark mainAsset for internalization
|
|
254
282
|
// since MSBs should not have main entry assets
|
|
@@ -260,7 +288,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
260
288
|
if (
|
|
261
289
|
// If this dependency requests isolated, but the bundle is not,
|
|
262
290
|
// make the bundle isolated for all uses.
|
|
263
|
-
dependency.bundleBehavior === 'isolated' && bundle.bundleBehavior == null) {
|
|
291
|
+
(dependency.bundleBehavior === 'isolated' || dependency.bundleBehavior === 'inlineIsolated') && bundle.bundleBehavior == null) {
|
|
264
292
|
bundle.bundleBehavior = dependency.bundleBehavior;
|
|
265
293
|
}
|
|
266
294
|
}
|
|
@@ -299,16 +327,17 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
299
327
|
env: childAsset.env,
|
|
300
328
|
bundleBehavior: dependency.bundleBehavior ?? childAsset.bundleBehavior,
|
|
301
329
|
target: referencingBundle.target,
|
|
302
|
-
needsStableName: childAsset.bundleBehavior === 'inline' || dependency.bundleBehavior === 'inline' || dependency.priority === 'parallel' && !dependency.needsStableName ? false : referencingBundle.needsStableName
|
|
330
|
+
needsStableName: childAsset.bundleBehavior === 'inline' || dependency.bundleBehavior === 'inline' || dependency.bundleBehavior === 'inlineIsolated' || dependency.priority === 'parallel' && !dependency.needsStableName ? false : referencingBundle.needsStableName
|
|
303
331
|
});
|
|
304
332
|
bundleId = bundleGraph.addNode(bundle);
|
|
305
333
|
} else {
|
|
306
|
-
|
|
307
|
-
(0, _assert().default)(
|
|
334
|
+
let bundleNode = bundleGraph.getNode(bundleId);
|
|
335
|
+
(0, _assert().default)(bundleNode != null && bundleNode !== 'root');
|
|
336
|
+
bundle = bundleNode;
|
|
308
337
|
if (
|
|
309
338
|
// If this dependency requests isolated, but the bundle is not,
|
|
310
339
|
// make the bundle isolated for all uses.
|
|
311
|
-
dependency.bundleBehavior === 'isolated' && bundle.bundleBehavior == null) {
|
|
340
|
+
(dependency.bundleBehavior === 'isolated' || dependency.bundleBehavior === 'inlineIsolated') && bundle.bundleBehavior == null) {
|
|
312
341
|
bundle.bundleBehavior = dependency.bundleBehavior;
|
|
313
342
|
}
|
|
314
343
|
}
|
|
@@ -494,7 +523,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
494
523
|
// not true that a bundle's available assets = all assets of all the bundleGroups
|
|
495
524
|
// it belongs to. It's the intersection of those sets.
|
|
496
525
|
let available;
|
|
497
|
-
if (bundleRoot.bundleBehavior === 'isolated') {
|
|
526
|
+
if (bundleRoot.bundleBehavior === 'isolated' || bundleRoot.bundleBehavior === 'inlineIsolated') {
|
|
498
527
|
available = new (_graph().BitSet)(assets.length);
|
|
499
528
|
} else {
|
|
500
529
|
available = (0, _nullthrows().default)(ancestorAssets[nodeId]).clone();
|
|
@@ -557,7 +586,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
557
586
|
continue;
|
|
558
587
|
}
|
|
559
588
|
let parentRoots = bundleRootGraph.getNodeIdsConnectedTo(id, _graph().ALL_EDGE_TYPES);
|
|
560
|
-
let canDelete = getBundleFromBundleRoot(bundleRoot).bundleBehavior !== 'isolated';
|
|
589
|
+
let canDelete = getBundleFromBundleRoot(bundleRoot).bundleBehavior !== 'isolated' && getBundleFromBundleRoot(bundleRoot).bundleBehavior !== 'inlineIsolated';
|
|
561
590
|
if (parentRoots.length === 0) continue;
|
|
562
591
|
for (let parentId of parentRoots) {
|
|
563
592
|
var _ancestorAssets$paren;
|
|
@@ -622,7 +651,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
622
651
|
let assetId = bundleRootGraph.getNode(nodeId);
|
|
623
652
|
if (assetId == null) return; // deleted
|
|
624
653
|
let a = assets[assetId];
|
|
625
|
-
if (entries.has(a) || !a.isBundleSplittable || bundleRoots.get(a) && (getBundleFromBundleRoot(a).needsStableName || getBundleFromBundleRoot(a).bundleBehavior === 'isolated')) {
|
|
654
|
+
if (entries.has(a) || !a.isBundleSplittable || bundleRoots.get(a) && (getBundleFromBundleRoot(a).needsStableName || getBundleFromBundleRoot(a).bundleBehavior === 'isolated' || getBundleFromBundleRoot(a).bundleBehavior === 'inlineIsolated')) {
|
|
626
655
|
// Add asset to non-splittable bundles.
|
|
627
656
|
addAssetToBundleRoot(asset, a);
|
|
628
657
|
} else if (!((_ancestorAssets$nodeI = ancestorAssets[nodeId]) !== null && _ancestorAssets$nodeI !== void 0 && _ancestorAssets$nodeI.has(i))) {
|
|
@@ -658,8 +687,9 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
658
687
|
manualSharedMap.set(manualSharedBundleKey, bundleId);
|
|
659
688
|
} else {
|
|
660
689
|
bundleId = (0, _nullthrows().default)(manualSharedMap.get(manualSharedBundleKey));
|
|
661
|
-
|
|
662
|
-
(0, _assert().default)(
|
|
690
|
+
let bundleNode = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
|
|
691
|
+
(0, _assert().default)(bundleNode != null && bundleNode !== 'root', 'We tried to use the root incorrectly');
|
|
692
|
+
bundle = bundleNode;
|
|
663
693
|
if (!bundle.assets.has(asset)) {
|
|
664
694
|
bundle.assets.add(asset);
|
|
665
695
|
bundle.size += asset.stats.size;
|
|
@@ -762,8 +792,9 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
762
792
|
bundleId = bundleGraph.addNode(bundle);
|
|
763
793
|
bundles.set(key, bundleId);
|
|
764
794
|
} else {
|
|
765
|
-
|
|
766
|
-
(0, _assert().default)(
|
|
795
|
+
let bundleNode = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
|
|
796
|
+
(0, _assert().default)(bundleNode !== 'root');
|
|
797
|
+
bundle = bundleNode;
|
|
767
798
|
}
|
|
768
799
|
bundle.assets.add(asset);
|
|
769
800
|
bundle.size += asset.stats.size;
|
|
@@ -784,6 +815,8 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
784
815
|
}
|
|
785
816
|
}
|
|
786
817
|
let manualSharedBundleIds = new Set([...manualSharedMap.values()]);
|
|
818
|
+
let modifiedSourceBundles = new Set();
|
|
819
|
+
|
|
787
820
|
// Step split manual shared bundles for those that have the "split" property set
|
|
788
821
|
let remainderMap = new (_utils().DefaultMap)(() => []);
|
|
789
822
|
for (let id of manualSharedMap.values()) {
|
|
@@ -791,8 +824,9 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
791
824
|
(0, _assert().default)(manualBundle !== 'root' && manualBundle != null);
|
|
792
825
|
if (manualBundle.sourceBundles.size > 0) {
|
|
793
826
|
var _manualAssetToConfig$;
|
|
794
|
-
let
|
|
795
|
-
(0, _assert().default)(
|
|
827
|
+
let firstSourceBundleNode = (0, _nullthrows().default)(bundleGraph.getNode([...manualBundle.sourceBundles][0]));
|
|
828
|
+
(0, _assert().default)(firstSourceBundleNode !== 'root');
|
|
829
|
+
let firstSourceBundle = firstSourceBundleNode;
|
|
796
830
|
let firstAsset = [...manualBundle.assets][0];
|
|
797
831
|
let manualSharedObject = manualAssetToConfig.get(firstAsset);
|
|
798
832
|
(0, _assert().default)(manualSharedObject != null);
|
|
@@ -800,7 +834,6 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
800
834
|
if (modNum != null) {
|
|
801
835
|
for (let a of [...manualBundle.assets]) {
|
|
802
836
|
let numRep = getBigIntFromContentKey(a.id);
|
|
803
|
-
// $FlowFixMe Flow doesn't know about BigInt
|
|
804
837
|
let r = Number(numRep % BigInt(modNum));
|
|
805
838
|
remainderMap.get(r).push(a);
|
|
806
839
|
}
|
|
@@ -847,6 +880,66 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
847
880
|
}
|
|
848
881
|
}
|
|
849
882
|
}
|
|
883
|
+
if ((0, _featureFlags().getFeatureFlag)('supportWebpackChunkName')) {
|
|
884
|
+
// Merge webpack chunk name bundles
|
|
885
|
+
let chunkNameBundles = new (_utils().DefaultMap)(() => new Set());
|
|
886
|
+
for (let [nodeId, node] of dependencyBundleGraph.nodes.entries()) {
|
|
887
|
+
var _bundleNode$value$mai;
|
|
888
|
+
// meta.chunkName is set by the Rust transformer, so we just need to find
|
|
889
|
+
// bundles that have a chunkName set.
|
|
890
|
+
if (!node || node.type !== 'dependency' || typeof node.value.meta.chunkName !== 'string') {
|
|
891
|
+
continue;
|
|
892
|
+
}
|
|
893
|
+
let connectedBundles = dependencyBundleGraph.getNodeIdsConnectedFrom(nodeId, dependencyPriorityEdges[node.value.priority]);
|
|
894
|
+
if (connectedBundles.length === 0) {
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
(0, _assert().default)(connectedBundles.length === 1, 'Expected webpackChunkName dependency to be connected to no more than one bundle');
|
|
898
|
+
let bundleId = connectedBundles[0];
|
|
899
|
+
let bundleNode = dependencyBundleGraph.getNode(bundleId);
|
|
900
|
+
(0, _assert().default)(bundleNode != null && bundleNode.type === 'bundle');
|
|
901
|
+
|
|
902
|
+
// If a bundle does not have a main entry asset, it's somehow just a
|
|
903
|
+
// shared bundle, and will be merged/deleted by other means.
|
|
904
|
+
if (bundleNode.value.mainEntryAsset == null) {
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
let bundleNodeId = null;
|
|
908
|
+
let mainEntryAssetId = (_bundleNode$value$mai = bundleNode.value.mainEntryAsset) === null || _bundleNode$value$mai === void 0 ? void 0 : _bundleNode$value$mai.id;
|
|
909
|
+
if (mainEntryAssetId != null) {
|
|
910
|
+
bundleNodeId = bundles.get(mainEntryAssetId);
|
|
911
|
+
}
|
|
912
|
+
if (bundleNodeId == null) {
|
|
913
|
+
continue;
|
|
914
|
+
}
|
|
915
|
+
chunkNameBundles.get(node.value.meta.chunkName)
|
|
916
|
+
// DependencyBundleGraph uses content keys as node ids, so we can use that
|
|
917
|
+
// to get the bundle id.
|
|
918
|
+
.add(bundleNodeId);
|
|
919
|
+
}
|
|
920
|
+
for (let [chunkName, bundleIds] of chunkNameBundles.entries()) {
|
|
921
|
+
// The `[request]` placeholder is not yet supported
|
|
922
|
+
if (bundleIds.size <= 1 || typeof chunkName === 'string' && chunkName.includes('[request]')) {
|
|
923
|
+
continue; // Nothing to merge
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Merge all bundles with the same chunk name into the first one.
|
|
927
|
+
let [firstBundleId, ...rest] = Array.from(bundleIds);
|
|
928
|
+
for (let bundleId of rest) {
|
|
929
|
+
mergeBundles(firstBundleId, bundleId, 'webpack-chunk-name');
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// Step merge async bundles that meet the configured params
|
|
935
|
+
if (config.asyncBundleMerge) {
|
|
936
|
+
mergeAsyncBundles(config.asyncBundleMerge);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// Step merge shared bundles that meet the configured params
|
|
940
|
+
if (config.sharedBundleMerge && config.sharedBundleMerge.length > 0) {
|
|
941
|
+
mergeSharedBundles(config.sharedBundleMerge);
|
|
942
|
+
}
|
|
850
943
|
|
|
851
944
|
// Step Merge Share Bundles: Merge any shared bundles under the minimum bundle size back into
|
|
852
945
|
// their source bundles, and remove the bundle.
|
|
@@ -857,9 +950,9 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
857
950
|
removeBundle(bundleGraph, bundleNodeId, assetReference);
|
|
858
951
|
}
|
|
859
952
|
}
|
|
860
|
-
let modifiedSourceBundles = new Set();
|
|
861
953
|
|
|
862
954
|
// Step Remove Shared Bundles: Remove shared bundles from bundle groups that hit the parallel request limit.
|
|
955
|
+
|
|
863
956
|
if (config.disableSharedBundles === false) {
|
|
864
957
|
for (let bundleGroupId of bundleGraph.getNodeIdsConnectedFrom(rootNodeId)) {
|
|
865
958
|
// Find shared bundles in this bundle group.
|
|
@@ -872,7 +965,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
872
965
|
let numBundlesContributingToPRL = bundleIdsInGroup.reduce((count, b) => {
|
|
873
966
|
let bundle = (0, _nullthrows().default)(bundleGraph.getNode(b));
|
|
874
967
|
(0, _assert().default)(bundle !== 'root');
|
|
875
|
-
return count + (bundle.bundleBehavior !== 'inline');
|
|
968
|
+
return count + Number(bundle.bundleBehavior !== 'inline' && bundle.bundleBehavior !== 'inlineIsolated');
|
|
876
969
|
}, 0);
|
|
877
970
|
if (numBundlesContributingToPRL > config.maxParallelRequests) {
|
|
878
971
|
let sharedBundleIdsInBundleGroup = bundleIdsInGroup.filter(b => {
|
|
@@ -901,6 +994,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
901
994
|
// Remove bundles until the bundle group is within the parallel request limit.
|
|
902
995
|
while (sharedBundlesInGroup.length > 0 && numBundlesContributingToPRL > config.maxParallelRequests) {
|
|
903
996
|
let bundleTuple = sharedBundlesInGroup.pop();
|
|
997
|
+
if (!bundleTuple) break;
|
|
904
998
|
let bundleToRemove = bundleTuple.bundle;
|
|
905
999
|
let bundleIdToRemove = bundleTuple.id;
|
|
906
1000
|
//TODO add integration test where bundles in bunlde group > max parallel request limit & only remove a couple shared bundles
|
|
@@ -944,10 +1038,279 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
944
1038
|
}
|
|
945
1039
|
}
|
|
946
1040
|
}
|
|
1041
|
+
function mergeBundles(bundleToKeepId, bundleToRemoveId, reason) {
|
|
1042
|
+
stats.trackMerge(bundleToKeepId, bundleToRemoveId, reason);
|
|
1043
|
+
let bundleToKeep = isNonRootBundle(bundleGraph.getNode(bundleToKeepId), `Bundle ${bundleToKeepId} not found`);
|
|
1044
|
+
let bundleToRemove = isNonRootBundle(bundleGraph.getNode(bundleToRemoveId), `Bundle ${bundleToRemoveId} not found`);
|
|
1045
|
+
modifiedSourceBundles.add(bundleToKeep);
|
|
1046
|
+
for (let asset of bundleToRemove.assets) {
|
|
1047
|
+
bundleToKeep.assets.add(asset);
|
|
1048
|
+
bundleToKeep.size += asset.stats.size;
|
|
1049
|
+
let newAssetReference = assetReference.get(asset).map(([dep, bundle]) => bundle === bundleToRemove ? [dep, bundleToKeep] : [dep, bundle]);
|
|
1050
|
+
assetReference.set(asset, newAssetReference);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Merge any internalized assets
|
|
1054
|
+
if ((0, _featureFlags().getFeatureFlag)('supportWebpackChunkName')) {
|
|
1055
|
+
if (bundleToKeep.internalizedAssets != null) {
|
|
1056
|
+
if (bundleToRemove.internalizedAssets != null) {
|
|
1057
|
+
bundleToKeep.internalizedAssets.intersect(bundleToRemove.internalizedAssets);
|
|
1058
|
+
} else {
|
|
1059
|
+
bundleToKeep.internalizedAssets.clear();
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
} else {
|
|
1063
|
+
(0, _assert().default)(bundleToKeep.internalizedAssets && bundleToRemove.internalizedAssets, 'All shared bundles should have internalized assets');
|
|
1064
|
+
bundleToKeep.internalizedAssets.union(bundleToRemove.internalizedAssets);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// Merge and clean up source bundles
|
|
1068
|
+
for (let sourceBundleId of bundleToRemove.sourceBundles) {
|
|
1069
|
+
if (bundleToKeep.sourceBundles.has(sourceBundleId)) {
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
if (sourceBundleId !== bundleToKeepId) {
|
|
1073
|
+
bundleToKeep.sourceBundles.add(sourceBundleId);
|
|
1074
|
+
bundleGraph.addEdge(sourceBundleId, bundleToKeepId);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
if ((0, _featureFlags().getFeatureFlag)('supportWebpackChunkName')) {
|
|
1078
|
+
bundleToKeep.sourceBundles.delete(bundleToRemoveId);
|
|
1079
|
+
for (let bundle of bundleGraph.getNodeIdsConnectedFrom(bundleToRemoveId)) {
|
|
1080
|
+
let bundleNode = (0, _nullthrows().default)(bundleGraph.getNode(bundle));
|
|
1081
|
+
if (bundleNode === 'root') {
|
|
1082
|
+
continue;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// If the bundle is a source bundle, add it to the bundle to keep
|
|
1086
|
+
if (bundleNode.sourceBundles.has(bundleToRemoveId)) {
|
|
1087
|
+
bundleNode.sourceBundles.delete(bundleToRemoveId);
|
|
1088
|
+
if (bundle !== bundleToKeepId) {
|
|
1089
|
+
bundleNode.sourceBundles.add(bundleToKeepId);
|
|
1090
|
+
bundleGraph.addEdge(bundleToKeepId, bundle);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// Merge bundle roots
|
|
1096
|
+
for (let bundleRoot of bundleToRemove.bundleRoots) {
|
|
1097
|
+
bundleToKeep.bundleRoots.add(bundleRoot);
|
|
1098
|
+
}
|
|
1099
|
+
if (bundleToRemove.mainEntryAsset != null) {
|
|
1100
|
+
(0, _assert().default)(bundleToKeep.mainEntryAsset != null);
|
|
1101
|
+
|
|
1102
|
+
// Merge the bundles in bundle group
|
|
1103
|
+
let bundlesInRemoveBundleGroup = getBundlesForBundleGroup(bundleToRemoveId);
|
|
1104
|
+
let removedBundleSharedBundles = new Set();
|
|
1105
|
+
for (let bundleIdInGroup of bundlesInRemoveBundleGroup) {
|
|
1106
|
+
if (bundleIdInGroup === bundleToRemoveId) {
|
|
1107
|
+
continue;
|
|
1108
|
+
}
|
|
1109
|
+
bundleGraph.addEdge(bundleToKeepId, bundleIdInGroup);
|
|
1110
|
+
removedBundleSharedBundles.add(bundleIdInGroup);
|
|
1111
|
+
}
|
|
1112
|
+
if ((0, _featureFlags().getFeatureFlag)('removeRedundantSharedBundles')) {
|
|
1113
|
+
// Merge any shared bundles that now have the same source bundles due to
|
|
1114
|
+
// the current bundle merge
|
|
1115
|
+
let sharedBundles = new (_utils().DefaultMap)(() => []);
|
|
1116
|
+
for (let bundleId of removedBundleSharedBundles) {
|
|
1117
|
+
let bundleNode = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
|
|
1118
|
+
(0, _assert().default)(bundleNode !== 'root');
|
|
1119
|
+
if (bundleNode.mainEntryAsset != null || bundleNode.manualSharedBundle != null) {
|
|
1120
|
+
continue;
|
|
1121
|
+
}
|
|
1122
|
+
let key = Array.from(bundleNode.sourceBundles).filter(sourceBundle => sourceBundle !== bundleToRemoveId).sort().join(',') + '.' + bundleNode.type;
|
|
1123
|
+
sharedBundles.get(key).push(bundleId);
|
|
1124
|
+
}
|
|
1125
|
+
for (let sharedBundlesToMerge of sharedBundles.values()) {
|
|
1126
|
+
if (sharedBundlesToMerge.length > 1) {
|
|
1127
|
+
let [firstBundleId, ...rest] = sharedBundlesToMerge;
|
|
1128
|
+
for (let bundleId of rest) {
|
|
1129
|
+
mergeBundles(firstBundleId, bundleId, 'redundant-shared');
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// Remove old bundle group
|
|
1136
|
+
bundleGroupBundleIds.delete(bundleToRemoveId);
|
|
1137
|
+
|
|
1138
|
+
// Clean up bundle roots
|
|
1139
|
+
let bundleRootToRemoveNodeId = (0, _nullthrows().default)(assetToBundleRootNodeId.get((0, _nullthrows().default)(bundleToRemove.mainEntryAsset)));
|
|
1140
|
+
let bundleRootToKeepNodeId = (0, _nullthrows().default)(assetToBundleRootNodeId.get((0, _nullthrows().default)(bundleToKeep.mainEntryAsset)));
|
|
1141
|
+
for (let nodeId of bundleRootGraph.getNodeIdsConnectedTo(bundleRootToRemoveNodeId)) {
|
|
1142
|
+
bundleRootGraph.addEdge(nodeId, bundleRootToKeepNodeId);
|
|
1143
|
+
bundleRootGraph.removeEdge(nodeId, bundleRootToRemoveNodeId);
|
|
1144
|
+
}
|
|
1145
|
+
for (let nodeId of bundleRootGraph.getNodeIdsConnectedFrom(bundleRootToRemoveNodeId)) {
|
|
1146
|
+
bundleRootGraph.addEdge(bundleRootToKeepNodeId, nodeId);
|
|
1147
|
+
bundleRootGraph.removeEdge(bundleRootToRemoveNodeId, nodeId);
|
|
1148
|
+
}
|
|
1149
|
+
bundleRoots.set((0, _nullthrows().default)(bundleToRemove.mainEntryAsset), [bundleToKeepId, bundleToKeepId]);
|
|
1150
|
+
|
|
1151
|
+
// Merge dependency bundle graph
|
|
1152
|
+
for (let dependencyNodeId of dependencyBundleGraph.getNodeIdsConnectedTo(dependencyBundleGraph.getNodeIdByContentKey(String(bundleToRemoveId)), _graph().ALL_EDGE_TYPES)) {
|
|
1153
|
+
let dependencyNode = (0, _nullthrows().default)(dependencyBundleGraph.getNode(dependencyNodeId));
|
|
1154
|
+
(0, _assert().default)(dependencyNode.type === 'dependency');
|
|
1155
|
+
|
|
1156
|
+
// Add dependency to the bundle to keep
|
|
1157
|
+
dependencyBundleGraph.addEdge(dependencyNodeId, dependencyBundleGraph.getNodeIdByContentKey(String(bundleToKeepId)), dependencyPriorityEdges[dependencyNode.value.priority]);
|
|
1158
|
+
// Remove dependency from the bundle to remove
|
|
1159
|
+
dependencyBundleGraph.removeEdge(dependencyNodeId, dependencyBundleGraph.getNodeIdByContentKey(String(bundleToRemoveId)), dependencyPriorityEdges[dependencyNode.value.priority]);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
bundleGraph.removeNode(bundleToRemoveId);
|
|
1164
|
+
}
|
|
1165
|
+
function mergeSharedBundles(mergeConfig) {
|
|
1166
|
+
// Find all shared bundles
|
|
1167
|
+
let sharedBundles = new Set();
|
|
1168
|
+
bundleGraph.traverse(nodeId => {
|
|
1169
|
+
let bundle = bundleGraph.getNode(nodeId);
|
|
1170
|
+
if (!bundle) {
|
|
1171
|
+
throw new Error(`Unable to find bundle ${nodeId} in bundle graph`);
|
|
1172
|
+
}
|
|
1173
|
+
if (bundle === 'root') {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
// Only consider JS shared bundles and non-reused bundles.
|
|
1178
|
+
// These count potentially be considered for merging in future but they're
|
|
1179
|
+
// more complicated to merge
|
|
1180
|
+
if (bundle.sourceBundles.size > 0 && bundle.manualSharedBundle == null && !bundle.mainEntryAsset && bundle.type === 'js') {
|
|
1181
|
+
sharedBundles.add(nodeId);
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
let clusters = (0, _bundleMerge.findMergeCandidates)(bundleGraph, Array.from(sharedBundles), mergeConfig.map(config => {
|
|
1185
|
+
var _config$sourceBundles;
|
|
1186
|
+
return {
|
|
1187
|
+
...config,
|
|
1188
|
+
sourceBundles: (_config$sourceBundles = config.sourceBundles) === null || _config$sourceBundles === void 0 ? void 0 : _config$sourceBundles.map(assetMatch => {
|
|
1189
|
+
let sourceBundleNodeId = mergeSourceBundleLookup.get(assetMatch);
|
|
1190
|
+
if (sourceBundleNodeId == null) {
|
|
1191
|
+
throw new Error(`Source bundle ${assetMatch} not found in merge source bundle lookup`);
|
|
1192
|
+
}
|
|
1193
|
+
return sourceBundleNodeId;
|
|
1194
|
+
})
|
|
1195
|
+
};
|
|
1196
|
+
}));
|
|
1197
|
+
let mergedBundles = new Set();
|
|
1198
|
+
for (let cluster of clusters) {
|
|
1199
|
+
let [mergeTarget, ...rest] = cluster;
|
|
1200
|
+
for (let bundleIdToMerge of rest) {
|
|
1201
|
+
mergeBundles(mergeTarget, bundleIdToMerge, 'shared-merge');
|
|
1202
|
+
}
|
|
1203
|
+
mergedBundles.add(mergeTarget);
|
|
1204
|
+
}
|
|
1205
|
+
if ((0, _featureFlags().getFeatureFlag)('supportWebpackChunkName')) {
|
|
1206
|
+
return mergedBundles;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
function mergeAsyncBundles({
|
|
1210
|
+
bundleSize,
|
|
1211
|
+
maxOverfetchSize,
|
|
1212
|
+
ignore
|
|
1213
|
+
}) {
|
|
1214
|
+
let mergeCandidates = [];
|
|
1215
|
+
let ignoreRegexes = (ignore === null || ignore === void 0 ? void 0 : ignore.map(glob => (0, _utils().globToRegex)(glob))) ?? [];
|
|
1216
|
+
let isIgnored = bundle => {
|
|
1217
|
+
if (!bundle.mainEntryAsset) {
|
|
1218
|
+
return false;
|
|
1219
|
+
}
|
|
1220
|
+
let mainEntryFilePath = _path().default.relative(config.projectRoot, (0, _nullthrows().default)(bundle.mainEntryAsset).filePath);
|
|
1221
|
+
return ignoreRegexes.some(regex => regex.test(mainEntryFilePath));
|
|
1222
|
+
};
|
|
1223
|
+
for (let [_bundleRootAsset, [bundleRootBundleId]] of bundleRoots) {
|
|
1224
|
+
let bundleRootBundle = (0, _nullthrows().default)(bundleGraph.getNode(bundleRootBundleId));
|
|
1225
|
+
(0, _assert().default)(bundleRootBundle !== 'root');
|
|
1226
|
+
if (bundleRootBundle.type === 'js' && bundleRootBundle.bundleBehavior !== 'inline' && bundleRootBundle.bundleBehavior !== 'inlineIsolated' && bundleRootBundle.size <= bundleSize && !isIgnored(bundleRootBundle)) {
|
|
1227
|
+
mergeCandidates.push(bundleRootBundleId);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
let candidates = [];
|
|
1231
|
+
for (let i = 0; i < mergeCandidates.length; i++) {
|
|
1232
|
+
for (let j = i + 1; j < mergeCandidates.length; j++) {
|
|
1233
|
+
let a = mergeCandidates[i];
|
|
1234
|
+
let b = mergeCandidates[j];
|
|
1235
|
+
if (a === b) continue; // Skip self-comparison
|
|
1236
|
+
|
|
1237
|
+
candidates.push(scoreAsyncMerge(a, b, maxOverfetchSize));
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
let sortByScore = (a, b) => {
|
|
1241
|
+
let diff = a.score - b.score;
|
|
1242
|
+
if (diff > 0) {
|
|
1243
|
+
return 1;
|
|
1244
|
+
} else if (diff < 0) {
|
|
1245
|
+
return -1;
|
|
1246
|
+
}
|
|
1247
|
+
return 0;
|
|
1248
|
+
};
|
|
1249
|
+
candidates = candidates.filter(({
|
|
1250
|
+
overfetchSize,
|
|
1251
|
+
score
|
|
1252
|
+
}) => overfetchSize <= maxOverfetchSize && score > 0).sort(sortByScore);
|
|
1253
|
+
|
|
1254
|
+
// Tracks the bundles that have been merged
|
|
1255
|
+
let merged = new Set();
|
|
1256
|
+
// Tracks the deleted bundles to the bundle they were merged into.
|
|
1257
|
+
let mergeRemap = new Map();
|
|
1258
|
+
// Tracks the bundles that have been rescored and added back into the
|
|
1259
|
+
// candidates.
|
|
1260
|
+
let rescored = new (_utils().DefaultMap)(() => new Set());
|
|
1261
|
+
do {
|
|
1262
|
+
let [a, b] = (0, _nullthrows().default)(candidates.pop()).bundleIds;
|
|
1263
|
+
if (bundleGraph.hasNode(a) && bundleGraph.hasNode(b) && (!merged.has(a) && !merged.has(b) || rescored.get(a).has(b))) {
|
|
1264
|
+
mergeRemap.set(b, a);
|
|
1265
|
+
merged.add(a);
|
|
1266
|
+
rescored.get(a).clear();
|
|
1267
|
+
mergeBundles(a, b, 'async-merge');
|
|
1268
|
+
continue;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
// One or both of the bundles have been previously merged, so we'll
|
|
1272
|
+
// rescore and add the result back into the list of candidates.
|
|
1273
|
+
let getMergedBundleId = bundleId => {
|
|
1274
|
+
let seen = new Set();
|
|
1275
|
+
while (!bundleGraph.hasNode(bundleId) && !seen.has(bundleId)) {
|
|
1276
|
+
seen.add(bundleId);
|
|
1277
|
+
bundleId = (0, _nullthrows().default)(mergeRemap.get(bundleId));
|
|
1278
|
+
}
|
|
1279
|
+
if (!bundleGraph.hasNode(bundleId)) {
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
return bundleId;
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1285
|
+
// Map a and b to their merged bundle ids if they've already been merged
|
|
1286
|
+
let currentA = getMergedBundleId(a);
|
|
1287
|
+
let currentB = getMergedBundleId(b);
|
|
1288
|
+
if (!currentA || !currentB ||
|
|
1289
|
+
// Bundles are already merged
|
|
1290
|
+
currentA === currentB) {
|
|
1291
|
+
// This combiniation is not valid, so we skip it.
|
|
1292
|
+
continue;
|
|
1293
|
+
}
|
|
1294
|
+
let candidate = scoreAsyncMerge(currentA, currentB, maxOverfetchSize);
|
|
1295
|
+
if (candidate.overfetchSize <= maxOverfetchSize && candidate.score > 0) {
|
|
1296
|
+
_sortedArrayFunctions().default.add(candidates, candidate, sortByScore);
|
|
1297
|
+
rescored.get(currentA).add(currentB);
|
|
1298
|
+
}
|
|
1299
|
+
} while (candidates.length > 0);
|
|
1300
|
+
}
|
|
1301
|
+
function getBundle(bundleId) {
|
|
1302
|
+
let bundle = bundleGraph.getNode(bundleId);
|
|
1303
|
+
if (bundle === 'root') {
|
|
1304
|
+
throw new Error(`Cannot access root bundle`);
|
|
1305
|
+
}
|
|
1306
|
+
if (bundle == null) {
|
|
1307
|
+
throw new Error(`Bundle ${bundleId} not found in bundle graph`);
|
|
1308
|
+
}
|
|
1309
|
+
return bundle;
|
|
1310
|
+
}
|
|
947
1311
|
function getBigIntFromContentKey(contentKey) {
|
|
948
1312
|
let b = Buffer.alloc(64);
|
|
949
1313
|
b.write(contentKey);
|
|
950
|
-
// $FlowFixMe Flow doesn't have BigInt types in this version
|
|
951
1314
|
return b.readBigInt64BE();
|
|
952
1315
|
}
|
|
953
1316
|
// Fix asset order in source bundles as they are likely now incorrect after shared bundle deletion
|
|
@@ -977,6 +1340,53 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
977
1340
|
}, bundleGroupId);
|
|
978
1341
|
return bundlesInABundleGroup;
|
|
979
1342
|
}
|
|
1343
|
+
function scoreAsyncMerge(bundleAId, bundleBId, maxOverfetchSize) {
|
|
1344
|
+
let bundleGroupA = new Set(getBundlesForBundleGroup(bundleAId));
|
|
1345
|
+
let bundleGroupB = new Set(getBundlesForBundleGroup(bundleBId));
|
|
1346
|
+
let overlapSize = 0;
|
|
1347
|
+
let overfetchSize = 0;
|
|
1348
|
+
for (let bundleId of new Set([...bundleGroupA, ...bundleGroupB])) {
|
|
1349
|
+
let bundle = getBundle(bundleId);
|
|
1350
|
+
if (bundleGroupA.has(bundleId) && bundleGroupB.has(bundleId)) {
|
|
1351
|
+
overlapSize += bundle.size;
|
|
1352
|
+
} else {
|
|
1353
|
+
overfetchSize += bundle.size;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
let overlapPercent = overlapSize / (overfetchSize + overlapSize);
|
|
1357
|
+
let bundleAParents = getBundleParents(bundleAId);
|
|
1358
|
+
let bundleBParents = getBundleParents(bundleBId);
|
|
1359
|
+
let sharedParentOverlap = 0;
|
|
1360
|
+
let sharedParentMismatch = 0;
|
|
1361
|
+
for (let bundleId of new Set([...bundleAParents, ...bundleBParents])) {
|
|
1362
|
+
if (bundleAParents.has(bundleId) && bundleBParents.has(bundleId)) {
|
|
1363
|
+
sharedParentOverlap++;
|
|
1364
|
+
} else {
|
|
1365
|
+
sharedParentMismatch++;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
let overfetchScore = overfetchSize / maxOverfetchSize;
|
|
1369
|
+
let sharedParentPercent = sharedParentOverlap / (sharedParentOverlap + sharedParentMismatch);
|
|
1370
|
+
let score = sharedParentPercent + overlapPercent + overfetchScore;
|
|
1371
|
+
return {
|
|
1372
|
+
overfetchSize,
|
|
1373
|
+
score,
|
|
1374
|
+
bundleIds: [bundleAId, bundleBId]
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
function getBundleParents(bundleId) {
|
|
1378
|
+
let parents = new Set();
|
|
1379
|
+
let {
|
|
1380
|
+
bundleRoots
|
|
1381
|
+
} = getBundle(bundleId);
|
|
1382
|
+
for (let bundleRoot of bundleRoots) {
|
|
1383
|
+
let bundleRootNodeId = (0, _nullthrows().default)(assetToBundleRootNodeId.get(bundleRoot));
|
|
1384
|
+
for (let parentId of bundleRootGraph.getNodeIdsConnectedTo(bundleRootNodeId, _graph().ALL_EDGE_TYPES)) {
|
|
1385
|
+
parents.add(parentId);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
return parents;
|
|
1389
|
+
}
|
|
980
1390
|
function getBundleFromBundleRoot(bundleRoot) {
|
|
981
1391
|
let bundle = bundleGraph.getNode((0, _nullthrows().default)(bundleRoots.get(bundleRoot))[0]);
|
|
982
1392
|
(0, _assert().default)(bundle !== 'root' && bundle != null);
|
|
@@ -1026,6 +1436,11 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
1026
1436
|
}
|
|
1027
1437
|
bundleGraph.removeNode(bundleId);
|
|
1028
1438
|
}
|
|
1439
|
+
stats.report(bundleId => {
|
|
1440
|
+
let bundle = bundleGraph.getNode(bundleId);
|
|
1441
|
+
(0, _assert().default)(bundle !== 'root');
|
|
1442
|
+
return bundle;
|
|
1443
|
+
});
|
|
1029
1444
|
return {
|
|
1030
1445
|
assets,
|
|
1031
1446
|
bundleGraph,
|
|
@@ -1042,6 +1457,7 @@ function createBundle(opts) {
|
|
|
1042
1457
|
bundleBehavior: opts.bundleBehavior,
|
|
1043
1458
|
env: (0, _nullthrows().default)(opts.env),
|
|
1044
1459
|
mainEntryAsset: null,
|
|
1460
|
+
bundleRoots: new Set(),
|
|
1045
1461
|
manualSharedBundle: opts.manualSharedBundle,
|
|
1046
1462
|
needsStableName: Boolean(opts.needsStableName),
|
|
1047
1463
|
size: 0,
|
|
@@ -1057,6 +1473,7 @@ function createBundle(opts) {
|
|
|
1057
1473
|
bundleBehavior: opts.bundleBehavior ?? asset.bundleBehavior,
|
|
1058
1474
|
env: opts.env ?? asset.env,
|
|
1059
1475
|
mainEntryAsset: asset,
|
|
1476
|
+
bundleRoots: new Set([asset]),
|
|
1060
1477
|
manualSharedBundle: opts.manualSharedBundle,
|
|
1061
1478
|
needsStableName: Boolean(opts.needsStableName),
|
|
1062
1479
|
size: asset.stats.size,
|