@atlaspack/bundler-default 2.14.5-canary.35 → 2.14.5-canary.351
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 +589 -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 +106 -37
- package/lib/bundlerConfig.js +52 -6
- package/lib/decorateLegacyGraph.js +24 -3
- package/lib/idealGraph.js +410 -55
- 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} +106 -45
- package/src/{decorateLegacyGraph.js → decorateLegacyGraph.ts} +26 -7
- package/src/{idealGraph.js → idealGraph.ts} +729 -137
- package/src/memoize.ts +32 -0
- package/src/stats.ts +97 -0
- package/tsconfig.json +30 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/bundleMerge.js +0 -103
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 () {
|
|
@@ -48,8 +55,10 @@ function _nullthrows() {
|
|
|
48
55
|
return data;
|
|
49
56
|
}
|
|
50
57
|
var _bundleMerge = require("./bundleMerge");
|
|
58
|
+
var _stats = require("./stats");
|
|
51
59
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
52
60
|
/* BundleRoot - An asset that is the main entry of a Bundle. */
|
|
61
|
+
|
|
53
62
|
const dependencyPriorityEdges = {
|
|
54
63
|
sync: 1,
|
|
55
64
|
parallel: 2,
|
|
@@ -65,12 +74,19 @@ const idealBundleGraphEdges = exports.idealBundleGraphEdges = Object.freeze({
|
|
|
65
74
|
// which mutates the assetGraph into the bundleGraph we would
|
|
66
75
|
// expect from default bundler
|
|
67
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
|
+
}
|
|
68
82
|
function createIdealGraph(assetGraph, config, entries, logger) {
|
|
83
|
+
var _config$sharedBundleM;
|
|
69
84
|
// Asset to the bundle and group it's an entry of
|
|
70
85
|
let bundleRoots = new Map();
|
|
71
86
|
let bundles = new Map();
|
|
72
87
|
let dependencyBundleGraph = new (_graph().ContentGraph)();
|
|
73
88
|
let assetReference = new (_utils().DefaultMap)(() => []);
|
|
89
|
+
let stats = new _stats.Stats(config.projectRoot);
|
|
74
90
|
|
|
75
91
|
// A Graph of Bundles and a root node (dummy string), which models only Bundles, and connections to their
|
|
76
92
|
// referencing Bundle. There are no actual BundleGroup nodes, just bundles that take on that role.
|
|
@@ -108,15 +124,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
108
124
|
}
|
|
109
125
|
let assets = [];
|
|
110
126
|
let assetToIndex = new Map();
|
|
111
|
-
|
|
112
|
-
let manualSharedMap = new Map();
|
|
113
|
-
// May need a map to be able to look up NON- bundle root assets which need special case instructions
|
|
114
|
-
// Use this when placing assets into bundles, to avoid duplication
|
|
115
|
-
let manualAssetToBundle = new Map();
|
|
116
|
-
let {
|
|
117
|
-
manualAssetToConfig,
|
|
118
|
-
constantModuleToMSB
|
|
119
|
-
} = function makeManualAssetToConfigLookup() {
|
|
127
|
+
function makeManualAssetToConfigLookup() {
|
|
120
128
|
let manualAssetToConfig = new Map();
|
|
121
129
|
let constantModuleToMSB = new (_utils().DefaultMap)(() => []);
|
|
122
130
|
if (config.manualSharedBundles.length === 0) {
|
|
@@ -160,17 +168,15 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
160
168
|
assetGraph.traverse((node, _, actions) => {
|
|
161
169
|
if (node.type === 'asset' && (!Array.isArray(c.types) || c.types.includes(node.value.type))) {
|
|
162
170
|
let projectRelativePath = _path().default.relative(config.projectRoot, node.value.filePath);
|
|
163
|
-
if (!assetRegexes.some(regex => regex.test(projectRelativePath))) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
171
|
|
|
167
172
|
// We track all matching MSB's for constant modules as they are never duplicated
|
|
168
173
|
// and need to be assigned to all matching bundles
|
|
169
174
|
if (node.value.meta.isConstantModule === true) {
|
|
170
175
|
constantModuleToMSB.get(node.value).push(c);
|
|
171
176
|
}
|
|
172
|
-
|
|
173
|
-
|
|
177
|
+
if (assetRegexes.some(regex => regex.test(projectRelativePath))) {
|
|
178
|
+
manualAssetToConfig.set(node.value, c);
|
|
179
|
+
}
|
|
174
180
|
}
|
|
175
181
|
if (node.type === 'dependency' && (node.value.priority === 'lazy' || (0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && node.value.priority === 'conditional') && parentAsset) {
|
|
176
182
|
// Don't walk past the bundle group assets
|
|
@@ -182,8 +188,23 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
182
188
|
manualAssetToConfig,
|
|
183
189
|
constantModuleToMSB
|
|
184
190
|
};
|
|
185
|
-
}
|
|
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();
|
|
186
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
|
+
}));
|
|
187
208
|
|
|
188
209
|
/**
|
|
189
210
|
* Step Create Bundles: Traverse the assetGraph (aka MutableBundleGraph) and create bundles
|
|
@@ -234,15 +255,16 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
234
255
|
manualSharedBundleKey != null && manualSharedMap.has(manualSharedBundleKey)) {
|
|
235
256
|
bundleId = (0, _nullthrows().default)(manualSharedMap.get(manualSharedBundleKey));
|
|
236
257
|
}
|
|
237
|
-
if (dependency.priority === 'lazy' || (0, _featureFlags().getFeatureFlag)('conditionalBundlingApi') && node.value.priority === 'conditional' || childAsset.bundleBehavior === 'isolated'
|
|
238
|
-
|
|
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') {
|
|
239
261
|
if (bundleId == null) {
|
|
240
262
|
let firstBundleGroup = (0, _nullthrows().default)(bundleGraph.getNode(stack[0][1]));
|
|
241
263
|
(0, _assert().default)(firstBundleGroup !== 'root');
|
|
242
264
|
bundle = createBundle({
|
|
243
265
|
asset: childAsset,
|
|
244
266
|
bundleBehavior: dependency.bundleBehavior ?? childAsset.bundleBehavior,
|
|
245
|
-
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,
|
|
246
268
|
target: firstBundleGroup.target
|
|
247
269
|
});
|
|
248
270
|
bundleId = bundleGraph.addNode(bundle);
|
|
@@ -250,6 +272,11 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
250
272
|
bundleRoots.set(childAsset, [bundleId, bundleId]);
|
|
251
273
|
bundleGroupBundleIds.add(bundleId);
|
|
252
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
|
+
}
|
|
253
280
|
if (manualSharedObject) {
|
|
254
281
|
// MSB Step 4: If this was the first instance of a match, mark mainAsset for internalization
|
|
255
282
|
// since MSBs should not have main entry assets
|
|
@@ -261,7 +288,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
261
288
|
if (
|
|
262
289
|
// If this dependency requests isolated, but the bundle is not,
|
|
263
290
|
// make the bundle isolated for all uses.
|
|
264
|
-
dependency.bundleBehavior === 'isolated' && bundle.bundleBehavior == null) {
|
|
291
|
+
(dependency.bundleBehavior === 'isolated' || dependency.bundleBehavior === 'inlineIsolated') && bundle.bundleBehavior == null) {
|
|
265
292
|
bundle.bundleBehavior = dependency.bundleBehavior;
|
|
266
293
|
}
|
|
267
294
|
}
|
|
@@ -300,16 +327,17 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
300
327
|
env: childAsset.env,
|
|
301
328
|
bundleBehavior: dependency.bundleBehavior ?? childAsset.bundleBehavior,
|
|
302
329
|
target: referencingBundle.target,
|
|
303
|
-
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
|
|
304
331
|
});
|
|
305
332
|
bundleId = bundleGraph.addNode(bundle);
|
|
306
333
|
} else {
|
|
307
|
-
|
|
308
|
-
(0, _assert().default)(
|
|
334
|
+
let bundleNode = bundleGraph.getNode(bundleId);
|
|
335
|
+
(0, _assert().default)(bundleNode != null && bundleNode !== 'root');
|
|
336
|
+
bundle = bundleNode;
|
|
309
337
|
if (
|
|
310
338
|
// If this dependency requests isolated, but the bundle is not,
|
|
311
339
|
// make the bundle isolated for all uses.
|
|
312
|
-
dependency.bundleBehavior === 'isolated' && bundle.bundleBehavior == null) {
|
|
340
|
+
(dependency.bundleBehavior === 'isolated' || dependency.bundleBehavior === 'inlineIsolated') && bundle.bundleBehavior == null) {
|
|
313
341
|
bundle.bundleBehavior = dependency.bundleBehavior;
|
|
314
342
|
}
|
|
315
343
|
}
|
|
@@ -495,7 +523,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
495
523
|
// not true that a bundle's available assets = all assets of all the bundleGroups
|
|
496
524
|
// it belongs to. It's the intersection of those sets.
|
|
497
525
|
let available;
|
|
498
|
-
if (bundleRoot.bundleBehavior === 'isolated') {
|
|
526
|
+
if (bundleRoot.bundleBehavior === 'isolated' || bundleRoot.bundleBehavior === 'inlineIsolated') {
|
|
499
527
|
available = new (_graph().BitSet)(assets.length);
|
|
500
528
|
} else {
|
|
501
529
|
available = (0, _nullthrows().default)(ancestorAssets[nodeId]).clone();
|
|
@@ -558,7 +586,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
558
586
|
continue;
|
|
559
587
|
}
|
|
560
588
|
let parentRoots = bundleRootGraph.getNodeIdsConnectedTo(id, _graph().ALL_EDGE_TYPES);
|
|
561
|
-
let canDelete = getBundleFromBundleRoot(bundleRoot).bundleBehavior !== 'isolated';
|
|
589
|
+
let canDelete = getBundleFromBundleRoot(bundleRoot).bundleBehavior !== 'isolated' && getBundleFromBundleRoot(bundleRoot).bundleBehavior !== 'inlineIsolated';
|
|
562
590
|
if (parentRoots.length === 0) continue;
|
|
563
591
|
for (let parentId of parentRoots) {
|
|
564
592
|
var _ancestorAssets$paren;
|
|
@@ -623,7 +651,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
623
651
|
let assetId = bundleRootGraph.getNode(nodeId);
|
|
624
652
|
if (assetId == null) return; // deleted
|
|
625
653
|
let a = assets[assetId];
|
|
626
|
-
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')) {
|
|
627
655
|
// Add asset to non-splittable bundles.
|
|
628
656
|
addAssetToBundleRoot(asset, a);
|
|
629
657
|
} else if (!((_ancestorAssets$nodeI = ancestorAssets[nodeId]) !== null && _ancestorAssets$nodeI !== void 0 && _ancestorAssets$nodeI.has(i))) {
|
|
@@ -659,8 +687,9 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
659
687
|
manualSharedMap.set(manualSharedBundleKey, bundleId);
|
|
660
688
|
} else {
|
|
661
689
|
bundleId = (0, _nullthrows().default)(manualSharedMap.get(manualSharedBundleKey));
|
|
662
|
-
|
|
663
|
-
(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;
|
|
664
693
|
if (!bundle.assets.has(asset)) {
|
|
665
694
|
bundle.assets.add(asset);
|
|
666
695
|
bundle.size += asset.stats.size;
|
|
@@ -763,8 +792,9 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
763
792
|
bundleId = bundleGraph.addNode(bundle);
|
|
764
793
|
bundles.set(key, bundleId);
|
|
765
794
|
} else {
|
|
766
|
-
|
|
767
|
-
(0, _assert().default)(
|
|
795
|
+
let bundleNode = (0, _nullthrows().default)(bundleGraph.getNode(bundleId));
|
|
796
|
+
(0, _assert().default)(bundleNode !== 'root');
|
|
797
|
+
bundle = bundleNode;
|
|
768
798
|
}
|
|
769
799
|
bundle.assets.add(asset);
|
|
770
800
|
bundle.size += asset.stats.size;
|
|
@@ -785,6 +815,8 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
785
815
|
}
|
|
786
816
|
}
|
|
787
817
|
let manualSharedBundleIds = new Set([...manualSharedMap.values()]);
|
|
818
|
+
let modifiedSourceBundles = new Set();
|
|
819
|
+
|
|
788
820
|
// Step split manual shared bundles for those that have the "split" property set
|
|
789
821
|
let remainderMap = new (_utils().DefaultMap)(() => []);
|
|
790
822
|
for (let id of manualSharedMap.values()) {
|
|
@@ -792,8 +824,9 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
792
824
|
(0, _assert().default)(manualBundle !== 'root' && manualBundle != null);
|
|
793
825
|
if (manualBundle.sourceBundles.size > 0) {
|
|
794
826
|
var _manualAssetToConfig$;
|
|
795
|
-
let
|
|
796
|
-
(0, _assert().default)(
|
|
827
|
+
let firstSourceBundleNode = (0, _nullthrows().default)(bundleGraph.getNode([...manualBundle.sourceBundles][0]));
|
|
828
|
+
(0, _assert().default)(firstSourceBundleNode !== 'root');
|
|
829
|
+
let firstSourceBundle = firstSourceBundleNode;
|
|
797
830
|
let firstAsset = [...manualBundle.assets][0];
|
|
798
831
|
let manualSharedObject = manualAssetToConfig.get(firstAsset);
|
|
799
832
|
(0, _assert().default)(manualSharedObject != null);
|
|
@@ -801,7 +834,6 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
801
834
|
if (modNum != null) {
|
|
802
835
|
for (let a of [...manualBundle.assets]) {
|
|
803
836
|
let numRep = getBigIntFromContentKey(a.id);
|
|
804
|
-
// $FlowFixMe Flow doesn't know about BigInt
|
|
805
837
|
let r = Number(numRep % BigInt(modNum));
|
|
806
838
|
remainderMap.get(r).push(a);
|
|
807
839
|
}
|
|
@@ -848,11 +880,65 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
848
880
|
}
|
|
849
881
|
}
|
|
850
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
|
+
}
|
|
851
938
|
|
|
852
|
-
// Step merge shared bundles that meet the
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
mergeOverlapBundles();
|
|
939
|
+
// Step merge shared bundles that meet the configured params
|
|
940
|
+
if (config.sharedBundleMerge && config.sharedBundleMerge.length > 0) {
|
|
941
|
+
mergeSharedBundles(config.sharedBundleMerge);
|
|
856
942
|
}
|
|
857
943
|
|
|
858
944
|
// Step Merge Share Bundles: Merge any shared bundles under the minimum bundle size back into
|
|
@@ -866,7 +952,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
866
952
|
}
|
|
867
953
|
|
|
868
954
|
// Step Remove Shared Bundles: Remove shared bundles from bundle groups that hit the parallel request limit.
|
|
869
|
-
|
|
955
|
+
|
|
870
956
|
if (config.disableSharedBundles === false) {
|
|
871
957
|
for (let bundleGroupId of bundleGraph.getNodeIdsConnectedFrom(rootNodeId)) {
|
|
872
958
|
// Find shared bundles in this bundle group.
|
|
@@ -879,7 +965,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
879
965
|
let numBundlesContributingToPRL = bundleIdsInGroup.reduce((count, b) => {
|
|
880
966
|
let bundle = (0, _nullthrows().default)(bundleGraph.getNode(b));
|
|
881
967
|
(0, _assert().default)(bundle !== 'root');
|
|
882
|
-
return count + (bundle.bundleBehavior !== 'inline');
|
|
968
|
+
return count + Number(bundle.bundleBehavior !== 'inline' && bundle.bundleBehavior !== 'inlineIsolated');
|
|
883
969
|
}, 0);
|
|
884
970
|
if (numBundlesContributingToPRL > config.maxParallelRequests) {
|
|
885
971
|
let sharedBundleIdsInBundleGroup = bundleIdsInGroup.filter(b => {
|
|
@@ -908,6 +994,7 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
908
994
|
// Remove bundles until the bundle group is within the parallel request limit.
|
|
909
995
|
while (sharedBundlesInGroup.length > 0 && numBundlesContributingToPRL > config.maxParallelRequests) {
|
|
910
996
|
let bundleTuple = sharedBundlesInGroup.pop();
|
|
997
|
+
if (!bundleTuple) break;
|
|
911
998
|
let bundleToRemove = bundleTuple.bundle;
|
|
912
999
|
let bundleIdToRemove = bundleTuple.id;
|
|
913
1000
|
//TODO add integration test where bundles in bunlde group > max parallel request limit & only remove a couple shared bundles
|
|
@@ -951,35 +1038,131 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
951
1038
|
}
|
|
952
1039
|
}
|
|
953
1040
|
}
|
|
954
|
-
function mergeBundles(
|
|
955
|
-
|
|
956
|
-
let
|
|
957
|
-
|
|
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);
|
|
958
1046
|
for (let asset of bundleToRemove.assets) {
|
|
959
1047
|
bundleToKeep.assets.add(asset);
|
|
960
1048
|
bundleToKeep.size += asset.stats.size;
|
|
961
1049
|
let newAssetReference = assetReference.get(asset).map(([dep, bundle]) => bundle === bundleToRemove ? [dep, bundleToKeep] : [dep, bundle]);
|
|
962
1050
|
assetReference.set(asset, newAssetReference);
|
|
963
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
|
|
964
1068
|
for (let sourceBundleId of bundleToRemove.sourceBundles) {
|
|
965
1069
|
if (bundleToKeep.sourceBundles.has(sourceBundleId)) {
|
|
966
1070
|
continue;
|
|
967
1071
|
}
|
|
968
|
-
|
|
969
|
-
|
|
1072
|
+
if (sourceBundleId !== bundleToKeepId) {
|
|
1073
|
+
bundleToKeep.sourceBundles.add(sourceBundleId);
|
|
1074
|
+
bundleGraph.addEdge(sourceBundleId, bundleToKeepId);
|
|
1075
|
+
}
|
|
970
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
|
+
}
|
|
971
1084
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
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
|
+
}
|
|
978
1161
|
}
|
|
979
1162
|
}
|
|
980
1163
|
bundleGraph.removeNode(bundleToRemoveId);
|
|
981
1164
|
}
|
|
982
|
-
function
|
|
1165
|
+
function mergeSharedBundles(mergeConfig) {
|
|
983
1166
|
// Find all shared bundles
|
|
984
1167
|
let sharedBundles = new Set();
|
|
985
1168
|
bundleGraph.traverse(nodeId => {
|
|
@@ -998,18 +1181,136 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
998
1181
|
sharedBundles.add(nodeId);
|
|
999
1182
|
}
|
|
1000
1183
|
});
|
|
1001
|
-
let clusters = (0, _bundleMerge.findMergeCandidates)(bundleGraph, Array.from(sharedBundles), config
|
|
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();
|
|
1002
1198
|
for (let cluster of clusters) {
|
|
1003
1199
|
let [mergeTarget, ...rest] = cluster;
|
|
1004
1200
|
for (let bundleIdToMerge of rest) {
|
|
1005
|
-
mergeBundles(
|
|
1201
|
+
mergeBundles(mergeTarget, bundleIdToMerge, 'shared-merge');
|
|
1006
1202
|
}
|
|
1203
|
+
mergedBundles.add(mergeTarget);
|
|
1204
|
+
}
|
|
1205
|
+
if ((0, _featureFlags().getFeatureFlag)('supportWebpackChunkName')) {
|
|
1206
|
+
return mergedBundles;
|
|
1007
1207
|
}
|
|
1008
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
|
+
}
|
|
1009
1311
|
function getBigIntFromContentKey(contentKey) {
|
|
1010
1312
|
let b = Buffer.alloc(64);
|
|
1011
1313
|
b.write(contentKey);
|
|
1012
|
-
// $FlowFixMe Flow doesn't have BigInt types in this version
|
|
1013
1314
|
return b.readBigInt64BE();
|
|
1014
1315
|
}
|
|
1015
1316
|
// Fix asset order in source bundles as they are likely now incorrect after shared bundle deletion
|
|
@@ -1039,6 +1340,53 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
1039
1340
|
}, bundleGroupId);
|
|
1040
1341
|
return bundlesInABundleGroup;
|
|
1041
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
|
+
}
|
|
1042
1390
|
function getBundleFromBundleRoot(bundleRoot) {
|
|
1043
1391
|
let bundle = bundleGraph.getNode((0, _nullthrows().default)(bundleRoots.get(bundleRoot))[0]);
|
|
1044
1392
|
(0, _assert().default)(bundle !== 'root' && bundle != null);
|
|
@@ -1088,6 +1436,11 @@ function createIdealGraph(assetGraph, config, entries, logger) {
|
|
|
1088
1436
|
}
|
|
1089
1437
|
bundleGraph.removeNode(bundleId);
|
|
1090
1438
|
}
|
|
1439
|
+
stats.report(bundleId => {
|
|
1440
|
+
let bundle = bundleGraph.getNode(bundleId);
|
|
1441
|
+
(0, _assert().default)(bundle !== 'root');
|
|
1442
|
+
return bundle;
|
|
1443
|
+
});
|
|
1091
1444
|
return {
|
|
1092
1445
|
assets,
|
|
1093
1446
|
bundleGraph,
|
|
@@ -1104,6 +1457,7 @@ function createBundle(opts) {
|
|
|
1104
1457
|
bundleBehavior: opts.bundleBehavior,
|
|
1105
1458
|
env: (0, _nullthrows().default)(opts.env),
|
|
1106
1459
|
mainEntryAsset: null,
|
|
1460
|
+
bundleRoots: new Set(),
|
|
1107
1461
|
manualSharedBundle: opts.manualSharedBundle,
|
|
1108
1462
|
needsStableName: Boolean(opts.needsStableName),
|
|
1109
1463
|
size: 0,
|
|
@@ -1119,6 +1473,7 @@ function createBundle(opts) {
|
|
|
1119
1473
|
bundleBehavior: opts.bundleBehavior ?? asset.bundleBehavior,
|
|
1120
1474
|
env: opts.env ?? asset.env,
|
|
1121
1475
|
mainEntryAsset: asset,
|
|
1476
|
+
bundleRoots: new Set([asset]),
|
|
1122
1477
|
manualSharedBundle: opts.manualSharedBundle,
|
|
1123
1478
|
needsStableName: Boolean(opts.needsStableName),
|
|
1124
1479
|
size: asset.stats.size,
|